From 92b57d7e3400db9ffbab31a8bdb2cd26cce28e85 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Fri, 9 Jan 2026 18:19:06 -0500 Subject: [PATCH 1/5] Add HMAC-BLAKE2b and HMAC-BLAKE2s API functions --- wolfcrypt/src/blake2b.c | 62 ++++++++++++++++++- wolfcrypt/src/blake2s.c | 62 ++++++++++++++++++- wolfcrypt/test/test.c | 124 ++++++++++++++++++++++++++++++++++++- wolfssl/wolfcrypt/blake2.h | 6 ++ 4 files changed, 248 insertions(+), 6 deletions(-) diff --git a/wolfcrypt/src/blake2b.c b/wolfcrypt/src/blake2b.c index 1f473cdd17b..2295bb30726 100644 --- a/wolfcrypt/src/blake2b.c +++ b/wolfcrypt/src/blake2b.c @@ -511,7 +511,65 @@ int wc_Blake2bFinal(Blake2b* b2b, byte* final, word32 requestSz) } -/* end CTaoCrypt API */ +int wc_Blake2bHmac(const byte * in, size_t in_len, + const byte * key, size_t key_len, + byte * out, size_t out_len) +{ + byte x_key[BLAKE2B_BLOCKBYTES]; + byte i_hash[BLAKE2B_OUTBYTES]; + Blake2b state; + int i; + int ret; -#endif /* HAVE_BLAKE2 */ + if (in == NULL || key == NULL || out == NULL) + return BAD_FUNC_ARG; + + if (out_len != BLAKE2B_OUTBYTES) + return BUFFER_E; + + if (key_len > BLAKE2B_BLOCKBYTES) { + if ((ret = wc_InitBlake2b(&state, BLAKE2B_OUTBYTES)) != 0) + return ret; + if ((ret = wc_Blake2bUpdate(&state, key, (word32)key_len)) != 0) + return ret; + if ((ret = wc_Blake2bFinal(&state, x_key, 0)) != 0) + return ret; + } else { + XMEMCPY(x_key, key, key_len); + XMEMSET(x_key + key_len, 0, BLAKE2B_BLOCKBYTES - key_len); + } + for (i = 0; i < BLAKE2B_BLOCKBYTES; ++i) + x_key[i] ^= 0x36U; + + if ((ret = wc_InitBlake2b(&state, BLAKE2B_OUTBYTES)) != 0) + return ret; + if ((ret = wc_Blake2bUpdate(&state, x_key, BLAKE2B_BLOCKBYTES)) != 0) + return ret; + if ((ret = wc_Blake2bUpdate(&state, in, (word32)in_len)) != 0) + return ret; + if ((ret = wc_Blake2bFinal(&state, i_hash, 0)) != 0) + return ret; + + for (i = 0; i < BLAKE2B_BLOCKBYTES; ++i) + x_key[i] ^= (0x5CU ^ 0x36U); + + if ((ret = wc_InitBlake2b(&state, BLAKE2B_OUTBYTES)) != 0) + return ret; + if ((ret = wc_Blake2bUpdate(&state, x_key, BLAKE2B_BLOCKBYTES)) != 0) + return ret; + if ((ret = wc_Blake2bUpdate(&state, i_hash, BLAKE2B_OUTBYTES)) != 0) + return ret; + if ((ret = wc_Blake2bFinal(&state, i_hash, 0)) != 0) + return ret; + + XMEMCPY(out, i_hash, BLAKE2B_OUTBYTES); + XMEMSET(x_key, 0, BLAKE2B_BLOCKBYTES); + XMEMSET(i_hash, 0, BLAKE2B_OUTBYTES); + + return 0; +} + +/* end wolfCrypt API */ + +#endif /* HAVE_BLAKE2 */ diff --git a/wolfcrypt/src/blake2s.c b/wolfcrypt/src/blake2s.c index cf5c9f2ffb4..7dfd9b67ea3 100644 --- a/wolfcrypt/src/blake2s.c +++ b/wolfcrypt/src/blake2s.c @@ -505,7 +505,65 @@ int wc_Blake2sFinal(Blake2s* b2s, byte* final, word32 requestSz) } -/* end CTaoCrypt API */ +int wc_Blake2sHmac(const byte * in, size_t in_len, + const byte * key, size_t key_len, + byte * out, size_t out_len) +{ + byte x_key[BLAKE2S_BLOCKBYTES]; + byte i_hash[BLAKE2S_OUTBYTES]; + Blake2s state; + int i; + int ret; -#endif /* HAVE_BLAKE2S */ + if (in == NULL || key == NULL || out == NULL) + return BAD_FUNC_ARG; + + if (out_len != BLAKE2S_OUTBYTES) + return BUFFER_E; + + if (key_len > BLAKE2S_BLOCKBYTES) { + if ((ret = wc_InitBlake2s(&state, BLAKE2S_OUTBYTES)) != 0) + return ret; + if ((ret = wc_Blake2sUpdate(&state, key, (word32)key_len)) != 0) + return ret; + if ((ret = wc_Blake2sFinal(&state, x_key, 0)) != 0) + return ret; + } else { + XMEMCPY(x_key, key, key_len); + XMEMSET(x_key + key_len, 0, BLAKE2S_BLOCKBYTES - key_len); + } + for (i = 0; i < BLAKE2S_BLOCKBYTES; ++i) + x_key[i] ^= 0x36U; + + if ((ret = wc_InitBlake2s(&state, BLAKE2S_OUTBYTES)) != 0) + return ret; + if ((ret = wc_Blake2sUpdate(&state, x_key, BLAKE2S_BLOCKBYTES)) != 0) + return ret; + if ((ret = wc_Blake2sUpdate(&state, in, (word32)in_len)) != 0) + return ret; + if ((ret = wc_Blake2sFinal(&state, i_hash, 0)) != 0) + return ret; + + for (i = 0; i < BLAKE2S_BLOCKBYTES; ++i) + x_key[i] ^= (0x5CU ^ 0x36U); + + if ((ret = wc_InitBlake2s(&state, BLAKE2S_OUTBYTES)) != 0) + return ret; + if ((ret = wc_Blake2sUpdate(&state, x_key, BLAKE2S_BLOCKBYTES)) != 0) + return ret; + if ((ret = wc_Blake2sUpdate(&state, i_hash, BLAKE2S_OUTBYTES)) != 0) + return ret; + if ((ret = wc_Blake2sFinal(&state, i_hash, 0)) != 0) + return ret; + + XMEMCPY(out, i_hash, BLAKE2S_OUTBYTES); + XMEMSET(x_key, 0, BLAKE2S_BLOCKBYTES); + XMEMSET(i_hash, 0, BLAKE2S_OUTBYTES); + + return 0; +} + +/* end wolfCrypt API */ + +#endif /* HAVE_BLAKE2S */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 54f8d722130..efe70cfebd3 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -776,9 +776,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t scrypt_test(void); #endif #ifdef HAVE_BLAKE2 WOLFSSL_TEST_SUBROUTINE wc_test_ret_t blake2b_test(void); + WOLFSSL_TEST_SUBROUTINE wc_test_ret_t blake2b_hmac_test(void); #endif #ifdef HAVE_BLAKE2S WOLFSSL_TEST_SUBROUTINE wc_test_ret_t blake2s_test(void); + WOLFSSL_TEST_SUBROUTINE wc_test_ret_t blake2s_hmac_test(void); #endif #ifdef HAVE_LIBZ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t compress_test(void); @@ -2187,12 +2189,20 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ TEST_FAIL("BLAKE2b test failed!\n", ret); else TEST_PASS("BLAKE2b test passed!\n"); + if ( (ret = blake2b_hmac_test()) != 0) + TEST_FAIL("HMAC-BLAKE2b test failed!\n", ret); + else + TEST_PASS("HMAC-BLAKE2b test passed!\n"); #endif #ifdef HAVE_BLAKE2S if ( (ret = blake2s_test()) != 0) TEST_FAIL("BLAKE2s test failed!\n", ret); else TEST_PASS("BLAKE2s test passed!\n"); + if ( (ret = blake2s_hmac_test()) != 0) + TEST_FAIL("HMAC-BLAKE2s test failed!\n", ret); + else + TEST_PASS("HMAC-BLAKE2s test passed!\n"); #endif #ifndef NO_HMAC @@ -4581,7 +4591,6 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ripemd_test(void) #ifdef HAVE_BLAKE2 - #define BLAKE2B_TESTS 3 static const byte blake2b_vec[BLAKE2B_TESTS][BLAKE2B_OUTBYTES] = @@ -4651,10 +4660,71 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t blake2b_test(void) return 0; } + +WOLFSSL_TEST_SUBROUTINE wc_test_ret_t blake2b_hmac_test(void) +{ + static const byte key1[] = {0x41, 0x42, 0x43, 0x44}; /* ABCD */ + static const byte message1[] = {0x48, 0x65, 0x6c, 0x6c, 0x6f}; /* Hello */ + static const byte expected1[] = { + 0x46, 0x76, 0xbb, 0x0e, 0xf8, 0xa1, 0x56, 0x33, + 0xde, 0xdc, 0x44, 0xe3, 0x2b, 0xf3, 0xee, 0x5b, + 0x5f, 0x7f, 0x04, 0x00, 0x2c, 0xaa, 0xd4, 0x93, + 0xc6, 0xa6, 0xb4, 0xf3, 0x14, 0x8d, 0x6d, 0x9c, + 0x6a, 0x12, 0x02, 0x85, 0x66, 0xed, 0x9b, 0x5d, + 0x8d, 0x0e, 0x3d, 0xf4, 0x78, 0xee, 0x5a, 0xf6, + 0x2f, 0x97, 0xa5, 0x77, 0x88, 0x8c, 0xc4, 0x66, + 0x46, 0xb1, 0xba, 0x51, 0x29, 0x19, 0xd7, 0xaa, + }; + static const byte key2[] = { + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, + 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, + 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, 0x33 + }; /* 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123 */ + static const byte message2[] = { + 0x61, 0x62, 0x63, 0x64, 0x62, 0x63, 0x64, 0x65, 0x63, 0x64, 0x65, 0x66, + 0x64, 0x65, 0x66, 0x67, 0x65, 0x66, 0x67, 0x68, 0x66, 0x67, 0x68, 0x69, + 0x67, 0x68, 0x69, 0x6a, 0x68, 0x69, 0x6a, 0x6b, 0x69, 0x6a, 0x6b, 0x6c, + 0x6a, 0x6b, 0x6c, 0x6d, 0x6b, 0x6c, 0x6d, 0x6e, 0x6c, 0x6d, 0x6e, 0x6f, + 0x6d, 0x6e, 0x6f, 0x70, 0x6e, 0x6f, 0x70, 0x71 + }; /* abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq */ + static const byte expected2[] = { + 0x2a, 0xda, 0xf6, 0x94, 0x79, 0xce, 0xe2, 0xd2, + 0x5d, 0x89, 0x8b, 0xd7, 0x0d, 0xbc, 0x11, 0x1f, + 0x98, 0x99, 0xe0, 0x17, 0x7c, 0x5b, 0x8f, 0x94, + 0xf5, 0x95, 0xbc, 0x1b, 0xb1, 0x95, 0xe8, 0x60, + 0xbb, 0x29, 0xa4, 0xd9, 0x27, 0x2e, 0x00, 0xea, + 0xba, 0xc3, 0x3e, 0xe6, 0x9c, 0xc7, 0xd7, 0x8d, + 0x69, 0xc7, 0xb4, 0xf7, 0x31, 0x4a, 0xb1, 0xf0, + 0x3c, 0xed, 0x06, 0x49, 0x6f, 0x46, 0x99, 0xea, + }; + + byte out[BLAKE2B_OUTBYTES]; + + int ret; + + ret = wc_Blake2bHmac(message1, sizeof(message1), + key1, sizeof(key1), out, sizeof(out)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + if (XMEMCMP(out, expected1, sizeof(out)) != 0) + return WC_TEST_RET_ENC_NC; + + ret = wc_Blake2bHmac(message2, sizeof(message2), + key2, sizeof(key2), out, sizeof(out)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + if (XMEMCMP(out, expected2, sizeof(out)) != 0) + return WC_TEST_RET_ENC_NC; + + return 0; +} #endif /* HAVE_BLAKE2 */ -#ifdef HAVE_BLAKE2S +#ifdef HAVE_BLAKE2S #define BLAKE2S_TESTS 3 @@ -4713,6 +4783,56 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t blake2s_test(void) return 0; } + +WOLFSSL_TEST_SUBROUTINE wc_test_ret_t blake2s_hmac_test(void) +{ + static const byte key1[] = {0x41, 0x42, 0x43, 0x44}; /* ABCD */ + static const byte message1[] = {0x48, 0x65, 0x6c, 0x6c, 0x6f}; /* Hello */ + static const byte expected1[] = { + 0x96, 0xca, 0x1d, 0xaa, 0x9a, 0x33, 0x97, 0x3d, + 0xc5, 0x95, 0x3e, 0xce, 0x49, 0x93, 0x75, 0xc1, + 0x2a, 0x7c, 0x8f, 0x5b, 0xf0, 0x28, 0xef, 0xc3, + 0xfb, 0xc5, 0x97, 0xcd, 0xcc, 0x74, 0x44, 0x68, + }; + static const byte key2[] = { + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, + 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, 0x33 + }; /* 0123456789ABCDEF0123456789ABCDEF0123 */ + static const byte message2[] = { + 0x61, 0x62, 0x63, 0x64, 0x62, 0x63, 0x64, 0x65, 0x63, 0x64, 0x65, 0x66, + 0x64, 0x65, 0x66, 0x67, 0x65, 0x66, 0x67, 0x68, 0x66, 0x67, 0x68, 0x69, + 0x67, 0x68, 0x69, 0x6a, 0x68, 0x69, 0x6a, 0x6b, 0x69, 0x6a, 0x6b, 0x6c, + 0x6a, 0x6b, 0x6c, 0x6d, 0x6b, 0x6c, 0x6d, 0x6e, 0x6c, 0x6d, 0x6e, 0x6f, + 0x6d, 0x6e, 0x6f, 0x70, 0x6e, 0x6f, 0x70, 0x71 + }; /* abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq */ + static const byte expected2[] = { + 0xc4, 0x63, 0xdb, 0x28, 0x97, 0x60, 0x6a, 0xa7, + 0x1e, 0xe6, 0xcf, 0x93, 0x85, 0x3c, 0x90, 0x71, + 0xea, 0x76, 0x7f, 0x6a, 0xa7, 0x20, 0x80, 0x35, + 0xe1, 0x68, 0x95, 0xfe, 0x65, 0x65, 0x43, 0x76, + }; + + byte out[BLAKE2S_OUTBYTES]; + + int ret; + + ret = wc_Blake2sHmac(message1, sizeof(message1), + key1, sizeof(key1), out, sizeof(out)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + if (XMEMCMP(out, expected1, sizeof(out)) != 0) + return WC_TEST_RET_ENC_NC; + + ret = wc_Blake2sHmac(message2, sizeof(message2), + key2, sizeof(key2), out, sizeof(out)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + if (XMEMCMP(out, expected2, sizeof(out)) != 0) + return WC_TEST_RET_ENC_NC; + + return 0; +} #endif /* HAVE_BLAKE2S */ diff --git a/wolfssl/wolfcrypt/blake2.h b/wolfssl/wolfcrypt/blake2.h index da66d9ba917..cc6900de520 100644 --- a/wolfssl/wolfcrypt/blake2.h +++ b/wolfssl/wolfcrypt/blake2.h @@ -88,6 +88,9 @@ WOLFSSL_API int wc_InitBlake2b_WithKey(Blake2b* b2b, word32 digestSz, const byte *key, word32 keylen); WOLFSSL_API int wc_Blake2bUpdate(Blake2b* b2b, const byte* data, word32 sz); WOLFSSL_API int wc_Blake2bFinal(Blake2b* b2b, byte* final, word32 requestSz); +WOLFSSL_API int wc_Blake2bHmac(const byte * in, size_t in_len, + const byte * key, size_t key_len, + byte * out, size_t out_len); #endif #ifdef HAVE_BLAKE2S @@ -96,6 +99,9 @@ WOLFSSL_API int wc_InitBlake2s_WithKey(Blake2s* b2s, word32 digestSz, const byte *key, word32 keylen); WOLFSSL_API int wc_Blake2sUpdate(Blake2s* b2s, const byte* data, word32 sz); WOLFSSL_API int wc_Blake2sFinal(Blake2s* b2s, byte* final, word32 requestSz); +WOLFSSL_API int wc_Blake2sHmac(const byte * in, size_t in_len, + const byte * key, size_t key_len, + byte * out, size_t out_len); #endif From ee708dc45724d41c5cd28b3590d8312d4d39cc96 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Mon, 12 Jan 2026 08:56:17 -0500 Subject: [PATCH 2/5] Update README and doxygen for BLAKE2b/BLAKE2s --- README | 5 +- README.md | 4 +- doc/dox_comments/header_files/blake2.h | 173 ++++++++++++++++++++++++- 3 files changed, 171 insertions(+), 11 deletions(-) diff --git a/README b/README index 619f1f37d51..14bc22b322a 100644 --- a/README +++ b/README @@ -7,8 +7,9 @@ and feature set. It is commonly used in standard operating environments as well because of its royalty-free pricing and excellent cross platform support. wolfSSL supports industry standards up to the current TLS 1.3 and DTLS 1.3 levels, is up to 20 times smaller than OpenSSL, and offers progressive ciphers -such as ChaCha20, Curve25519, and Blake2b. User benchmarking and feedback -reports dramatically better performance when using wolfSSL over OpenSSL. +such as ChaCha20, Curve25519, BLAKE2b/BLAKE2s and Post-Quantum TLS 1.3 groups. +User benchmarking and feedback reports dramatically better performance when +using wolfSSL over OpenSSL. wolfSSL is powered by the wolfCrypt library. Two versions of the wolfCrypt cryptography library have been FIPS 140-2 validated (Certificate #2425 and diff --git a/README.md b/README.md index f555f08b23a..94b71b812dc 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ standard operating environments as well because of its royalty-free pricing and excellent cross platform support. wolfSSL supports industry standards up to the current [TLS 1.3](https://www.wolfssl.com/tls13) and DTLS 1.3, is up to 20 times smaller than OpenSSL, and offers progressive ciphers such as ChaCha20, -Curve25519, Blake2b and Post-Quantum TLS 1.3 groups. User benchmarking and -feedback reports dramatically better performance when using wolfSSL over +Curve25519, BLAKE2b/BLAKE2s and Post-Quantum TLS 1.3 groups. User benchmarking +and feedback reports dramatically better performance when using wolfSSL over OpenSSL. wolfSSL is powered by the wolfCrypt cryptography library. Two versions of diff --git a/doc/dox_comments/header_files/blake2.h b/doc/dox_comments/header_files/blake2.h index 71a858cdf2f..ecf389fa756 100644 --- a/doc/dox_comments/header_files/blake2.h +++ b/doc/dox_comments/header_files/blake2.h @@ -14,7 +14,7 @@ \code Blake2b b2b; // initialize Blake2b structure with 64 byte digest - wc_InitBlake2b(&b2b, 64); + wc_InitBlake2b(&b2b, BLAKE2B_OUTBYTES); \endcode \sa wc_Blake2bUpdate @@ -41,13 +41,13 @@ int wc_InitBlake2b(Blake2b* b2b, word32 digestSz); int ret; Blake2b b2b; // initialize Blake2b structure with 64 byte digest - wc_InitBlake2b(&b2b, 64); + wc_InitBlake2b(&b2b, BLAKE2B_OUTBYTES); byte plain[] = { // initialize input }; ret = wc_Blake2bUpdate(&b2b, plain, sizeof(plain)); if( ret != 0) { - // error updating blake2b + // error updating blake2b } \endcode @@ -78,14 +78,14 @@ int wc_Blake2bUpdate(Blake2b* b2b, const byte* data, word32 sz); \code int ret; Blake2b b2b; - byte hash[64]; + byte hash[BLAKE2B_OUTBYTES]; // initialize Blake2b structure with 64 byte digest - wc_InitBlake2b(&b2b, 64); + wc_InitBlake2b(&b2b, BLAKE2B_OUTBYTES); ... // call wc_Blake2bUpdate to add data to hash - ret = wc_Blake2bFinal(&b2b, hash, 64); + ret = wc_Blake2bFinal(&b2b, hash, BLAKE2B_OUTBYTES); if( ret != 0) { - // error generating blake2b hash + // error generating blake2b hash } \endcode @@ -93,3 +93,162 @@ int wc_Blake2bUpdate(Blake2b* b2b, const byte* data, word32 sz); \sa wc_Blake2bUpdate */ int wc_Blake2bFinal(Blake2b* b2b, byte* final, word32 requestSz); + +/*! + \ingroup BLAKE2 + + \brief This function computes the HMAC-BLAKE2b message authentication code + of the given input data using the given key. + + \return 0 Returned upon successfully computing the HMAC-BLAKE2b MAC. + + \param in pointer to the input data + \param in_len length of the input data + \param key pointer to the key + \param key_len length of the key + \param out output buffer to store computed MAC + \param out_len length of output buffer + + _Example_ + \code + int ret; + byte mac[BLAKE2B_OUTBYTES]; + byte data[] = {1, 2, 3}; + byte key[] = {4, 5, 6}; + ret = wc_Blake2bHmac(data, sizeof(data), key, sizeof(key), mac, sizeof(mac)); + if( ret != 0) { + // error generating HMAC-BLAKE2b + } + \endcode +*/ +int wc_Blake2bHmac(const byte * in, size_t in_len, + const byte * key, size_t key_len, + byte * out, size_t out_len); + + +/*! + \ingroup BLAKE2 + + \brief This function initializes a Blake2s structure for use with the + Blake2 hash function. + + \return 0 Returned upon successfully initializing the Blake2s structure and + setting the digest size. + + \param b2s pointer to the Blake2s structure to initialize + \param digestSz length of the blake 2 digest to implement + + _Example_ + \code + Blake2s b2s; + // initialize Blake2s structure with 32 byte digest + wc_InitBlake2s(&b2s, BLAKE2S_OUTBYTES); + \endcode + + \sa wc_Blake2sUpdate +*/ +int wc_InitBlake2s(Blake2s* b2s, word32 digestSz); + +/*! + \ingroup BLAKE2 + + \brief This function updates the Blake2s hash with the given input data. + This function should be called after wc_InitBlake2s, and repeated until + one is ready for the final hash: wc_Blake2sFinal. + + \return 0 Returned upon successfully update the Blake2s structure with + the given data + \return -1 Returned if there is a failure while compressing the input data + + \param b2s pointer to the Blake2s structure to update + \param data pointer to a buffer containing the data to append + \param sz length of the input data to append + + _Example_ + \code + int ret; + Blake2s b2s; + // initialize Blake2s structure with 32 byte digest + wc_InitBlake2s(&b2s, BLAKE2S_OUTBYTES); + + byte plain[] = { // initialize input }; + + ret = wc_Blake2sUpdate(&b2s, plain, sizeof(plain)); + if( ret != 0) { + // error updating blake2s + } + \endcode + + \sa wc_InitBlake2s + \sa wc_Blake2sFinal +*/ +int wc_Blake2sUpdate(Blake2s* b2s, const byte* data, word32 sz); + +/*! + \ingroup BLAKE2 + + \brief This function computes the Blake2s hash of the previously supplied + input data. The output hash will be of length requestSz, or, if + requestSz==0, the digestSz of the b2s structure. This function should be + called after wc_InitBlake2s and wc_Blake2sUpdate has been processed for + each piece of input data desired. + + \return 0 Returned upon successfully computing the Blake2s hash + \return -1 Returned if there is a failure while parsing the Blake2s hash + + \param b2s pointer to the Blake2s structure to update + \param final pointer to a buffer in which to store the blake2s hash. + Should be of length requestSz + \param requestSz length of the digest to compute. When this is zero, + b2s->digestSz will be used instead + + _Example_ + \code + int ret; + Blake2s b2s; + byte hash[BLAKE2S_OUTBYTES]; + // initialize Blake2s structure with 32 byte digest + wc_InitBlake2s(&b2s, BLAKE2S_OUTBYTES); + ... // call wc_Blake2sUpdate to add data to hash + + ret = wc_Blake2sFinal(&b2s, hash, BLAKE2S_OUTBYTES); + if( ret != 0) { + // error generating blake2s hash + } + \endcode + + \sa wc_InitBlake2s + \sa wc_Blake2sUpdate +*/ +int wc_Blake2sFinal(Blake2s* b2s, byte* final, word32 requestSz); + +/*! + \ingroup BLAKE2 + + \brief This function computes the HMAC-BLAKE2s message authentication code + of the given input data using the given key. + + \return 0 Returned upon successfully computing the HMAC-BLAKE2s MAC. + + \param in pointer to the input data + \param in_len length of the input data + \param key pointer to the key + \param key_len length of the key + \param out output buffer to store computed MAC + \param out_len length of output buffer + + _Example_ + \code + int ret; + byte mac[BLAKE2S_OUTBYTES]; + byte data[] = {1, 2, 3}; + byte key[] = {4, 5, 6}; + ret = wc_Blake2sHmac(data, sizeof(data), key, sizeof(key), mac, sizeof(mac)); + if( ret != 0) { + // error generating HMAC-BLAKE2s + } + \endcode +*/ +int wc_Blake2sHmac(const byte * in, size_t in_len, + const byte * key, size_t key_len, + byte * out, size_t out_len); From 2b3c02531cd9733170a2ee368c8507a2ffff78a7 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 14 Jan 2026 09:03:17 -0500 Subject: [PATCH 3/5] Use ForceZero to clean up HMAC-BLAKE2[bs] --- wolfcrypt/src/blake2b.c | 10 ++++++++-- wolfcrypt/src/blake2s.c | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/wolfcrypt/src/blake2b.c b/wolfcrypt/src/blake2b.c index 2295bb30726..1f24a7999d1 100644 --- a/wolfcrypt/src/blake2b.c +++ b/wolfcrypt/src/blake2b.c @@ -37,6 +37,12 @@ #include #include +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif static const word64 blake2b_IV[8] = { @@ -564,8 +570,8 @@ int wc_Blake2bHmac(const byte * in, size_t in_len, return ret; XMEMCPY(out, i_hash, BLAKE2B_OUTBYTES); - XMEMSET(x_key, 0, BLAKE2B_BLOCKBYTES); - XMEMSET(i_hash, 0, BLAKE2B_OUTBYTES); + ForceZero(x_key, BLAKE2B_BLOCKBYTES); + ForceZero(i_hash, BLAKE2B_OUTBYTES); return 0; } diff --git a/wolfcrypt/src/blake2s.c b/wolfcrypt/src/blake2s.c index 7dfd9b67ea3..2b312c5740b 100644 --- a/wolfcrypt/src/blake2s.c +++ b/wolfcrypt/src/blake2s.c @@ -37,6 +37,12 @@ #include #include +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif static const word32 blake2s_IV[8] = { @@ -558,8 +564,8 @@ int wc_Blake2sHmac(const byte * in, size_t in_len, return ret; XMEMCPY(out, i_hash, BLAKE2S_OUTBYTES); - XMEMSET(x_key, 0, BLAKE2S_BLOCKBYTES); - XMEMSET(i_hash, 0, BLAKE2S_OUTBYTES); + ForceZero(x_key, BLAKE2S_BLOCKBYTES); + ForceZero(i_hash, BLAKE2S_OUTBYTES); return 0; } From 74c79dab1eb384a30459f5e751dbc5ad78efe888 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 14 Jan 2026 09:04:41 -0500 Subject: [PATCH 4/5] Update constants in BLAKE2 doxygen documentation --- doc/dox_comments/header_files/blake2.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/doc/dox_comments/header_files/blake2.h b/doc/dox_comments/header_files/blake2.h index ecf389fa756..c0a1722d83a 100644 --- a/doc/dox_comments/header_files/blake2.h +++ b/doc/dox_comments/header_files/blake2.h @@ -14,7 +14,7 @@ \code Blake2b b2b; // initialize Blake2b structure with 64 byte digest - wc_InitBlake2b(&b2b, BLAKE2B_OUTBYTES); + wc_InitBlake2b(&b2b, WC_BLAKE2B_DIGEST_SIZE); \endcode \sa wc_Blake2bUpdate @@ -41,7 +41,7 @@ int wc_InitBlake2b(Blake2b* b2b, word32 digestSz); int ret; Blake2b b2b; // initialize Blake2b structure with 64 byte digest - wc_InitBlake2b(&b2b, BLAKE2B_OUTBYTES); + wc_InitBlake2b(&b2b, WC_BLAKE2B_DIGEST_SIZE); byte plain[] = { // initialize input }; @@ -78,12 +78,12 @@ int wc_Blake2bUpdate(Blake2b* b2b, const byte* data, word32 sz); \code int ret; Blake2b b2b; - byte hash[BLAKE2B_OUTBYTES]; + byte hash[WC_BLAKE2B_DIGEST_SIZE]; // initialize Blake2b structure with 64 byte digest - wc_InitBlake2b(&b2b, BLAKE2B_OUTBYTES); + wc_InitBlake2b(&b2b, WC_BLAKE2B_DIGEST_SIZE); ... // call wc_Blake2bUpdate to add data to hash - ret = wc_Blake2bFinal(&b2b, hash, BLAKE2B_OUTBYTES); + ret = wc_Blake2bFinal(&b2b, hash, WC_BLAKE2B_DIGEST_SIZE); if( ret != 0) { // error generating blake2b hash } @@ -112,7 +112,7 @@ int wc_Blake2bFinal(Blake2b* b2b, byte* final, word32 requestSz); _Example_ \code int ret; - byte mac[BLAKE2B_OUTBYTES]; + byte mac[WC_BLAKE2B_DIGEST_SIZE]; byte data[] = {1, 2, 3}; byte key[] = {4, 5, 6}; ret = wc_Blake2bHmac(data, sizeof(data), key, sizeof(key), mac, sizeof(mac)); @@ -142,7 +142,7 @@ int wc_Blake2bHmac(const byte * in, size_t in_len, \code Blake2s b2s; // initialize Blake2s structure with 32 byte digest - wc_InitBlake2s(&b2s, BLAKE2S_OUTBYTES); + wc_InitBlake2s(&b2s, WC_BLAKE2S_DIGEST_SIZE); \endcode \sa wc_Blake2sUpdate @@ -169,7 +169,7 @@ int wc_InitBlake2s(Blake2s* b2s, word32 digestSz); int ret; Blake2s b2s; // initialize Blake2s structure with 32 byte digest - wc_InitBlake2s(&b2s, BLAKE2S_OUTBYTES); + wc_InitBlake2s(&b2s, WC_BLAKE2S_DIGEST_SIZE); byte plain[] = { // initialize input }; @@ -206,12 +206,12 @@ int wc_Blake2sUpdate(Blake2s* b2s, const byte* data, word32 sz); \code int ret; Blake2s b2s; - byte hash[BLAKE2S_OUTBYTES]; + byte hash[WC_BLAKE2S_DIGEST_SIZE]; // initialize Blake2s structure with 32 byte digest - wc_InitBlake2s(&b2s, BLAKE2S_OUTBYTES); + wc_InitBlake2s(&b2s, WC_BLAKE2S_DIGEST_SIZE); ... // call wc_Blake2sUpdate to add data to hash - ret = wc_Blake2sFinal(&b2s, hash, BLAKE2S_OUTBYTES); + ret = wc_Blake2sFinal(&b2s, hash, WC_BLAKE2S_DIGEST_SIZE); if( ret != 0) { // error generating blake2s hash } @@ -240,7 +240,7 @@ int wc_Blake2sFinal(Blake2s* b2s, byte* final, word32 requestSz); _Example_ \code int ret; - byte mac[BLAKE2S_OUTBYTES]; + byte mac[WC_BLAKE2S_DIGEST_SIZE]; byte data[] = {1, 2, 3}; byte key[] = {4, 5, 6}; ret = wc_Blake2sHmac(data, sizeof(data), key, sizeof(key), mac, sizeof(mac)); From b432ee93a508632eb2e1299cd59dceb86a7974fa Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 14 Jan 2026 15:37:07 -0500 Subject: [PATCH 5/5] Add incremental API for HMAC-BLAKE2[bs] computation --- doc/dox_comments/header_files/blake2.h | 180 +++++++++++++++++++++++-- wolfcrypt/src/blake2b.c | 118 ++++++++++------ wolfcrypt/src/blake2s.c | 118 ++++++++++------ wolfcrypt/test/test.c | 56 +++++++- wolfssl/wolfcrypt/blake2.h | 14 ++ 5 files changed, 400 insertions(+), 86 deletions(-) diff --git a/doc/dox_comments/header_files/blake2.h b/doc/dox_comments/header_files/blake2.h index c0a1722d83a..57768d254e3 100644 --- a/doc/dox_comments/header_files/blake2.h +++ b/doc/dox_comments/header_files/blake2.h @@ -46,7 +46,7 @@ int wc_InitBlake2b(Blake2b* b2b, word32 digestSz); byte plain[] = { // initialize input }; ret = wc_Blake2bUpdate(&b2b, plain, sizeof(plain)); - if( ret != 0) { + if (ret != 0) { // error updating blake2b } \endcode @@ -84,7 +84,7 @@ int wc_Blake2bUpdate(Blake2b* b2b, const byte* data, word32 sz); ... // call wc_Blake2bUpdate to add data to hash ret = wc_Blake2bFinal(&b2b, hash, WC_BLAKE2B_DIGEST_SIZE); - if( ret != 0) { + if (ret != 0) { // error generating blake2b hash } \endcode @@ -97,8 +97,90 @@ int wc_Blake2bFinal(Blake2b* b2b, byte* final, word32 requestSz); /*! \ingroup BLAKE2 - \brief This function computes the HMAC-BLAKE2b message authentication code - of the given input data using the given key. + \brief Initialize an HMAC-BLAKE2b message authentication code computation. + + \return 0 Returned upon successfully initializing the HMAC-BLAKE2b MAC + computation. + + \param b2b Blake2b structure to be used for the MAC computation. + \param key pointer to the key + \param key_len length of the key + + _Example_ + \code + Blake2b b2b; + int ret; + byte key[] = {4, 5, 6}; + ret = wc_Blake2bHmacInit(&b2b, key); + if (ret != 0) { + // error generating HMAC-BLAKE2b + } + \endcode +*/ +int wc_Blake2bHmacInit(Blake2b * b2b, + const byte * key, size_t key_len); + +/*! + \ingroup BLAKE2 + + \brief Update an HMAC-BLAKE2b message authentication code computation with + additional input data. + + \return 0 Returned upon successfully updating the HMAC-BLAKE2b MAC + computation. + + \param b2b Blake2b structure to be used for the MAC computation. + \param in pointer to the input data + \param in_len length of the input data + + _Example_ + \code + Blake2b b2b; + int ret; + byte key[] = {4, 5, 6}; + byte data[] = {1, 2, 3}; + ret = wc_Blake2bHmacInit(&b2b, key, sizeof(key)); + ret = wc_Blake2bHmacUpdate(&b2b, data, sizeof(data)); + \endcode +*/ +int wc_Blake2bHmacUpdate(Blake2b * b2b, + const byte * in, size_t in_len); + +/*! + \ingroup BLAKE2 + + \brief Finalize an HMAC-BLAKE2b message authentication code computation. + + \return 0 Returned upon successfully finalizing the HMAC-BLAKE2b MAC + computation. + + \param b2b Blake2b structure to be used for the MAC computation. + \param key pointer to the key + \param key_len length of the key + \param out output buffer to store computed MAC + \param out_len length of output buffer + + _Example_ + \code + Blake2b b2b; + int ret; + byte key[] = {4, 5, 6}; + byte data[] = {1, 2, 3}; + byte mac[WC_BLAKE2B_DIGEST_SIZE]; + ret = wc_Blake2bHmacInit(&b2b, key, sizeof(key)); + ret = wc_Blake2bHmacUpdate(&b2b, data, sizeof(data)); + ret = wc_Blake2bHmacFinalize(&b2b, key, sizeof(key), mac, sizezof(mac)); + \endcode +*/ +int wc_Blake2bHmacFinal(Blake2b * b2b, + const byte * key, size_t key_len, + byte * out, size_t out_len); + +/*! + \ingroup BLAKE2 + + \brief Compute the HMAC-BLAKE2b message authentication code of the given + input data using the given key. \return 0 Returned upon successfully computing the HMAC-BLAKE2b MAC. @@ -116,7 +198,7 @@ int wc_Blake2bFinal(Blake2b* b2b, byte* final, word32 requestSz); byte data[] = {1, 2, 3}; byte key[] = {4, 5, 6}; ret = wc_Blake2bHmac(data, sizeof(data), key, sizeof(key), mac, sizeof(mac)); - if( ret != 0) { + if (ret != 0) { // error generating HMAC-BLAKE2b } \endcode @@ -174,7 +256,7 @@ int wc_InitBlake2s(Blake2s* b2s, word32 digestSz); byte plain[] = { // initialize input }; ret = wc_Blake2sUpdate(&b2s, plain, sizeof(plain)); - if( ret != 0) { + if (ret != 0) { // error updating blake2s } \endcode @@ -212,7 +294,7 @@ int wc_Blake2sUpdate(Blake2s* b2s, const byte* data, word32 sz); ... // call wc_Blake2sUpdate to add data to hash ret = wc_Blake2sFinal(&b2s, hash, WC_BLAKE2S_DIGEST_SIZE); - if( ret != 0) { + if (ret != 0) { // error generating blake2s hash } \endcode @@ -222,6 +304,88 @@ int wc_Blake2sUpdate(Blake2s* b2s, const byte* data, word32 sz); */ int wc_Blake2sFinal(Blake2s* b2s, byte* final, word32 requestSz); +/*! + \ingroup BLAKE2 + + \brief Initialize an HMAC-BLAKE2s message authentication code computation. + + \return 0 Returned upon successfully initializing the HMAC-BLAKE2s MAC + computation. + + \param b2s Blake2s structure to be used for the MAC computation. + \param key pointer to the key + \param key_len length of the key + + _Example_ + \code + Blake2s b2s; + int ret; + byte key[] = {4, 5, 6}; + ret = wc_Blake2sHmacInit(&b2s, key); + if (ret != 0) { + // error generating HMAC-BLAKE2s + } + \endcode +*/ +int wc_Blake2sHmacInit(Blake2s * b2s, + const byte * key, size_t key_len); + +/*! + \ingroup BLAKE2 + + \brief Update an HMAC-BLAKE2s message authentication code computation with + additional input data. + + \return 0 Returned upon successfully updating the HMAC-BLAKE2s MAC + computation. + + \param b2s Blake2s structure to be used for the MAC computation. + \param in pointer to the input data + \param in_len length of the input data + + _Example_ + \code + Blake2s b2s; + int ret; + byte key[] = {4, 5, 6}; + byte data[] = {1, 2, 3}; + ret = wc_Blake2sHmacInit(&b2s, key, sizeof(key)); + ret = wc_Blake2sHmacUpdate(&b2s, data, sizeof(data)); + \endcode +*/ +int wc_Blake2sHmacUpdate(Blake2s * b2s, + const byte * in, size_t in_len); + +/*! + \ingroup BLAKE2 + + \brief Finalize an HMAC-BLAKE2s message authentication code computation. + + \return 0 Returned upon successfully finalizing the HMAC-BLAKE2s MAC + computation. + + \param b2s Blake2s structure to be used for the MAC computation. + \param key pointer to the key + \param key_len length of the key + \param out output buffer to store computed MAC + \param out_len length of output buffer + + _Example_ + \code + Blake2s b2s; + int ret; + byte key[] = {4, 5, 6}; + byte data[] = {1, 2, 3}; + byte mac[WC_BLAKE2S_DIGEST_SIZE]; + ret = wc_Blake2sHmacInit(&b2s, key, sizeof(key)); + ret = wc_Blake2sHmacUpdate(&b2s, data, sizeof(data)); + ret = wc_Blake2sHmacFinalize(&b2s, key, sizeof(key), mac, sizezof(mac)); + \endcode +*/ +int wc_Blake2sHmacFinal(Blake2s * b2s, + const byte * key, size_t key_len, + byte * out, size_t out_len); + /*! \ingroup BLAKE2 @@ -244,7 +408,7 @@ int wc_Blake2sFinal(Blake2s* b2s, byte* final, word32 requestSz); byte data[] = {1, 2, 3}; byte key[] = {4, 5, 6}; ret = wc_Blake2sHmac(data, sizeof(data), key, sizeof(key), mac, sizeof(mac)); - if( ret != 0) { + if (ret != 0) { // error generating HMAC-BLAKE2s } \endcode diff --git a/wolfcrypt/src/blake2b.c b/wolfcrypt/src/blake2b.c index 1f24a7999d1..fcb87bd566e 100644 --- a/wolfcrypt/src/blake2b.c +++ b/wolfcrypt/src/blake2b.c @@ -517,63 +517,105 @@ int wc_Blake2bFinal(Blake2b* b2b, byte* final, word32 requestSz) } -int wc_Blake2bHmac(const byte * in, size_t in_len, - const byte * key, size_t key_len, +int wc_Blake2bHmacInit(Blake2b * b2b, const byte * key, size_t key_len) +{ + byte x_key[BLAKE2B_BLOCKBYTES]; + int i; + int ret = 0; + + if (key == NULL) + return BAD_FUNC_ARG; + + if (key_len > BLAKE2B_BLOCKBYTES) { + ret = wc_InitBlake2b(b2b, BLAKE2B_OUTBYTES); + if (ret == 0) + ret = wc_Blake2bUpdate(b2b, key, (word32)key_len); + if (ret == 0) + ret = wc_Blake2bFinal(b2b, x_key, 0); + } else { + XMEMCPY(x_key, key, key_len); + XMEMSET(x_key + key_len, 0, BLAKE2B_BLOCKBYTES - key_len); + } + + for (i = 0; i < BLAKE2B_BLOCKBYTES; ++i) + x_key[i] ^= 0x36U; + + if (ret == 0) + ret = wc_InitBlake2b(b2b, BLAKE2B_OUTBYTES); + if (ret == 0) + ret = wc_Blake2bUpdate(b2b, x_key, BLAKE2B_BLOCKBYTES); + + ForceZero(x_key, sizeof(x_key)); + + return ret; +} + +int wc_Blake2bHmacUpdate(Blake2b * b2b, const byte * in, size_t in_len) +{ + if (in == NULL) + return BAD_FUNC_ARG; + + return wc_Blake2bUpdate(b2b, in, (word32)in_len); +} + +int wc_Blake2bHmacFinal(Blake2b * b2b, const byte * key, size_t key_len, byte * out, size_t out_len) { byte x_key[BLAKE2B_BLOCKBYTES]; - byte i_hash[BLAKE2B_OUTBYTES]; - Blake2b state; int i; - int ret; + int ret = 0; - if (in == NULL || key == NULL || out == NULL) + if (key == NULL) return BAD_FUNC_ARG; if (out_len != BLAKE2B_OUTBYTES) return BUFFER_E; if (key_len > BLAKE2B_BLOCKBYTES) { - if ((ret = wc_InitBlake2b(&state, BLAKE2B_OUTBYTES)) != 0) - return ret; - if ((ret = wc_Blake2bUpdate(&state, key, (word32)key_len)) != 0) - return ret; - if ((ret = wc_Blake2bFinal(&state, x_key, 0)) != 0) - return ret; + ret = wc_InitBlake2b(b2b, BLAKE2B_OUTBYTES); + if (ret == 0) + ret = wc_Blake2bUpdate(b2b, key, (word32)key_len); + if (ret == 0) + ret = wc_Blake2bFinal(b2b, x_key, 0); } else { XMEMCPY(x_key, key, key_len); XMEMSET(x_key + key_len, 0, BLAKE2B_BLOCKBYTES - key_len); } for (i = 0; i < BLAKE2B_BLOCKBYTES; ++i) - x_key[i] ^= 0x36U; + x_key[i] ^= 0x5CU; - if ((ret = wc_InitBlake2b(&state, BLAKE2B_OUTBYTES)) != 0) - return ret; - if ((ret = wc_Blake2bUpdate(&state, x_key, BLAKE2B_BLOCKBYTES)) != 0) - return ret; - if ((ret = wc_Blake2bUpdate(&state, in, (word32)in_len)) != 0) - return ret; - if ((ret = wc_Blake2bFinal(&state, i_hash, 0)) != 0) - return ret; + if (ret == 0) + ret = wc_Blake2bFinal(b2b, out, 0); - for (i = 0; i < BLAKE2B_BLOCKBYTES; ++i) - x_key[i] ^= (0x5CU ^ 0x36U); - - if ((ret = wc_InitBlake2b(&state, BLAKE2B_OUTBYTES)) != 0) - return ret; - if ((ret = wc_Blake2bUpdate(&state, x_key, BLAKE2B_BLOCKBYTES)) != 0) - return ret; - if ((ret = wc_Blake2bUpdate(&state, i_hash, BLAKE2B_OUTBYTES)) != 0) - return ret; - if ((ret = wc_Blake2bFinal(&state, i_hash, 0)) != 0) - return ret; - - XMEMCPY(out, i_hash, BLAKE2B_OUTBYTES); - ForceZero(x_key, BLAKE2B_BLOCKBYTES); - ForceZero(i_hash, BLAKE2B_OUTBYTES); - - return 0; + if (ret == 0) + ret = wc_InitBlake2b(b2b, BLAKE2B_OUTBYTES); + if (ret == 0) + ret = wc_Blake2bUpdate(b2b, x_key, BLAKE2B_BLOCKBYTES); + if (ret == 0) + ret = wc_Blake2bUpdate(b2b, out, BLAKE2B_OUTBYTES); + if (ret == 0) + ret = wc_Blake2bFinal(b2b, out, 0); + + ForceZero(x_key, sizeof(x_key)); + + return ret; +} + +int wc_Blake2bHmac(const byte * in, size_t in_len, + const byte * key, size_t key_len, + byte * out, size_t out_len) +{ + Blake2b state; + int ret; + + ret = wc_Blake2bHmacInit(&state, key, key_len); + if (ret == 0) + ret = wc_Blake2bHmacUpdate(&state, in, in_len); + if (ret == 0) + ret = wc_Blake2bHmacFinal(&state, key, key_len, out, out_len); + + return ret; } /* end wolfCrypt API */ diff --git a/wolfcrypt/src/blake2s.c b/wolfcrypt/src/blake2s.c index 2b312c5740b..ae77ad5192a 100644 --- a/wolfcrypt/src/blake2s.c +++ b/wolfcrypt/src/blake2s.c @@ -511,63 +511,105 @@ int wc_Blake2sFinal(Blake2s* b2s, byte* final, word32 requestSz) } -int wc_Blake2sHmac(const byte * in, size_t in_len, - const byte * key, size_t key_len, +int wc_Blake2sHmacInit(Blake2s * b2s, const byte * key, size_t key_len) +{ + byte x_key[BLAKE2S_BLOCKBYTES]; + int i; + int ret = 0; + + if (key == NULL) + return BAD_FUNC_ARG; + + if (key_len > BLAKE2S_BLOCKBYTES) { + ret = wc_InitBlake2s(b2s, BLAKE2S_OUTBYTES); + if (ret == 0) + ret = wc_Blake2sUpdate(b2s, key, (word32)key_len); + if (ret == 0) + ret = wc_Blake2sFinal(b2s, x_key, 0); + } else { + XMEMCPY(x_key, key, key_len); + XMEMSET(x_key + key_len, 0, BLAKE2S_BLOCKBYTES - key_len); + } + + for (i = 0; i < BLAKE2S_BLOCKBYTES; ++i) + x_key[i] ^= 0x36U; + + if (ret == 0) + ret = wc_InitBlake2s(b2s, BLAKE2S_OUTBYTES); + if (ret == 0) + ret = wc_Blake2sUpdate(b2s, x_key, BLAKE2S_BLOCKBYTES); + + ForceZero(x_key, sizeof(x_key)); + + return ret; +} + +int wc_Blake2sHmacUpdate(Blake2s * b2s, const byte * in, size_t in_len) +{ + if (in == NULL) + return BAD_FUNC_ARG; + + return wc_Blake2sUpdate(b2s, in, (word32)in_len); +} + +int wc_Blake2sHmacFinal(Blake2s * b2s, const byte * key, size_t key_len, byte * out, size_t out_len) { byte x_key[BLAKE2S_BLOCKBYTES]; - byte i_hash[BLAKE2S_OUTBYTES]; - Blake2s state; int i; - int ret; + int ret = 0; - if (in == NULL || key == NULL || out == NULL) + if (key == NULL) return BAD_FUNC_ARG; if (out_len != BLAKE2S_OUTBYTES) return BUFFER_E; if (key_len > BLAKE2S_BLOCKBYTES) { - if ((ret = wc_InitBlake2s(&state, BLAKE2S_OUTBYTES)) != 0) - return ret; - if ((ret = wc_Blake2sUpdate(&state, key, (word32)key_len)) != 0) - return ret; - if ((ret = wc_Blake2sFinal(&state, x_key, 0)) != 0) - return ret; + ret = wc_InitBlake2s(b2s, BLAKE2S_OUTBYTES); + if (ret == 0) + ret = wc_Blake2sUpdate(b2s, key, (word32)key_len); + if (ret == 0) + ret = wc_Blake2sFinal(b2s, x_key, 0); } else { XMEMCPY(x_key, key, key_len); XMEMSET(x_key + key_len, 0, BLAKE2S_BLOCKBYTES - key_len); } for (i = 0; i < BLAKE2S_BLOCKBYTES; ++i) - x_key[i] ^= 0x36U; + x_key[i] ^= 0x5CU; - if ((ret = wc_InitBlake2s(&state, BLAKE2S_OUTBYTES)) != 0) - return ret; - if ((ret = wc_Blake2sUpdate(&state, x_key, BLAKE2S_BLOCKBYTES)) != 0) - return ret; - if ((ret = wc_Blake2sUpdate(&state, in, (word32)in_len)) != 0) - return ret; - if ((ret = wc_Blake2sFinal(&state, i_hash, 0)) != 0) - return ret; + if (ret == 0) + ret = wc_Blake2sFinal(b2s, out, 0); - for (i = 0; i < BLAKE2S_BLOCKBYTES; ++i) - x_key[i] ^= (0x5CU ^ 0x36U); - - if ((ret = wc_InitBlake2s(&state, BLAKE2S_OUTBYTES)) != 0) - return ret; - if ((ret = wc_Blake2sUpdate(&state, x_key, BLAKE2S_BLOCKBYTES)) != 0) - return ret; - if ((ret = wc_Blake2sUpdate(&state, i_hash, BLAKE2S_OUTBYTES)) != 0) - return ret; - if ((ret = wc_Blake2sFinal(&state, i_hash, 0)) != 0) - return ret; - - XMEMCPY(out, i_hash, BLAKE2S_OUTBYTES); - ForceZero(x_key, BLAKE2S_BLOCKBYTES); - ForceZero(i_hash, BLAKE2S_OUTBYTES); - - return 0; + if (ret == 0) + ret = wc_InitBlake2s(b2s, BLAKE2S_OUTBYTES); + if (ret == 0) + ret = wc_Blake2sUpdate(b2s, x_key, BLAKE2S_BLOCKBYTES); + if (ret == 0) + ret = wc_Blake2sUpdate(b2s, out, BLAKE2S_OUTBYTES); + if (ret == 0) + ret = wc_Blake2sFinal(b2s, out, 0); + + ForceZero(x_key, sizeof(x_key)); + + return ret; +} + +int wc_Blake2sHmac(const byte * in, size_t in_len, + const byte * key, size_t key_len, + byte * out, size_t out_len) +{ + Blake2s state; + int ret; + + ret = wc_Blake2sHmacInit(&state, key, key_len); + if (ret == 0) + ret = wc_Blake2sHmacUpdate(&state, in, in_len); + if (ret == 0) + ret = wc_Blake2sHmacFinal(&state, key, key_len, out, out_len); + + return ret; } /* end wolfCrypt API */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index efe70cfebd3..ad6fa25493d 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -4702,8 +4702,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t blake2b_hmac_test(void) }; byte out[BLAKE2B_OUTBYTES]; - int ret; + Blake2b b2b; ret = wc_Blake2bHmac(message1, sizeof(message1), key1, sizeof(key1), out, sizeof(out)); @@ -4719,6 +4719,32 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t blake2b_hmac_test(void) if (XMEMCMP(out, expected2, sizeof(out)) != 0) return WC_TEST_RET_ENC_NC; + ret = wc_Blake2bHmacInit(&b2b, key1, sizeof(key1)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_Blake2bHmacUpdate(&b2b, message1, sizeof(message1) / 2u); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_Blake2bHmacUpdate(&b2b, &message1[sizeof(message1) / 2u], sizeof(message1) - sizeof(message1) / 2u); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_Blake2bHmacFinal(&b2b, key1, sizeof(key1), out, sizeof(out)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_Blake2bHmacInit(&b2b, key2, sizeof(key2)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_Blake2bHmacUpdate(&b2b, message2, sizeof(message2) / 2u); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_Blake2bHmacUpdate(&b2b, &message2[sizeof(message2) / 2u], sizeof(message2) - sizeof(message2) / 2u); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_Blake2bHmacFinal(&b2b, key2, sizeof(key2), out, sizeof(out)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + return 0; } #endif /* HAVE_BLAKE2 */ @@ -4814,8 +4840,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t blake2s_hmac_test(void) }; byte out[BLAKE2S_OUTBYTES]; - int ret; + Blake2s b2s; ret = wc_Blake2sHmac(message1, sizeof(message1), key1, sizeof(key1), out, sizeof(out)); @@ -4831,6 +4857,32 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t blake2s_hmac_test(void) if (XMEMCMP(out, expected2, sizeof(out)) != 0) return WC_TEST_RET_ENC_NC; + ret = wc_Blake2sHmacInit(&b2s, key1, sizeof(key1)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_Blake2sHmacUpdate(&b2s, message1, sizeof(message1) / 2u); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_Blake2sHmacUpdate(&b2s, &message1[sizeof(message1) / 2u], sizeof(message1) - sizeof(message1) / 2u); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_Blake2sHmacFinal(&b2s, key1, sizeof(key1), out, sizeof(out)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_Blake2sHmacInit(&b2s, key2, sizeof(key2)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_Blake2sHmacUpdate(&b2s, message2, sizeof(message2) / 2u); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_Blake2sHmacUpdate(&b2s, &message2[sizeof(message2) / 2u], sizeof(message2) - sizeof(message2) / 2u); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_Blake2sHmacFinal(&b2s, key2, sizeof(key2), out, sizeof(out)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + return 0; } #endif /* HAVE_BLAKE2S */ diff --git a/wolfssl/wolfcrypt/blake2.h b/wolfssl/wolfcrypt/blake2.h index cc6900de520..ff7710b5cd4 100644 --- a/wolfssl/wolfcrypt/blake2.h +++ b/wolfssl/wolfcrypt/blake2.h @@ -88,6 +88,13 @@ WOLFSSL_API int wc_InitBlake2b_WithKey(Blake2b* b2b, word32 digestSz, const byte *key, word32 keylen); WOLFSSL_API int wc_Blake2bUpdate(Blake2b* b2b, const byte* data, word32 sz); WOLFSSL_API int wc_Blake2bFinal(Blake2b* b2b, byte* final, word32 requestSz); +WOLFSSL_API int wc_Blake2bHmacInit(Blake2b * b2b, + const byte * key, size_t key_len); +WOLFSSL_API int wc_Blake2bHmacUpdate(Blake2b * b2b, + const byte * in, size_t in_len); +WOLFSSL_API int wc_Blake2bHmacFinal(Blake2b * b2b, + const byte * key, size_t key_len, + byte * out, size_t out_len); WOLFSSL_API int wc_Blake2bHmac(const byte * in, size_t in_len, const byte * key, size_t key_len, byte * out, size_t out_len); @@ -99,6 +106,13 @@ WOLFSSL_API int wc_InitBlake2s_WithKey(Blake2s* b2s, word32 digestSz, const byte *key, word32 keylen); WOLFSSL_API int wc_Blake2sUpdate(Blake2s* b2s, const byte* data, word32 sz); WOLFSSL_API int wc_Blake2sFinal(Blake2s* b2s, byte* final, word32 requestSz); +WOLFSSL_API int wc_Blake2sHmacInit(Blake2s * b2s, + const byte * key, size_t key_len); +WOLFSSL_API int wc_Blake2sHmacUpdate(Blake2s * b2s, + const byte * in, size_t in_len); +WOLFSSL_API int wc_Blake2sHmacFinal(Blake2s * b2s, + const byte * key, size_t key_len, + byte * out, size_t out_len); WOLFSSL_API int wc_Blake2sHmac(const byte * in, size_t in_len, const byte * key, size_t key_len, byte * out, size_t out_len);