diff --git a/doc/crypto.dox b/doc/crypto.dox index ab416a45..8ea74699 100644 --- a/doc/crypto.dox +++ b/doc/crypto.dox @@ -63,13 +63,13 @@ Ardunino Mega 2560 running at 16 MHz are similar: ChaCha (20 rounds)14.87us14.88us43.74us130 ChaCha (12 rounds)10.38us10.38us43.74us130 ChaCha (8 rounds)8.13us8.14us43.74us130 -SHA121.90us 94 -SHA25643.85us 106 -SHA512123.25us 210 +SHA121.90us 93 +SHA25643.85us 105 +SHA512123.24us 209 SHA3_256121.69us 403 SHA3_512229.12us 403 -BLAKE2s18.54us 170 -BLAKE2b50.59us 338 +BLAKE2s18.54us 169 +BLAKE2b50.58us 337 Where a cipher supports more than one key size (such as ChaCha), the values diff --git a/libraries/Crypto/BLAKE2b.cpp b/libraries/Crypto/BLAKE2b.cpp index ec0fbe64..569cb518 100644 --- a/libraries/Crypto/BLAKE2b.cpp +++ b/libraries/Crypto/BLAKE2b.cpp @@ -89,7 +89,6 @@ void BLAKE2b::reset() state.h[6] = BLAKE2b_IV6; state.h[7] = BLAKE2b_IV7; state.chunkSize = 0; - state.finalized = false; state.lengthLow = 0; state.lengthHigh = 0; } @@ -112,17 +111,12 @@ void BLAKE2b::reset(uint8_t outputLength) state.h[6] = BLAKE2b_IV6; state.h[7] = BLAKE2b_IV7; state.chunkSize = 0; - state.finalized = false; state.lengthLow = 0; state.lengthHigh = 0; } void BLAKE2b::update(const void *data, size_t len) { - // Reset the hashing process if finalize() was called previously. - if (state.finalized) - reset(); - // Break the input up into 1024-bit chunks and process each in turn. const uint8_t *d = (const uint8_t *)data; while (len > 0) { @@ -148,17 +142,13 @@ void BLAKE2b::update(const void *data, size_t len) void BLAKE2b::finalize(void *hash, size_t len) { - // Finalize the hash if necessary. - if (!state.finalized) { - // Pad the last chunk and hash it with f0 set to all-ones. - memset(((uint8_t *)state.m) + state.chunkSize, 0, 128 - state.chunkSize); - processChunk(0xFFFFFFFFFFFFFFFFULL); + // Pad the last chunk and hash it with f0 set to all-ones. + memset(((uint8_t *)state.m) + state.chunkSize, 0, 128 - state.chunkSize); + processChunk(0xFFFFFFFFFFFFFFFFULL); - // Convert the hash into little-endian in the message buffer. - for (uint8_t posn = 0; posn < 8; ++posn) - state.m[posn] = htole64(state.h[posn]); - state.finalized = true; - } + // Convert the hash into little-endian in the message buffer. + for (uint8_t posn = 0; posn < 8; ++posn) + state.m[posn] = htole64(state.h[posn]); // Copy the hash to the caller's return buffer. if (len > 64) diff --git a/libraries/Crypto/BLAKE2b.h b/libraries/Crypto/BLAKE2b.h index 781b6761..67d7e887 100644 --- a/libraries/Crypto/BLAKE2b.h +++ b/libraries/Crypto/BLAKE2b.h @@ -46,10 +46,9 @@ private: uint64_t h[8]; uint64_t m[16]; uint64_t v[16]; - uint8_t chunkSize; - bool finalized; uint64_t lengthLow; uint64_t lengthHigh; + uint8_t chunkSize; } state; void processChunk(uint64_t f0); diff --git a/libraries/Crypto/BLAKE2s.cpp b/libraries/Crypto/BLAKE2s.cpp index 762dfa1a..a3244611 100644 --- a/libraries/Crypto/BLAKE2s.cpp +++ b/libraries/Crypto/BLAKE2s.cpp @@ -89,7 +89,6 @@ void BLAKE2s::reset() state.h[6] = BLAKE2s_IV6; state.h[7] = BLAKE2s_IV7; state.chunkSize = 0; - state.finalized = false; state.length = 0; } @@ -111,16 +110,11 @@ void BLAKE2s::reset(uint8_t outputLength) state.h[6] = BLAKE2s_IV6; state.h[7] = BLAKE2s_IV7; state.chunkSize = 0; - state.finalized = false; state.length = 0; } void BLAKE2s::update(const void *data, size_t len) { - // Reset the hashing process if finalize() was called previously. - if (state.finalized) - reset(); - // Break the input up into 512-bit chunks and process each in turn. const uint8_t *d = (const uint8_t *)data; while (len > 0) { @@ -143,17 +137,13 @@ void BLAKE2s::update(const void *data, size_t len) void BLAKE2s::finalize(void *hash, size_t len) { - // Finalize the hash if necessary. - if (!state.finalized) { - // Pad the last chunk and hash it with f0 set to all-ones. - memset(((uint8_t *)state.m) + state.chunkSize, 0, 64 - state.chunkSize); - processChunk(0xFFFFFFFF); + // Pad the last chunk and hash it with f0 set to all-ones. + memset(((uint8_t *)state.m) + state.chunkSize, 0, 64 - state.chunkSize); + processChunk(0xFFFFFFFF); - // Convert the hash into little-endian in the message buffer. - for (uint8_t posn = 0; posn < 8; ++posn) - state.m[posn] = htole32(state.h[posn]); - state.finalized = true; - } + // Convert the hash into little-endian in the message buffer. + for (uint8_t posn = 0; posn < 8; ++posn) + state.m[posn] = htole32(state.h[posn]); // Copy the hash to the caller's return buffer. if (len > 32) diff --git a/libraries/Crypto/BLAKE2s.h b/libraries/Crypto/BLAKE2s.h index 51f8df14..a996fff1 100644 --- a/libraries/Crypto/BLAKE2s.h +++ b/libraries/Crypto/BLAKE2s.h @@ -46,9 +46,8 @@ private: uint32_t h[8]; uint32_t m[16]; uint32_t v[16]; - uint8_t chunkSize; - bool finalized; uint64_t length; + uint8_t chunkSize; } state; void processChunk(uint32_t f0); diff --git a/libraries/Crypto/Hash.cpp b/libraries/Crypto/Hash.cpp index e6801107..f0f3b3ab 100644 --- a/libraries/Crypto/Hash.cpp +++ b/libraries/Crypto/Hash.cpp @@ -76,8 +76,8 @@ Hash::~Hash() * \param data Data to be hashed. * \param len Number of bytes of data to be hashed. * - * If finalize() has already been called, then calling update() will - * reset() the hash and start a new hashing process. + * If finalize() has already been called, then the behavior of update() will + * be undefined. Call reset() first to start a new hashing process. * * \sa reset(), finalize() */ @@ -93,8 +93,8 @@ Hash::~Hash() * truncated to the first \a len bytes. If \a len is greater than * hashSize(), then the remaining bytes will left unchanged. * - * If finalize() is called again, the same hash value is returned again until - * the next call to reset() or update(). + * If finalize() is called again, then the returned \a hash value is + * undefined. Call reset() first to start a new hashing process. * * \sa reset(), update() */ diff --git a/libraries/Crypto/SHA1.cpp b/libraries/Crypto/SHA1.cpp index 8783fdad..ab5ac575 100644 --- a/libraries/Crypto/SHA1.cpp +++ b/libraries/Crypto/SHA1.cpp @@ -69,16 +69,11 @@ void SHA1::reset() state.h[3] = 0x10325476; state.h[4] = 0xC3D2E1F0; state.chunkSize = 0; - state.finalized = false; state.length = 0; } void SHA1::update(const void *data, size_t len) { - // Reset the hashing process if finalize() was called previously. - if (state.finalized) - reset(); - // Update the total length (in bits, not bytes). state.length += ((uint64_t)len) << 3; @@ -101,33 +96,29 @@ void SHA1::update(const void *data, size_t len) void SHA1::finalize(void *hash, size_t len) { - // Finalize the hash if necessary. - if (!state.finalized) { - // Pad the last chunk. We may need two padding chunks if there - // isn't enough room in the first for the padding and length. - uint8_t *wbytes = (uint8_t *)state.w; - if (state.chunkSize <= (64 - 9)) { - wbytes[state.chunkSize] = 0x80; - memset(wbytes + state.chunkSize + 1, 0x00, 64 - 8 - (state.chunkSize + 1)); - state.w[14] = htobe32((uint32_t)(state.length >> 32)); - state.w[15] = htobe32((uint32_t)state.length); - processChunk(); - } else { - wbytes[state.chunkSize] = 0x80; - memset(wbytes + state.chunkSize + 1, 0x00, 64 - (state.chunkSize + 1)); - processChunk(); - memset(wbytes, 0x00, 64 - 8); - state.w[14] = htobe32((uint32_t)(state.length >> 32)); - state.w[15] = htobe32((uint32_t)state.length); - processChunk(); - } - - // Convert the result into big endian and return it. - for (uint8_t posn = 0; posn < 5; ++posn) - state.w[posn] = htobe32(state.h[posn]); - state.finalized = true; + // Pad the last chunk. We may need two padding chunks if there + // isn't enough room in the first for the padding and length. + uint8_t *wbytes = (uint8_t *)state.w; + if (state.chunkSize <= (64 - 9)) { + wbytes[state.chunkSize] = 0x80; + memset(wbytes + state.chunkSize + 1, 0x00, 64 - 8 - (state.chunkSize + 1)); + state.w[14] = htobe32((uint32_t)(state.length >> 32)); + state.w[15] = htobe32((uint32_t)state.length); + processChunk(); + } else { + wbytes[state.chunkSize] = 0x80; + memset(wbytes + state.chunkSize + 1, 0x00, 64 - (state.chunkSize + 1)); + processChunk(); + memset(wbytes, 0x00, 64 - 8); + state.w[14] = htobe32((uint32_t)(state.length >> 32)); + state.w[15] = htobe32((uint32_t)state.length); + processChunk(); } + // Convert the result into big endian and return it. + for (uint8_t posn = 0; posn < 5; ++posn) + state.w[posn] = htobe32(state.h[posn]); + // Copy the hash to the caller's return buffer. if (len > 20) len = 20; diff --git a/libraries/Crypto/SHA1.h b/libraries/Crypto/SHA1.h index 83ed362f..1a81a0cb 100644 --- a/libraries/Crypto/SHA1.h +++ b/libraries/Crypto/SHA1.h @@ -44,9 +44,8 @@ private: struct { uint32_t h[5]; uint32_t w[16]; - uint8_t chunkSize; - bool finalized; uint64_t length; + uint8_t chunkSize; } state; void processChunk(); diff --git a/libraries/Crypto/SHA256.cpp b/libraries/Crypto/SHA256.cpp index 30257620..26b1b500 100644 --- a/libraries/Crypto/SHA256.cpp +++ b/libraries/Crypto/SHA256.cpp @@ -74,16 +74,11 @@ void SHA256::reset() state.h[6] = 0x1f83d9ab; state.h[7] = 0x5be0cd19; state.chunkSize = 0; - state.finalized = false; state.length = 0; } void SHA256::update(const void *data, size_t len) { - // Reset the hashing process if finalize() was called previously. - if (state.finalized) - reset(); - // Update the total length (in bits, not bytes). state.length += ((uint64_t)len) << 3; @@ -106,33 +101,29 @@ void SHA256::update(const void *data, size_t len) void SHA256::finalize(void *hash, size_t len) { - // Finalize the hash if necessary. - if (!state.finalized) { - // Pad the last chunk. We may need two padding chunks if there - // isn't enough room in the first for the padding and length. - uint8_t *wbytes = (uint8_t *)state.w; - if (state.chunkSize <= (64 - 9)) { - wbytes[state.chunkSize] = 0x80; - memset(wbytes + state.chunkSize + 1, 0x00, 64 - 8 - (state.chunkSize + 1)); - state.w[14] = htobe32((uint32_t)(state.length >> 32)); - state.w[15] = htobe32((uint32_t)state.length); - processChunk(); - } else { - wbytes[state.chunkSize] = 0x80; - memset(wbytes + state.chunkSize + 1, 0x00, 64 - (state.chunkSize + 1)); - processChunk(); - memset(wbytes, 0x00, 64 - 8); - state.w[14] = htobe32((uint32_t)(state.length >> 32)); - state.w[15] = htobe32((uint32_t)state.length); - processChunk(); - } - - // Convert the result into big endian and return it. - for (uint8_t posn = 0; posn < 8; ++posn) - state.w[posn] = htobe32(state.h[posn]); - state.finalized = true; + // Pad the last chunk. We may need two padding chunks if there + // isn't enough room in the first for the padding and length. + uint8_t *wbytes = (uint8_t *)state.w; + if (state.chunkSize <= (64 - 9)) { + wbytes[state.chunkSize] = 0x80; + memset(wbytes + state.chunkSize + 1, 0x00, 64 - 8 - (state.chunkSize + 1)); + state.w[14] = htobe32((uint32_t)(state.length >> 32)); + state.w[15] = htobe32((uint32_t)state.length); + processChunk(); + } else { + wbytes[state.chunkSize] = 0x80; + memset(wbytes + state.chunkSize + 1, 0x00, 64 - (state.chunkSize + 1)); + processChunk(); + memset(wbytes, 0x00, 64 - 8); + state.w[14] = htobe32((uint32_t)(state.length >> 32)); + state.w[15] = htobe32((uint32_t)state.length); + processChunk(); } + // Convert the result into big endian and return it. + for (uint8_t posn = 0; posn < 8; ++posn) + state.w[posn] = htobe32(state.h[posn]); + // Copy the hash to the caller's return buffer. if (len > 32) len = 32; diff --git a/libraries/Crypto/SHA256.h b/libraries/Crypto/SHA256.h index f65a08cf..c4a2504b 100644 --- a/libraries/Crypto/SHA256.h +++ b/libraries/Crypto/SHA256.h @@ -44,9 +44,8 @@ private: struct { uint32_t h[8]; uint32_t w[16]; - uint8_t chunkSize; - bool finalized; uint64_t length; + uint8_t chunkSize; } state; void processChunk(); diff --git a/libraries/Crypto/SHA512.cpp b/libraries/Crypto/SHA512.cpp index d9588dda..cfe8859c 100644 --- a/libraries/Crypto/SHA512.cpp +++ b/libraries/Crypto/SHA512.cpp @@ -72,17 +72,12 @@ void SHA512::reset() }; memcpy_P(state.h, hashStart, sizeof(hashStart)); state.chunkSize = 0; - state.finalized = false; state.lengthLow = 0; state.lengthHigh = 0; } void SHA512::update(const void *data, size_t len) { - // Reset the hashing process if finalize() was called previously. - if (state.finalized) - reset(); - // Update the total length in bits, not bytes. uint64_t temp = state.lengthLow; state.lengthLow += (((uint64_t)len) << 3); @@ -109,33 +104,29 @@ void SHA512::update(const void *data, size_t len) void SHA512::finalize(void *hash, size_t len) { - // Finalize the hash if necessary. - if (!state.finalized) { - // Pad the last chunk. We may need two padding chunks if there - // isn't enough room in the first for the padding and length. - uint8_t *wbytes = (uint8_t *)state.w; - if (state.chunkSize <= (128 - 17)) { - wbytes[state.chunkSize] = 0x80; - memset(wbytes + state.chunkSize + 1, 0x00, 128 - 16 - (state.chunkSize + 1)); - state.w[14] = htobe64(state.lengthHigh); - state.w[15] = htobe64(state.lengthLow); - processChunk(); - } else { - wbytes[state.chunkSize] = 0x80; - memset(wbytes + state.chunkSize + 1, 0x00, 128 - (state.chunkSize + 1)); - processChunk(); - memset(wbytes, 0x00, 128 - 16); - state.w[14] = htobe64(state.lengthHigh); - state.w[15] = htobe64(state.lengthLow); - processChunk(); - } - - // Convert the result into big endian and return it. - for (uint8_t posn = 0; posn < 8; ++posn) - state.w[posn] = htobe64(state.h[posn]); - state.finalized = true; + // Pad the last chunk. We may need two padding chunks if there + // isn't enough room in the first for the padding and length. + uint8_t *wbytes = (uint8_t *)state.w; + if (state.chunkSize <= (128 - 17)) { + wbytes[state.chunkSize] = 0x80; + memset(wbytes + state.chunkSize + 1, 0x00, 128 - 16 - (state.chunkSize + 1)); + state.w[14] = htobe64(state.lengthHigh); + state.w[15] = htobe64(state.lengthLow); + processChunk(); + } else { + wbytes[state.chunkSize] = 0x80; + memset(wbytes + state.chunkSize + 1, 0x00, 128 - (state.chunkSize + 1)); + processChunk(); + memset(wbytes, 0x00, 128 - 16); + state.w[14] = htobe64(state.lengthHigh); + state.w[15] = htobe64(state.lengthLow); + processChunk(); } + // Convert the result into big endian and return it. + for (uint8_t posn = 0; posn < 8; ++posn) + state.w[posn] = htobe64(state.h[posn]); + // Copy the hash to the caller's return buffer. if (len > 64) len = 64; diff --git a/libraries/Crypto/SHA512.h b/libraries/Crypto/SHA512.h index ae37118a..d394ae45 100644 --- a/libraries/Crypto/SHA512.h +++ b/libraries/Crypto/SHA512.h @@ -44,10 +44,9 @@ private: struct { uint64_t h[8]; uint64_t w[16]; - uint8_t chunkSize; - bool finalized; uint64_t lengthLow; uint64_t lengthHigh; + uint8_t chunkSize; } state; void processChunk(); diff --git a/libraries/Crypto/examples/TestBLAKE2b/TestBLAKE2b.ino b/libraries/Crypto/examples/TestBLAKE2b/TestBLAKE2b.ino index adfe1418..e40c0a92 100644 --- a/libraries/Crypto/examples/TestBLAKE2b/TestBLAKE2b.ino +++ b/libraries/Crypto/examples/TestBLAKE2b/TestBLAKE2b.ino @@ -98,17 +98,7 @@ bool testHash_N(Hash *hash, const struct TestHashVector *test, size_t inc) size_t posn, len; uint8_t value[HASH_SIZE]; - for (posn = 0; posn < size; posn += inc) { - len = size - posn; - if (len > inc) - len = inc; - hash->update(test->data + posn, len); - } - hash->finalize(value, sizeof(value)); - if (memcmp(value, test->hash, sizeof(value)) != 0) - return false; - - // Try again to make sure the hash resets. + hash->reset(); for (posn = 0; posn < size; posn += inc) { len = size - posn; if (len > inc) diff --git a/libraries/Crypto/examples/TestBLAKE2s/TestBLAKE2s.ino b/libraries/Crypto/examples/TestBLAKE2s/TestBLAKE2s.ino index d7eb6839..26d4c9ee 100644 --- a/libraries/Crypto/examples/TestBLAKE2s/TestBLAKE2s.ino +++ b/libraries/Crypto/examples/TestBLAKE2s/TestBLAKE2s.ino @@ -82,17 +82,7 @@ bool testHash_N(Hash *hash, const struct TestHashVector *test, size_t inc) size_t posn, len; uint8_t value[HASH_SIZE]; - for (posn = 0; posn < size; posn += inc) { - len = size - posn; - if (len > inc) - len = inc; - hash->update(test->data + posn, len); - } - hash->finalize(value, sizeof(value)); - if (memcmp(value, test->hash, sizeof(value)) != 0) - return false; - - // Try again to make sure the hash resets. + hash->reset(); for (posn = 0; posn < size; posn += inc) { len = size - posn; if (len > inc) diff --git a/libraries/Crypto/examples/TestSHA1/TestSHA1.ino b/libraries/Crypto/examples/TestSHA1/TestSHA1.ino index 033b2fdd..da398f1a 100644 --- a/libraries/Crypto/examples/TestSHA1/TestSHA1.ino +++ b/libraries/Crypto/examples/TestSHA1/TestSHA1.ino @@ -62,17 +62,7 @@ bool testHash_N(Hash *hash, const struct TestHashVector *test, size_t inc) size_t posn, len; uint8_t value[HASH_SIZE]; - for (posn = 0; posn < size; posn += inc) { - len = size - posn; - if (len > inc) - len = inc; - hash->update(test->data + posn, len); - } - hash->finalize(value, sizeof(value)); - if (memcmp(value, test->hash, sizeof(value)) != 0) - return false; - - // Try again to make sure the hash resets. + hash->reset(); for (posn = 0; posn < size; posn += inc) { len = size - posn; if (len > inc) diff --git a/libraries/Crypto/examples/TestSHA256/TestSHA256.ino b/libraries/Crypto/examples/TestSHA256/TestSHA256.ino index 767acd5c..6117ee2b 100644 --- a/libraries/Crypto/examples/TestSHA256/TestSHA256.ino +++ b/libraries/Crypto/examples/TestSHA256/TestSHA256.ino @@ -64,17 +64,7 @@ bool testHash_N(Hash *hash, const struct TestHashVector *test, size_t inc) size_t posn, len; uint8_t value[HASH_SIZE]; - for (posn = 0; posn < size; posn += inc) { - len = size - posn; - if (len > inc) - len = inc; - hash->update(test->data + posn, len); - } - hash->finalize(value, sizeof(value)); - if (memcmp(value, test->hash, sizeof(value)) != 0) - return false; - - // Try again to make sure the hash resets. + hash->reset(); for (posn = 0; posn < size; posn += inc) { len = size - posn; if (len > inc) diff --git a/libraries/Crypto/examples/TestSHA512/TestSHA512.ino b/libraries/Crypto/examples/TestSHA512/TestSHA512.ino index 9e47701d..e1876459 100644 --- a/libraries/Crypto/examples/TestSHA512/TestSHA512.ino +++ b/libraries/Crypto/examples/TestSHA512/TestSHA512.ino @@ -85,17 +85,7 @@ bool testHash_N(Hash *hash, const struct TestHashVector *test, size_t inc) size_t posn, len; uint8_t value[HASH_SIZE]; - for (posn = 0; posn < size; posn += inc) { - len = size - posn; - if (len > inc) - len = inc; - hash->update(test->data + posn, len); - } - hash->finalize(value, sizeof(value)); - if (memcmp(value, test->hash, sizeof(value)) != 0) - return false; - - // Try again to make sure the hash resets. + hash->reset(); for (posn = 0; posn < size; posn += inc) { len = size - posn; if (len > inc)