hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit ae9f39ed90742d9384c6564199935a56d4727034
parent faee2abca97888527babb34c9d32cf564223c79e
Author: Armin Preiml <apreiml@strohwolke.at>
Date:   Tue, 25 Jan 2022 20:27:53 +0100

crypto: make sure to clear state on closing hashes

Signed-off-by: Armin Preiml <apreiml@strohwolke.at>
Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Mcrypto/blake2b/blake2b.ha | 17++++++++++++++---
Mcrypto/sha1/sha1.ha | 14+++++++++++++-
Mcrypto/sha256/sha256.ha | 14+++++++++++++-
Mcrypto/sha512/sha512.ha | 29+++++++++++++++++++++++++----
Mscripts/gen-stdlib | 12++++++------
Mstdlib.mk | 14+++++++-------
6 files changed, 78 insertions(+), 22 deletions(-)

diff --git a/crypto/blake2b/blake2b.ha b/crypto/blake2b/blake2b.ha @@ -1,3 +1,4 @@ +use bytes; use crypto::math; use endian; use hash; @@ -44,9 +45,10 @@ export type digest = struct { }; // Creates a [[hash::hash]] which computes a BLAKE2b hash with a given key and a -// given hash size. The size must be between 1 and 64, inclusive. This hash -// function does not allocate any additional state, so you do not need to call -// [[hash::close]] when you are done with it. +// given hash size. The size must be between 1 and 64, inclusive. If this +// function is used to hash sensitive information, the caller should call +// [[hash::close]] to erase sentitive data from memory after use; if not, the +// use of [[hash::close]] is optional. export fn blake2b(key: []u8, sz: size) digest = { assert(1 <= sz); assert(sz <= 64); @@ -57,6 +59,7 @@ export fn blake2b(key: []u8, sz: size) digest = { keyblock[..len(key)] = key; return digest { writer = &write, + closer = &close, sum = &sum, reset = &reset, sz = sz, @@ -97,6 +100,7 @@ fn sum(h: *hash::hash, buf: []u8) void = { let h = h: *digest; let copy = *h; let h = &copy; + defer hash::close(h); h.tlow += h.blocklen; if (h.tlow < h.blocklen: u64) h.thigh += 1; @@ -164,3 +168,10 @@ fn mix(v: *[16]u64, a: size, b: size, c: size, d: size, x: u64, y: u64) void = { v[c] = v[c] + v[d]; v[b] = math::rotr64(v[b] ^ v[c], R4); }; + +fn close(stream: *io::stream) void = { + let s = stream: *digest; + bytes::zero((s.h[..]: *[*]u8)[..len(s.h) * size(u32)]); + bytes::zero(s.block); + bytes::zero(s.key); +}; diff --git a/crypto/sha1/sha1.ha b/crypto/sha1/sha1.ha @@ -1,5 +1,6 @@ use hash; use io; +use bytes; use crypto::math; use endian; @@ -25,10 +26,14 @@ export type digest = struct { // Creates a [[hash::hash]] which computes a SHA-1 hash. Note that this // alogorithm is no longer considered secure. Where possible, applications are -// encouraged to use [[crypto::sha256]] or [[crypto::sha512]] instead. +// encouraged to use [[crypto::sha256]] or [[crypto::sha512]] instead. If this +// function is used to hash sensitive information, the caller should call +// [[hash::close]] to erase sentitive data from memory after use; if not, the +// use of [[hash::close]] is optional. export fn sha1() digest = { let sha = digest { writer = &write, + closer = &close, sum = &sum, reset = &reset, sz = SIZE, @@ -86,6 +91,7 @@ fn sum(h: *hash::hash, buf: []u8) void = { let h = h: *digest; let copy = *h; let h = &copy; + defer hash::close(h); // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64. let ln = h.ln; @@ -207,3 +213,9 @@ fn block(h: *digest, p: []u8) void = { h.h[3] = h3; h.h[4] = h4; }; + +fn close(stream: *io::stream) void = { + let s = stream: *digest; + bytes::zero((s.h[..]: *[*]u8)[..len(s.h) * size(u32)]); + bytes::zero(s.x); +}; diff --git a/crypto/sha256/sha256.ha b/crypto/sha256/sha256.ha @@ -1,4 +1,5 @@ use crypto::math; +use bytes; use endian; use hash; use io; @@ -41,10 +42,14 @@ export type state = struct { ln: size, }; -// Creates a [[hash::hash]] which computes a SHA-256 hash. +// Creates a [[hash::hash]] which computes a SHA-256 hash. If this function is +// used to hash sensitive information, the caller should call [[hash::close]] to +// erase sentitive data from memory after use; if not, the use of +// [[hash::close]] is optional. export fn sha256() state = { let sha = state { writer = &write, + closer = &close, sum = &sum, reset = &reset, sz = SIZE, @@ -103,6 +108,7 @@ fn sum(h: *hash::hash, buf: []u8) void = { let h = h: *state; let copy = *h; let h = &copy; + defer hash::close(h); // Add padding let ln = h.ln; @@ -197,3 +203,9 @@ fn block(h: *state, buf: []u8) void = { h.h[6] = h6; h.h[7] = h7; }; + +fn close(stream: *io::stream) void = { + let s = stream: *state; + bytes::zero((s.h[..]: *[*]u8)[..len(s.h) * size(u32)]); + bytes::zero(s.x); +}; diff --git a/crypto/sha512/sha512.ha b/crypto/sha512/sha512.ha @@ -1,3 +1,4 @@ +use bytes; use crypto::math; use endian; use hash; @@ -65,22 +66,35 @@ export type digest = struct { var: variant, }; -// Creates a [[hash::hash]] which computes a SHA-512 hash. +// Creates a [[hash::hash]] which computes a SHA-512 hash. If this function is +// used to hash sensitive information, the caller should call [[hash::close]] to +// erase sentitive data from memory after use; if not, the use of +// [[hash::close]] is optional. export fn sha512() digest = init(variant::SHA512, SIZE); -// Creates a [[hash::hash]] which computes a SHA-512/224 hash. +// Creates a [[hash::hash]] which computes a SHA-512/224 hash. If this function +// is used to hash sensitive information, the caller should call [[hash::close]] +// to erase sentitive data from memory after use; if not, the use of +// [[hash::close]] is optional. export fn sha512_224() digest = init(variant::SHA512_224, SIZE224); -// Creates a [[hash::hash]] which computes a SHA-512/256 hash. +// Creates a [[hash::hash]] which computes a SHA-512/256 hash. If this function +// is used to hash sensitive information, the caller should call [[hash::close]] +// to erase sentitive data from memory after use; if not, the use of +// [[hash::close]] is optional. export fn sha512_256() digest = init(variant::SHA512_256, SIZE256); -// Creates a [[hash::hash]] which computes a SHA-384 hash. +// Creates a [[hash::hash]] which computes a SHA-384 hash. If this function is +// used to hash sensitive information, the caller should call [[hash::close]] to +// erase sentitive data from memory after use; if not, the use of +// [[hash::close]] is optional. export fn sha384() digest = init(variant::SHA384, SIZE384); // Internal initialization function fn init(var: variant, sz: size) digest = { let sha = digest { writer = &write, + closer = &close, sum = &sum, reset = &reset, sz = sz, @@ -128,6 +142,7 @@ fn sum(h: *hash::hash, buf: []u8) void = { let d = h: *digest; let copy = *d; let d = &copy; + defer hash::close(d); // Padding. Add a 1 bit and 0 bits until 112 bytes mod 128 let ln = d.ln; @@ -313,3 +328,9 @@ fn block(h: *digest, p: []u8) void = { h.h[6] = h6; h.h[7] = h7; }; + +fn close(stream: *io::stream) void = { + let s = stream: *digest; + bytes::zero((s.h[..]: *[*]u8)[..len(s.h) * size(u32)]); + bytes::zero(s.x); +}; diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib @@ -245,7 +245,7 @@ crypto_blake2b() { then gensrcs_crypto_blake2b gen_ssa crypto::blake2b encoding::hex fmt hash io strings \ - strio crypto::math endian + strio crypto::math endian bytes else gensrcs_crypto_blake2b +test.ha vectors+test.ha gen_ssa crypto::blake2b encoding::hex fmt hash io strings \ @@ -347,7 +347,7 @@ gensrcs_crypto_sha256() { } genssa_crypto_sha256() { - gen_ssa crypto::sha256 hash io endian $* + gen_ssa crypto::sha256 bytes hash io endian $* } crypto_sha256() { @@ -366,10 +366,10 @@ crypto_sha1() { if [ $testing -eq 0 ] then gen_srcs crypto::sha1 sha1.ha - gen_ssa crypto::sha1 hash io endian + gen_ssa crypto::sha1 bytes hash io endian else gen_srcs crypto::sha1 sha1.ha +test.ha - gen_ssa crypto::sha1 hash endian fmt strings encoding::hex + gen_ssa crypto::sha1 bytes hash endian fmt strings encoding::hex fi } @@ -377,10 +377,10 @@ crypto_sha512() { if [ $testing -eq 0 ] then gen_srcs crypto::sha512 sha512.ha - gen_ssa crypto::sha512 hash io endian + gen_ssa crypto::sha512 bytes hash io endian else gen_srcs crypto::sha512 sha512.ha +test.ha - gen_ssa crypto::sha512 hash endian fmt strings encoding::hex + gen_ssa crypto::sha512 bytes hash endian fmt strings encoding::hex fi } diff --git a/stdlib.mk b/stdlib.mk @@ -718,7 +718,7 @@ $(HARECACHE)/crypto/argon2/crypto_argon2-any.ssa: $(stdlib_crypto_argon2_any_src stdlib_crypto_blake2b_any_srcs= \ $(STDLIB)/crypto/blake2b/blake2b.ha -$(HARECACHE)/crypto/blake2b/crypto_blake2b-any.ssa: $(stdlib_crypto_blake2b_any_srcs) $(stdlib_rt) $(stdlib_encoding_hex_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM)) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_strio_$(PLATFORM)) $(stdlib_crypto_math_$(PLATFORM)) $(stdlib_endian_$(PLATFORM)) +$(HARECACHE)/crypto/blake2b/crypto_blake2b-any.ssa: $(stdlib_crypto_blake2b_any_srcs) $(stdlib_rt) $(stdlib_encoding_hex_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM)) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_strio_$(PLATFORM)) $(stdlib_crypto_math_$(PLATFORM)) $(stdlib_endian_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM)) @printf 'HAREC \t$@\n' @mkdir -p $(HARECACHE)/crypto/blake2b @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncrypto::blake2b \ @@ -825,7 +825,7 @@ $(HARECACHE)/crypto/salsa/crypto_salsa-any.ssa: $(stdlib_crypto_salsa_any_srcs) stdlib_crypto_sha1_any_srcs= \ $(STDLIB)/crypto/sha1/sha1.ha -$(HARECACHE)/crypto/sha1/crypto_sha1-any.ssa: $(stdlib_crypto_sha1_any_srcs) $(stdlib_rt) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_endian_$(PLATFORM)) +$(HARECACHE)/crypto/sha1/crypto_sha1-any.ssa: $(stdlib_crypto_sha1_any_srcs) $(stdlib_rt) $(stdlib_bytes_$(PLATFORM)) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_endian_$(PLATFORM)) @printf 'HAREC \t$@\n' @mkdir -p $(HARECACHE)/crypto/sha1 @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncrypto::sha1 \ @@ -835,7 +835,7 @@ $(HARECACHE)/crypto/sha1/crypto_sha1-any.ssa: $(stdlib_crypto_sha1_any_srcs) $(s stdlib_crypto_sha256_any_srcs= \ $(STDLIB)/crypto/sha256/sha256.ha -$(HARECACHE)/crypto/sha256/crypto_sha256-any.ssa: $(stdlib_crypto_sha256_any_srcs) $(stdlib_rt) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_endian_$(PLATFORM)) +$(HARECACHE)/crypto/sha256/crypto_sha256-any.ssa: $(stdlib_crypto_sha256_any_srcs) $(stdlib_rt) $(stdlib_bytes_$(PLATFORM)) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_endian_$(PLATFORM)) @printf 'HAREC \t$@\n' @mkdir -p $(HARECACHE)/crypto/sha256 @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncrypto::sha256 \ @@ -845,7 +845,7 @@ $(HARECACHE)/crypto/sha256/crypto_sha256-any.ssa: $(stdlib_crypto_sha256_any_src stdlib_crypto_sha512_any_srcs= \ $(STDLIB)/crypto/sha512/sha512.ha -$(HARECACHE)/crypto/sha512/crypto_sha512-any.ssa: $(stdlib_crypto_sha512_any_srcs) $(stdlib_rt) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_endian_$(PLATFORM)) +$(HARECACHE)/crypto/sha512/crypto_sha512-any.ssa: $(stdlib_crypto_sha512_any_srcs) $(stdlib_rt) $(stdlib_bytes_$(PLATFORM)) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_endian_$(PLATFORM)) @printf 'HAREC \t$@\n' @mkdir -p $(HARECACHE)/crypto/sha512 @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncrypto::sha512 \ @@ -2638,7 +2638,7 @@ testlib_crypto_sha1_any_srcs= \ $(STDLIB)/crypto/sha1/sha1.ha \ $(STDLIB)/crypto/sha1/+test.ha -$(TESTCACHE)/crypto/sha1/crypto_sha1-any.ssa: $(testlib_crypto_sha1_any_srcs) $(testlib_rt) $(testlib_hash_$(PLATFORM)) $(testlib_endian_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_encoding_hex_$(PLATFORM)) +$(TESTCACHE)/crypto/sha1/crypto_sha1-any.ssa: $(testlib_crypto_sha1_any_srcs) $(testlib_rt) $(testlib_bytes_$(PLATFORM)) $(testlib_hash_$(PLATFORM)) $(testlib_endian_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_encoding_hex_$(PLATFORM)) @printf 'HAREC \t$@\n' @mkdir -p $(TESTCACHE)/crypto/sha1 @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ncrypto::sha1 \ @@ -2649,7 +2649,7 @@ testlib_crypto_sha256_any_srcs= \ $(STDLIB)/crypto/sha256/sha256.ha \ $(STDLIB)/crypto/sha256/+test.ha -$(TESTCACHE)/crypto/sha256/crypto_sha256-any.ssa: $(testlib_crypto_sha256_any_srcs) $(testlib_rt) $(testlib_hash_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_endian_$(PLATFORM)) $(testlib_hash_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_encoding_hex_$(PLATFORM)) +$(TESTCACHE)/crypto/sha256/crypto_sha256-any.ssa: $(testlib_crypto_sha256_any_srcs) $(testlib_rt) $(testlib_bytes_$(PLATFORM)) $(testlib_hash_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_endian_$(PLATFORM)) $(testlib_hash_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_encoding_hex_$(PLATFORM)) @printf 'HAREC \t$@\n' @mkdir -p $(TESTCACHE)/crypto/sha256 @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ncrypto::sha256 \ @@ -2660,7 +2660,7 @@ testlib_crypto_sha512_any_srcs= \ $(STDLIB)/crypto/sha512/sha512.ha \ $(STDLIB)/crypto/sha512/+test.ha -$(TESTCACHE)/crypto/sha512/crypto_sha512-any.ssa: $(testlib_crypto_sha512_any_srcs) $(testlib_rt) $(testlib_hash_$(PLATFORM)) $(testlib_endian_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_encoding_hex_$(PLATFORM)) +$(TESTCACHE)/crypto/sha512/crypto_sha512-any.ssa: $(testlib_crypto_sha512_any_srcs) $(testlib_rt) $(testlib_bytes_$(PLATFORM)) $(testlib_hash_$(PLATFORM)) $(testlib_endian_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_encoding_hex_$(PLATFORM)) @printf 'HAREC \t$@\n' @mkdir -p $(TESTCACHE)/crypto/sha512 @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ncrypto::sha512 \