From 3e3e90b19e0cfe5d90b4cab44cbdf195820ecac5 Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Wed, 20 Jun 2018 19:41:47 +1000 Subject: [PATCH] Copying hash states to allow obtaining intermediate hash values --- libraries/Crypto/BLAKE2b.cpp | 34 +++++++++++++++ libraries/Crypto/BLAKE2b.h | 2 + libraries/Crypto/BLAKE2s.cpp | 34 +++++++++++++++ libraries/Crypto/BLAKE2s.h | 2 + libraries/Crypto/KeccakCore.cpp | 15 +++++++ libraries/Crypto/KeccakCore.h | 2 + libraries/Crypto/SHA256.cpp | 34 +++++++++++++++ libraries/Crypto/SHA256.h | 2 + libraries/Crypto/SHA3.cpp | 68 +++++++++++++++++++++++++++++ libraries/Crypto/SHA3.h | 4 ++ libraries/Crypto/SHA512.cpp | 34 +++++++++++++++ libraries/Crypto/SHA512.h | 2 + libraries/CryptoLegacy/src/SHA1.cpp | 34 +++++++++++++++ libraries/CryptoLegacy/src/SHA1.h | 2 + 14 files changed, 269 insertions(+) diff --git a/libraries/Crypto/BLAKE2b.cpp b/libraries/Crypto/BLAKE2b.cpp index d19f7353..9768d0cb 100644 --- a/libraries/Crypto/BLAKE2b.cpp +++ b/libraries/Crypto/BLAKE2b.cpp @@ -255,6 +255,40 @@ void BLAKE2b::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t ha clean(temp); } +/** + * \brief Copies the entire hash state from another object. + * + * \param other The other object to copy the state from. + * + * This function is intended for scenarios where the application needs to + * finalize the state to get an intermediate hash value, but must then + * continue hashing new data into the original state. + * + * In the following example, h1 will be the hash over data1 and h2 will + * be the hash over data1 concatenated with data2: + * + * \code + * // Hash the initial data. + * BLAKE2b hash1; + * hash1.update(data1, sizeof(data1)); + * + * // Copy the hash state and finalize to create h1. + * BLAKE2b hash2; + * hash2.copyFrom(hash1); + * hash2.finalize(h1, sizeof(h1)); + * + * // Continue adding data to the original unfinalized hash. + * hash1.update(data2, sizeof(data2)); + * + * // Get the final hash value h2. + * hash1.finalize(h2, sizeof(h2)); + * \endcode + */ +void BLAKE2b::copyFrom(const BLAKE2b &other) +{ + state = other.state; +} + // Permutation on the message input state for BLAKE2b. static const uint8_t sigma[12][16] PROGMEM = { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, diff --git a/libraries/Crypto/BLAKE2b.h b/libraries/Crypto/BLAKE2b.h index e3f78684..5d67a298 100644 --- a/libraries/Crypto/BLAKE2b.h +++ b/libraries/Crypto/BLAKE2b.h @@ -46,6 +46,8 @@ public: void resetHMAC(const void *key, size_t keyLen); void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen); + void copyFrom(const BLAKE2b &other); + private: struct { uint64_t h[8]; diff --git a/libraries/Crypto/BLAKE2s.cpp b/libraries/Crypto/BLAKE2s.cpp index 2a548538..05638512 100644 --- a/libraries/Crypto/BLAKE2s.cpp +++ b/libraries/Crypto/BLAKE2s.cpp @@ -249,6 +249,40 @@ void BLAKE2s::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t ha clean(temp); } +/** + * \brief Copies the entire hash state from another object. + * + * \param other The other object to copy the state from. + * + * This function is intended for scenarios where the application needs to + * finalize the state to get an intermediate hash value, but must then + * continue hashing new data into the original state. + * + * In the following example, h1 will be the hash over data1 and h2 will + * be the hash over data1 concatenated with data2: + * + * \code + * // Hash the initial data. + * BLAKE2s hash1; + * hash1.update(data1, sizeof(data1)); + * + * // Copy the hash state and finalize to create h1. + * BLAKE2s hash2; + * hash2.copyFrom(hash1); + * hash2.finalize(h1, sizeof(h1)); + * + * // Continue adding data to the original unfinalized hash. + * hash1.update(data2, sizeof(data2)); + * + * // Get the final hash value h2. + * hash1.finalize(h2, sizeof(h2)); + * \endcode + */ +void BLAKE2s::copyFrom(const BLAKE2s &other) +{ + state = other.state; +} + // Permutation on the message input state for BLAKE2s. static const uint8_t sigma[10][16] PROGMEM = { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, diff --git a/libraries/Crypto/BLAKE2s.h b/libraries/Crypto/BLAKE2s.h index 3ebae2e6..bb2266f2 100644 --- a/libraries/Crypto/BLAKE2s.h +++ b/libraries/Crypto/BLAKE2s.h @@ -46,6 +46,8 @@ public: void resetHMAC(const void *key, size_t keyLen); void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen); + void copyFrom(const BLAKE2s &other); + private: struct { uint32_t h[8]; diff --git a/libraries/Crypto/KeccakCore.cpp b/libraries/Crypto/KeccakCore.cpp index 4cc108af..6ff18efb 100644 --- a/libraries/Crypto/KeccakCore.cpp +++ b/libraries/Crypto/KeccakCore.cpp @@ -318,6 +318,21 @@ void KeccakCore::setHMACKey(const void *key, size_t len, uint8_t pad, size_t has keccakp(); } +/** + * \brief Copies the entire Keccak state from another object. + * + * \param other The other object to copy the state from. + * + * This function is intended for scenarios where the application needs to + * finalize the state to get an intermediate hash value, but must then + * continue hashing new data into the original state. + */ +void KeccakCore::copyFrom(const KeccakCore &other) +{ + state = other.state; + _blockSize = other._blockSize; +} + /** * \brief Transform the state with the KECCAK-p sponge function with b = 1600. */ diff --git a/libraries/Crypto/KeccakCore.h b/libraries/Crypto/KeccakCore.h index ca2447ee..e8054813 100644 --- a/libraries/Crypto/KeccakCore.h +++ b/libraries/Crypto/KeccakCore.h @@ -49,6 +49,8 @@ public: void setHMACKey(const void *key, size_t len, uint8_t pad, size_t hashSize); + void copyFrom(const KeccakCore &other); + private: struct { uint64_t A[5][5]; diff --git a/libraries/Crypto/SHA256.cpp b/libraries/Crypto/SHA256.cpp index 098b2e7a..a5718c6e 100644 --- a/libraries/Crypto/SHA256.cpp +++ b/libraries/Crypto/SHA256.cpp @@ -155,6 +155,40 @@ void SHA256::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t has clean(temp); } +/** + * \brief Copies the entire hash state from another object. + * + * \param other The other object to copy the state from. + * + * This function is intended for scenarios where the application needs to + * finalize the state to get an intermediate hash value, but must then + * continue hashing new data into the original state. + * + * In the following example, h1 will be the hash over data1 and h2 will + * be the hash over data1 concatenated with data2: + * + * \code + * // Hash the initial data. + * SHA256 hash1; + * hash1.update(data1, sizeof(data1)); + * + * // Copy the hash state and finalize to create h1. + * SHA256 hash2; + * hash2.copyFrom(hash1); + * hash2.finalize(h1, sizeof(h1)); + * + * // Continue adding data to the original unfinalized hash. + * hash1.update(data2, sizeof(data2)); + * + * // Get the final hash value h2. + * hash1.finalize(h2, sizeof(h2)); + * \endcode + */ +void SHA256::copyFrom(const SHA256 &other) +{ + state = other.state; +} + /** * \brief Processes a single 512-bit chunk with the core SHA-256 algorithm. * diff --git a/libraries/Crypto/SHA256.h b/libraries/Crypto/SHA256.h index 246ea586..a32d67c5 100644 --- a/libraries/Crypto/SHA256.h +++ b/libraries/Crypto/SHA256.h @@ -43,6 +43,8 @@ public: void resetHMAC(const void *key, size_t keyLen); void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen); + void copyFrom(const SHA256 &other); + private: struct { uint32_t h[8]; diff --git a/libraries/Crypto/SHA3.cpp b/libraries/Crypto/SHA3.cpp index 74353c44..e02db024 100644 --- a/libraries/Crypto/SHA3.cpp +++ b/libraries/Crypto/SHA3.cpp @@ -95,6 +95,40 @@ void SHA3_256::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t h clean(temp); } +/** + * \brief Copies the entire hash state from another object. + * + * \param other The other object to copy the state from. + * + * This function is intended for scenarios where the application needs to + * finalize the state to get an intermediate hash value, but must then + * continue hashing new data into the original state. + * + * In the following example, h1 will be the hash over data1 and h2 will + * be the hash over data1 concatenated with data2: + * + * \code + * // Hash the initial data. + * SHA3_256 hash1; + * hash1.update(data1, sizeof(data1)); + * + * // Copy the hash state and finalize to create h1. + * SHA3_256 hash2; + * hash2.copyFrom(hash1); + * hash2.finalize(h1, sizeof(h1)); + * + * // Continue adding data to the original unfinalized hash. + * hash1.update(data2, sizeof(data2)); + * + * // Get the final hash value h2. + * hash1.finalize(h2, sizeof(h2)); + * \endcode + */ +void SHA3_256::copyFrom(const SHA3_256 &other) +{ + core.copyFrom(other.core); +} + /** * \class SHA3_512 SHA3.h * \brief SHA3-512 hash algorithm. @@ -166,3 +200,37 @@ void SHA3_512::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t h finalize(hash, hashLen); clean(temp); } + +/** + * \brief Copies the entire hash state from another object. + * + * \param other The other object to copy the state from. + * + * This function is intended for scenarios where the application needs to + * finalize the state to get an intermediate hash value, but must then + * continue hashing new data into the original state. + * + * In the following example, h1 will be the hash over data1 and h2 will + * be the hash over data1 concatenated with data2: + * + * \code + * // Hash the initial data. + * SHA3_512 hash1; + * hash1.update(data1, sizeof(data1)); + * + * // Copy the hash state and finalize to create h1. + * SHA3_512 hash2; + * hash2.copyFrom(hash1); + * hash2.finalize(h1, sizeof(h1)); + * + * // Continue adding data to the original unfinalized hash. + * hash1.update(data2, sizeof(data2)); + * + * // Get the final hash value h2. + * hash1.finalize(h2, sizeof(h2)); + * \endcode + */ +void SHA3_512::copyFrom(const SHA3_512 &other) +{ + core.copyFrom(other.core); +} diff --git a/libraries/Crypto/SHA3.h b/libraries/Crypto/SHA3.h index 76bb031c..82114080 100644 --- a/libraries/Crypto/SHA3.h +++ b/libraries/Crypto/SHA3.h @@ -44,6 +44,8 @@ public: void resetHMAC(const void *key, size_t keyLen); void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen); + void copyFrom(const SHA3_256 &other); + private: KeccakCore core; }; @@ -66,6 +68,8 @@ public: void resetHMAC(const void *key, size_t keyLen); void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen); + void copyFrom(const SHA3_512 &other); + private: KeccakCore core; }; diff --git a/libraries/Crypto/SHA512.cpp b/libraries/Crypto/SHA512.cpp index 71cf0197..224789e9 100644 --- a/libraries/Crypto/SHA512.cpp +++ b/libraries/Crypto/SHA512.cpp @@ -158,6 +158,40 @@ void SHA512::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t has clean(temp); } +/** + * \brief Copies the entire hash state from another object. + * + * \param other The other object to copy the state from. + * + * This function is intended for scenarios where the application needs to + * finalize the state to get an intermediate hash value, but must then + * continue hashing new data into the original state. + * + * In the following example, h1 will be the hash over data1 and h2 will + * be the hash over data1 concatenated with data2: + * + * \code + * // Hash the initial data. + * SHA512 hash1; + * hash1.update(data1, sizeof(data1)); + * + * // Copy the hash state and finalize to create h1. + * SHA512 hash2; + * hash2.copyFrom(hash1); + * hash2.finalize(h1, sizeof(h1)); + * + * // Continue adding data to the original unfinalized hash. + * hash1.update(data2, sizeof(data2)); + * + * // Get the final hash value h2. + * hash1.finalize(h2, sizeof(h2)); + * \endcode + */ +void SHA512::copyFrom(const SHA512 &other) +{ + state = other.state; +} + /** * \brief Processes a single 1024-bit chunk with the core SHA-512 algorithm. * diff --git a/libraries/Crypto/SHA512.h b/libraries/Crypto/SHA512.h index d1a069f7..7bf0de35 100644 --- a/libraries/Crypto/SHA512.h +++ b/libraries/Crypto/SHA512.h @@ -45,6 +45,8 @@ public: void resetHMAC(const void *key, size_t keyLen); void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen); + void copyFrom(const SHA512 &other); + private: struct { uint64_t h[8]; diff --git a/libraries/CryptoLegacy/src/SHA1.cpp b/libraries/CryptoLegacy/src/SHA1.cpp index 9d212068..c8f94ab2 100644 --- a/libraries/CryptoLegacy/src/SHA1.cpp +++ b/libraries/CryptoLegacy/src/SHA1.cpp @@ -150,6 +150,40 @@ void SHA1::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashL clean(temp); } +/** + * \brief Copies the entire hash state from another object. + * + * \param other The other object to copy the state from. + * + * This function is intended for scenarios where the application needs to + * finalize the state to get an intermediate hash value, but must then + * continue hashing new data into the original state. + * + * In the following example, h1 will be the hash over data1 and h2 will + * be the hash over data1 concatenated with data2: + * + * \code + * // Hash the initial data. + * SHA1 hash1; + * hash1.update(data1, sizeof(data1)); + * + * // Copy the hash state and finalize to create h1. + * SHA1 hash2; + * hash2.copyFrom(hash1); + * hash2.finalize(h1, sizeof(h1)); + * + * // Continue adding data to the original unfinalized hash. + * hash1.update(data2, sizeof(data2)); + * + * // Get the final hash value h2. + * hash1.finalize(h2, sizeof(h2)); + * \endcode + */ +void SHA1::copyFrom(const SHA1 &other) +{ + state = other.state; +} + /** * \brief Processes a single 512-bit chunk with the core SHA-1 algorithm. * diff --git a/libraries/CryptoLegacy/src/SHA1.h b/libraries/CryptoLegacy/src/SHA1.h index 328ca39a..f4f9beac 100644 --- a/libraries/CryptoLegacy/src/SHA1.h +++ b/libraries/CryptoLegacy/src/SHA1.h @@ -43,6 +43,8 @@ public: void resetHMAC(const void *key, size_t keyLen); void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen); + void copyFrom(const SHA1 &other); + private: struct { uint32_t h[5];