diff --git a/configure.ac b/configure.ac index a58429691..09f2c592d 100644 --- a/configure.ac +++ b/configure.ac @@ -538,6 +538,18 @@ then fi +# HKDF +AC_ARG_ENABLE([hkdf], + [ --enable-hkdf Enable HKDF (HMAC-KDF) support (default: disabled)], + [ ENABLED_HKDF=$enableval ], + [ ENABLED_HKDF=no ] + ) +if test "$ENABLED_HKDF" = "yes" +then + AM_CFLAGS="$AM_CFLAGS -DHAVE_HKDF" +fi + + # DSA AC_ARG_ENABLE([dsa], [ --enable-dsa Enable DSA (default: disabled)], diff --git a/ctaocrypt/src/hmac.c b/ctaocrypt/src/hmac.c index 44de41e64..003eb6317 100644 --- a/ctaocrypt/src/hmac.c +++ b/ctaocrypt/src/hmac.c @@ -85,6 +85,7 @@ static int InitHmac(Hmac* hmac, int type) #endif default: + return BAD_FUNC_ARG; break; } @@ -92,18 +93,21 @@ static int InitHmac(Hmac* hmac, int type) } -void HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length) +int HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length) { byte* ip = (byte*) hmac->ipad; byte* op = (byte*) hmac->opad; word32 i, hmac_block_size = 0; + int ret; #ifdef HAVE_CAVIUM if (hmac->magic == CYASSL_HMAC_CAVIUM_MAGIC) return HmacCaviumSetKey(hmac, type, key, length); #endif - InitHmac(hmac, type); + ret = InitHmac(hmac, type); + if (ret != 0) + return ret; switch (hmac->macType) { #ifndef NO_MD5 @@ -203,7 +207,7 @@ void HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length) #endif default: - break; + return BAD_FUNC_ARG; } if (length < hmac_block_size) XMEMSET(ip + length, 0, hmac_block_size - length); @@ -212,6 +216,7 @@ void HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length) op[i] = ip[i] ^ OPAD; ip[i] ^= IPAD; } + return 0; } @@ -541,5 +546,121 @@ int CyaSSL_GetHmacMaxSize(void) return MAX_DIGEST_SIZE; } +#ifdef HAVE_HKDF + +#ifndef min + + static INLINE word32 min(word32 a, word32 b) + { + return a > b ? b : a; + } + +#endif /* min */ + + +static INLINE int GetHashSizeByType(int type) +{ + if (!(type == MD5 || type == SHA || type == SHA256 || type == SHA384 + || type == SHA512 || type == BLAKE2B_ID)) + return BAD_FUNC_ARG; + + switch (type) { + #ifndef NO_MD5 + case MD5: + return MD5_DIGEST_SIZE; + break; + #endif + + #ifndef NO_SHA + case SHA: + return SHA_DIGEST_SIZE; + break; + #endif + + #ifndef NO_SHA256 + case SHA256: + return SHA256_DIGEST_SIZE; + break; + #endif + + #ifdef CYASSL_SHA384 + case SHA384: + return SHA384_DIGEST_SIZE; + break; + #endif + + #ifdef CYASSL_SHA512 + case SHA512: + return SHA512_DIGEST_SIZE; + break; + #endif + + #ifdef HAVE_BLAKE2 + case BLAKE2B_ID: + return BLAKE2B_OUTBYTES; + break; + #endif + + default: + return BAD_FUNC_ARG; + break; + } +} + + +/* HMAC-KDF with hash type, optional salt and info, return 0 on success */ +int HKDF(int type, const byte* inKey, word32 inKeySz, + const byte* salt, word32 saltSz, + const byte* info, word32 infoSz, + byte* out, word32 outSz) +{ + Hmac myHmac; + byte tmp[MAX_DIGEST_SIZE]; /* localSalt helper and T */ + byte prk[MAX_DIGEST_SIZE]; + const byte* localSalt; /* either points to user input or tmp */ + int hashSz = GetHashSizeByType(type); + word32 outIdx = 0; + byte n = 0x1; + + if (hashSz < 0) + return BAD_FUNC_ARG; + + localSalt = salt; + if (localSalt == NULL) { + XMEMSET(tmp, 0, hashSz); + localSalt = tmp; + saltSz = hashSz; + } + + if (HmacSetKey(&myHmac, type, localSalt, saltSz) != 0) + return BAD_FUNC_ARG; + + HmacUpdate(&myHmac, inKey, inKeySz); + HmacFinal(&myHmac, prk); + + while (outIdx < outSz) { + int tmpSz = (n == 1) ? 0 : hashSz; + word32 left = outSz - outIdx; + + if (HmacSetKey(&myHmac, type, prk, hashSz) != 0) + return BAD_FUNC_ARG; + + HmacUpdate(&myHmac, tmp, tmpSz); + HmacUpdate(&myHmac, info, infoSz); + HmacUpdate(&myHmac, &n, 1); + HmacFinal(&myHmac, tmp); + + left = min(left, (word32)hashSz); + XMEMCPY(out+outIdx, tmp, left); + + outIdx += hashSz; + n++; + } + + return 0; +} + +#endif /* HAVE_HKDF */ + #endif /* NO_HMAC */ diff --git a/ctaocrypt/test/test.c b/ctaocrypt/test/test.c index cde9b2b77..b9002bd82 100644 --- a/ctaocrypt/test/test.c +++ b/ctaocrypt/test/test.c @@ -135,6 +135,7 @@ int hmac_sha256_test(void); int hmac_sha384_test(void); int hmac_sha512_test(void); int hmac_blake2b_test(void); +int hkdf_test(void); int arc4_test(void); int hc128_test(void); int rabbit_test(void); @@ -309,6 +310,13 @@ void ctaocrypt_test(void* args) printf( "HMAC-BLAKE2 test passed!\n"); #endif + #ifdef HAVE_HKDF + if ( (ret = hkdf_test()) != 0) + err_sys("HMAC-KDF test failed!\n", ret); + else + printf( "HMAC-KDF test passed!\n"); + #endif + #endif #ifdef HAVE_AESGCM @@ -3403,6 +3411,87 @@ int pwdbased_test(void) #endif /* NO_PWDBASED */ +#if defined(HAVE_HKDF) && (!defined(NO_SHA) || !defined(NO_SHA256)) + +int hkdf_test(void) +{ + int ret; + int L = 42; + byte okm1[42]; + byte ikm1[22] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b }; + byte salt1[13] ={ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c }; + byte info1[10] ={ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9 }; + byte res1[42] = { 0x0a, 0xc1, 0xaf, 0x70, 0x02, 0xb3, 0xd7, 0x61, + 0xd1, 0xe5, 0x52, 0x98, 0xda, 0x9d, 0x05, 0x06, + 0xb9, 0xae, 0x52, 0x05, 0x72, 0x20, 0xa3, 0x06, + 0xe0, 0x7b, 0x6b, 0x87, 0xe8, 0xdf, 0x21, 0xd0, + 0xea, 0x00, 0x03, 0x3d, 0xe0, 0x39, 0x84, 0xd3, + 0x49, 0x18 }; + byte res2[42] = { 0x08, 0x5a, 0x01, 0xea, 0x1b, 0x10, 0xf3, 0x69, + 0x33, 0x06, 0x8b, 0x56, 0xef, 0xa5, 0xad, 0x81, + 0xa4, 0xf1, 0x4b, 0x82, 0x2f, 0x5b, 0x09, 0x15, + 0x68, 0xa9, 0xcd, 0xd4, 0xf1, 0x55, 0xfd, 0xa2, + 0xc2, 0x2e, 0x42, 0x24, 0x78, 0xd3, 0x05, 0xf3, + 0xf8, 0x96 }; + byte res3[42] = { 0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, + 0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31, + 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e, + 0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d, + 0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a, + 0x96, 0xc8 }; + byte res4[42] = { 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, + 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a, + 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c, + 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf, + 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, + 0x58, 0x65 }; + + (void)res1; + (void)res2; + (void)res3; + (void)res4; + +#ifndef NO_SHA + ret = HKDF(SHA, ikm1, 22, NULL, 0, NULL, 0, okm1, L); + if (ret != 0) + return -2001; + + if (memcmp(okm1, res1, L) != 0) + return -2002; + + ret = HKDF(SHA, ikm1, 11, salt1, 13, info1, 10, okm1, L); + if (ret != 0) + return -2003; + + if (memcmp(okm1, res2, L) != 0) + return -2004; +#endif /* NO_SHA */ + +#ifndef NO_SHA256 + ret = HKDF(SHA256, ikm1, 22, NULL, 0, NULL, 0, okm1, L); + if (ret != 0) + return -2005; + + if (memcmp(okm1, res3, L) != 0) + return -2006; + + ret = HKDF(SHA256, ikm1, 22, salt1, 13, info1, 10, okm1, L); + if (ret != 0) + return -2007; + + if (memcmp(okm1, res4, L) != 0) + return -2007; +#endif /* NO_SHA256 */ + + return 0; +} + +#endif /* HAVE_HKDF */ + #ifdef HAVE_ECC diff --git a/cyassl/ctaocrypt/hmac.h b/cyassl/ctaocrypt/hmac.h index 47daf2794..4666ade19 100644 --- a/cyassl/ctaocrypt/hmac.h +++ b/cyassl/ctaocrypt/hmac.h @@ -151,7 +151,7 @@ typedef struct Hmac { /* does init */ -CYASSL_API void HmacSetKey(Hmac*, int type, const byte* key, word32 keySz); +CYASSL_API int HmacSetKey(Hmac*, int type, const byte* key, word32 keySz); CYASSL_API void HmacUpdate(Hmac*, const byte*, word32); CYASSL_API void HmacFinal(Hmac*, byte*); @@ -162,6 +162,16 @@ CYASSL_API void HmacFinal(Hmac*, byte*); CYASSL_API int CyaSSL_GetHmacMaxSize(void); + +#ifdef HAVE_HKDF + +CYASSL_API int HKDF(int type, const byte* inKey, word32 inKeySz, + const byte* salt, word32 saltSz, + const byte* info, word32 infoSz, + byte* out, word32 outSz); + +#endif /* HAVE_HKDF */ + #ifdef __cplusplus } /* extern "C" */ #endif