From f1a5e47aaeb293e977b22446352a1698a723abe7 Mon Sep 17 00:00:00 2001 From: ImagicTheCat Date: Wed, 24 May 2023 16:08:27 +0200 Subject: [PATCH 1/4] Fix/improve MD5 hashing. --- src/modules/data/HashFunction.cpp | 32 +++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/modules/data/HashFunction.cpp b/src/modules/data/HashFunction.cpp index 34d9e008d..79f4d25ef 100644 --- a/src/modules/data/HashFunction.cpp +++ b/src/modules/data/HashFunction.cpp @@ -50,6 +50,13 @@ inline uint64 rightrot(uint64 x, uint8 amount) return (x >> amount) | (x << (64 - amount)); } +// Extend the value of `a` to make it a multiple of `n`. +inline uint64 extend_multiple(uint64 a, uint64 n) +{ + uint64 r = a % n; + return r == 0 ? a : a + (n-r); +} + /** * The following implementation is based on the pseudocode provided by multiple * authors on wikipedia: https://en.wikipedia.org/wiki/MD5 @@ -79,25 +86,22 @@ public: uint32 c0 = 0x98badcfe; uint32 d0 = 0x10325476; - //Do the required padding (MD5, SHA1 and SHA2 use the same padding) - uint64 paddedLength = length + 1; //Consider the appended bit - if (paddedLength % 64 < 56) - paddedLength += 56 - paddedLength % 64; - if (paddedLength % 64 > 56) - paddedLength += 120 - paddedLength % 64; + // Compute final padded length, accounting for the appended bit (byte) and size + uint64 paddedLength = extend_multiple(length + 1 + 8, 64); - uint8 *padded = new uint8[paddedLength + 8]; + uint32 *padded = new uint32[paddedLength / 4]; memcpy(padded, input, length); - memset(padded + length, 0, paddedLength - length); - padded[length] = 0x80; + memset(((uint8*)padded) + length, 0, paddedLength - length); + *(((uint8*)padded) + length) = 0x80; // append bit - //Now we need the length in bits - *((uint64*) &padded[paddedLength]) = length * 8; - paddedLength += 8; + // Append length in bits + uint64 bit_length = length * 8; + memcpy(((uint8*)padded) + paddedLength - 8, &bit_length, 8); - for (uint64 i = 0; i < paddedLength; i += 64) + // Process chunks + for (uint64 i = 0; i < paddedLength/4; i += 16) { - uint32 *chunk = (uint32*) &padded[i]; + uint32 *chunk = &padded[i]; uint32 A = a0; uint32 B = b0; From 4304132f8f8c81e49c478c777ad420b4784be517 Mon Sep 17 00:00:00 2001 From: ImagicTheCat Date: Wed, 24 May 2023 16:09:34 +0200 Subject: [PATCH 2/4] Fix/improve SHA1 hashing. --- src/modules/data/HashFunction.cpp | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/modules/data/HashFunction.cpp b/src/modules/data/HashFunction.cpp index 79f4d25ef..49c5d970c 100644 --- a/src/modules/data/HashFunction.cpp +++ b/src/modules/data/HashFunction.cpp @@ -204,29 +204,25 @@ public: 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }; - //Do the required padding (MD5, SHA1 and SHA2 use the same padding) - uint64 paddedLength = length + 1; //Consider the appended bit - if (paddedLength % 64 < 56) - paddedLength += 56 - paddedLength % 64; - if (paddedLength % 64 > 56) - paddedLength += 120 - paddedLength % 64; + // Compute final padded length, accounting for the appended bit (byte) and size + uint64 paddedLength = extend_multiple(length + 1 + 8, 64); - uint8 *padded = new uint8[paddedLength + 8]; + uint32 *padded = new uint32[paddedLength / 4]; memcpy(padded, input, length); - memset(padded + length, 0, paddedLength - length); - padded[length] = 0x80; + memset(((uint8*)padded) + length, 0, paddedLength - length); + *(((uint8*)padded) + length) = 0x80; // append bit - // Now we need the length in bits (big endian) - length *= 8; - for (int i = 0; i < 8; ++i, ++paddedLength) - padded[paddedLength] = (length >> (56 - i * 8)) & 0xFF; + // Append length in bits (big endian) + uint64 bit_length = length * 8; + for (int i = 0; i < 8; ++i) + *(((uint8*)padded) + (paddedLength - 8 + i)) = (bit_length >> (56 - i * 8)) & 0xFF; // Allocate our extended words uint32 words[80]; - for (uint64 i = 0; i < paddedLength; i += 64) + for (uint64 i = 0; i < paddedLength/4; i += 16) { - uint32 *chunk = (uint32*) &padded[i]; + uint32 *chunk = &padded[i]; for (int j = 0; j < 16; j++) { char *c = (char*) &words[j]; From ade382072d24dfbf75f0615f26b1481ea389ada3 Mon Sep 17 00:00:00 2001 From: ImagicTheCat Date: Wed, 24 May 2023 16:10:53 +0200 Subject: [PATCH 3/4] Fix/improve SHA-224/256 hashing. --- src/modules/data/HashFunction.cpp | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/modules/data/HashFunction.cpp b/src/modules/data/HashFunction.cpp index 49c5d970c..b661c7af1 100644 --- a/src/modules/data/HashFunction.cpp +++ b/src/modules/data/HashFunction.cpp @@ -303,22 +303,18 @@ public: if (!isSupported(function)) throw love::Exception("Hash function not supported by SHA-224/SHA-256 implementation"); - //Do the required padding (MD5, SHA1 and SHA2 use the same padding) - uint64 paddedLength = length + 1; //Consider the appended bit - if (paddedLength % 64 < 56) - paddedLength += 56 - paddedLength % 64; - if (paddedLength % 64 > 56) - paddedLength += 120 - paddedLength % 64; + // Compute final padded length, accounting for the appended bit (byte) and size + uint64 paddedLength = extend_multiple(length + 1 + 8, 64); - uint8 *padded = new uint8[paddedLength + 8]; + uint32 *padded = new uint32[paddedLength / 4]; memcpy(padded, input, length); - memset(padded + length, 0, paddedLength - length); - padded[length] = 0x80; + memset(((uint8*)padded) + length, 0, paddedLength - length); + *(((uint8*)padded) + length) = 0x80; // append bit - // Now we need the length in bits (big endian) - length *= 8; - for (int i = 0; i < 8; ++i, ++paddedLength) - padded[paddedLength] = (length >> (56 - i * 8)) & 0xFF; + // Append length in bits (big endian) + uint64 bit_length = length * 8; + for (int i = 0; i < 8; ++i) + *(((uint8*)padded) + (paddedLength - 8 + i)) = (bit_length >> (56 - i * 8)) & 0xFF; uint32 intermediate[8]; if (function == FUNCTION_SHA224) @@ -329,9 +325,9 @@ public: // Allocate our extended words uint32 words[64]; - for (uint64 i = 0; i < paddedLength; i += 64) + for (uint64 i = 0; i < paddedLength/4; i += 16) { - uint32 *chunk = (uint32*) &padded[i]; + uint32 *chunk = &padded[i]; for (int j = 0; j < 16; j++) { char *c = (char*) &words[j]; From 22e68868e195f83e53fbafe994c0f13f9d13f5a0 Mon Sep 17 00:00:00 2001 From: ImagicTheCat Date: Wed, 24 May 2023 16:21:35 +0200 Subject: [PATCH 4/4] Fix/improve SHA-384/512 hashing. --- src/modules/data/HashFunction.cpp | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/modules/data/HashFunction.cpp b/src/modules/data/HashFunction.cpp index b661c7af1..03c67f68f 100644 --- a/src/modules/data/HashFunction.cpp +++ b/src/modules/data/HashFunction.cpp @@ -455,31 +455,26 @@ public: else memcpy(intermediates, initial512, sizeof(intermediates)); - //Do the required padding - uint64 paddedLength = length + 1; //Consider the appended bit - if (paddedLength % 128 < 112) - paddedLength += 112 - paddedLength % 128; - if (paddedLength % 128 > 112) - paddedLength += 240 - paddedLength % 128; + // Compute final padded length, accounting for the appended bit (byte) and size + uint64 paddedLength = extend_multiple(length + 1 + 16, 128); - uint8 *padded = new uint8[paddedLength + 16]; - paddedLength += 8; + uint64 *padded = new uint64[paddedLength / 8]; memcpy(padded, input, length); - memset(padded + length, 0, paddedLength - length); - padded[length] = 0x80; + memset(((uint8*)padded) + length, 0, paddedLength - length); + *(((uint8*)padded) + length) = 0x80; // append bit - // Now we need the length in bits (big endian), note we only write a 64-bit int, so + // Append length in bits (big endian), note we only write a 64-bit int, so // we have filled the first 8 bytes with zeroes - length *= 8; - for (int i = 0; i < 8; ++i, ++paddedLength) - padded[paddedLength] = (length >> (56 - i * 8)) & 0xFF; + uint64 bit_length = length * 8; + for (int i = 0; i < 8; ++i) + *(((uint8*)padded) + (paddedLength - 8 + i)) = (bit_length >> (56 - i * 8)) & 0xFF; // Allocate our extended words uint64 words[80]; - for (uint64 i = 0; i < paddedLength; i += 128) + for (uint64 i = 0; i < paddedLength/8; i += 16) { - uint64 *chunk = (uint64*) &padded[i]; + uint64 *chunk = &padded[i]; for (int j = 0; j < 16; ++j) { char *c = (char*) &words[j];