diff --git a/README b/README index 619f1f37d5..14bc22b322 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 f555f08b23..94b71b812d 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 71a858cdf2..57768d254e 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, WC_BLAKE2B_DIGEST_SIZE); \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, WC_BLAKE2B_DIGEST_SIZE); byte plain[] = { // initialize input }; ret = wc_Blake2bUpdate(&b2b, plain, sizeof(plain)); - if( ret != 0) { - // error updating blake2b + if (ret != 0) { + // 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[WC_BLAKE2B_DIGEST_SIZE]; // initialize Blake2b structure with 64 byte digest - wc_InitBlake2b(&b2b, 64); + wc_InitBlake2b(&b2b, WC_BLAKE2B_DIGEST_SIZE); ... // call wc_Blake2bUpdate to add data to hash - ret = wc_Blake2bFinal(&b2b, hash, 64); - if( ret != 0) { - // error generating blake2b hash + ret = wc_Blake2bFinal(&b2b, hash, WC_BLAKE2B_DIGEST_SIZE); + if (ret != 0) { + // error generating blake2b hash } \endcode @@ -93,3 +93,326 @@ 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 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. + + \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[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)); + 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, WC_BLAKE2S_DIGEST_SIZE); + \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, WC_BLAKE2S_DIGEST_SIZE); + + 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[WC_BLAKE2S_DIGEST_SIZE]; + // initialize Blake2s structure with 32 byte digest + wc_InitBlake2s(&b2s, WC_BLAKE2S_DIGEST_SIZE); + ... // call wc_Blake2sUpdate to add data to hash + + ret = wc_Blake2sFinal(&b2s, hash, WC_BLAKE2S_DIGEST_SIZE); + 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 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 + + \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[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)); + 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); diff --git a/wolfcrypt/src/blake2b.c b/wolfcrypt/src/blake2b.c index 1f473cdd17..fcb87bd566 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] = { @@ -511,7 +517,107 @@ int wc_Blake2bFinal(Blake2b* b2b, byte* final, word32 requestSz) } -/* end CTaoCrypt API */ +int wc_Blake2bHmacInit(Blake2b * b2b, const byte * key, size_t key_len) +{ + byte x_key[BLAKE2B_BLOCKBYTES]; + int i; + int ret = 0; -#endif /* HAVE_BLAKE2 */ + 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]; + int i; + int ret = 0; + + if (key == NULL) + return BAD_FUNC_ARG; + + if (out_len != BLAKE2B_OUTBYTES) + return BUFFER_E; + + 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] ^= 0x5CU; + + if (ret == 0) + ret = wc_Blake2bFinal(b2b, out, 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 */ + +#endif /* HAVE_BLAKE2 */ diff --git a/wolfcrypt/src/blake2s.c b/wolfcrypt/src/blake2s.c index cf5c9f2ffb..ae77ad5192 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] = { @@ -505,7 +511,107 @@ int wc_Blake2sFinal(Blake2s* b2s, byte* final, word32 requestSz) } -/* end CTaoCrypt API */ +int wc_Blake2sHmacInit(Blake2s * b2s, const byte * key, size_t key_len) +{ + byte x_key[BLAKE2S_BLOCKBYTES]; + int i; + int ret = 0; -#endif /* HAVE_BLAKE2S */ + 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]; + int i; + int ret = 0; + + if (key == NULL) + return BAD_FUNC_ARG; + + if (out_len != BLAKE2S_OUTBYTES) + return BUFFER_E; + + 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] ^= 0x5CU; + + if (ret == 0) + ret = wc_Blake2sFinal(b2s, out, 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 */ + +#endif /* HAVE_BLAKE2S */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 54f8d72213..ad6fa25493 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,97 @@ 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; + Blake2b b2b; + + 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; + + 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 */ -#ifdef HAVE_BLAKE2S +#ifdef HAVE_BLAKE2S #define BLAKE2S_TESTS 3 @@ -4713,6 +4809,82 @@ 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; + Blake2s b2s; + + 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; + + 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 da66d9ba91..ff7710b5cd 100644 --- a/wolfssl/wolfcrypt/blake2.h +++ b/wolfssl/wolfcrypt/blake2.h @@ -88,6 +88,16 @@ 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); #endif #ifdef HAVE_BLAKE2S @@ -96,6 +106,16 @@ 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); #endif