From 0448e50b3dd8d18bc46d18e5306a9619b93af1d2 Mon Sep 17 00:00:00 2001 From: Zack Puhl Date: Fri, 27 Jun 2025 21:20:33 -0400 Subject: [PATCH] Fix Incorrect SHA256 Hashes for Large Inputs (#2247) * fix >256MiB sha256 bitcount computation overflow --- lib/std/hash/sha256.c3 | 5 +++-- test/unit/stdlib/hash/sha256.c3 | 15 ++++++++++++++- test/unit/stdlib/hash/sha512.c3 | 15 ++++++++++++++- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/lib/std/hash/sha256.c3 b/lib/std/hash/sha256.c3 index 46ea81f94..23b0e701b 100644 --- a/lib/std/hash/sha256.c3 +++ b/lib/std/hash/sha256.c3 @@ -71,7 +71,7 @@ fn void Sha256.update(&self, char[] data) { uint i = 0; uint len = data.len; uint buffer_pos = (uint)(self.bitcount / 8) % BLOCK_SIZE; - self.bitcount += (ulong)(len * 8); + self.bitcount += ((ulong)len * 8); while (len--) { self.buffer[buffer_pos++] = data[i++]; @@ -173,4 +173,5 @@ fn void sha256_transform(uint* state, char* buffer) @local { state[7] += h; a = b = c = d = e = f = g = h = t1 = t2 = i = 0; m[:64] = buffer[:64] = 0; -} \ No newline at end of file +} + diff --git a/test/unit/stdlib/hash/sha256.c3 b/test/unit/stdlib/hash/sha256.c3 index d14c15801..ca6a7dd84 100644 --- a/test/unit/stdlib/hash/sha256.c3 +++ b/test/unit/stdlib/hash/sha256.c3 @@ -27,6 +27,18 @@ fn void test_sha256_longer() assert(sha.final() == x"59F109D9 533B2B70 E7C3B814 A2BD218F 78EA5D37 14455BC6 7987CF0D 664399CF"); } +fn void gigahash_sha256() +{ + // > 256 MiB is just at the threshold where the SHA bitcounter rolls overflows 'len', but doesn't hit the uint.max limit... + char[] c = calloc(257 * (1024*1024))[:(257*1024*1024)]; + defer free(c); + + Sha256 sha; + sha.init(); + sha.update(c); + assert(sha.final() == x"053EADFD EC682CF1 6F3F8704 C7609C57 868DD757 65E08DC5 A7491F5D 06BCB74D"); +} + fn void test_pbkdf2() { char[] pw = "password"; @@ -71,4 +83,5 @@ fn void test_sha256_million_a() } assert(sha.final() == x"CDC76E5C 9914FB92 81A1C7E2 84D73E67 F1809A48 A497200E 046D39CC C7112CD0"); -} \ No newline at end of file +} + diff --git a/test/unit/stdlib/hash/sha512.c3 b/test/unit/stdlib/hash/sha512.c3 index e829156ef..0ba9410f5 100644 --- a/test/unit/stdlib/hash/sha512.c3 +++ b/test/unit/stdlib/hash/sha512.c3 @@ -25,6 +25,18 @@ fn void test_sha512_longer() assert(sha.final() == x"7361ec4a617b6473fb751c44d1026db9442915a5fcea1a419e615d2f3bc5069494da28b8cf2e4412a1dc97d6848f9c84a254fb884ad0720a83eaa0434aeafd8c"); } +fn void gigahash_sha512() +{ + // This test is here because of an overflow that was present in SHA256. + char[] c = calloc(257 * (1024*1024))[:(257*1024*1024)]; + defer free(c); + + Sha512 sha; + sha.init(); + sha.update(c); + assert(sha.final() == x"724999ca733fdd49f489fc59a49ce41460531a78aa0c03488be9f4a1e29f955bd325d47462c89234a8f587d8a5d6a9ab79137bc5ce3acbfb928553dba8431a36"); +} + fn void test_pbkdf2() { char[] pw = "password"; @@ -66,4 +78,5 @@ fn void test_sha512_million_a() sha.update("aaaaaaaaaa"); } assert(sha.final() == x"e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"); -} \ No newline at end of file +} +