From c98857a47e55b8dc6e6bc2b883587a37f3c97a2d Mon Sep 17 00:00:00 2001 From: RyanC Date: Sun, 11 Nov 2012 15:00:19 -0800 Subject: [PATCH] add hkdf impl --- libtomcrypt.dsp | 5 ++ libtomcrypt_VS2005.vcproj | 22 +++++++ libtomcrypt_VS2008.vcproj | 22 +++++++ makefile | 3 +- makefile.icc | 3 +- makefile.msvc | 3 +- makefile.shared | 3 +- makefile.unix | 3 +- src/headers/tomcrypt.h | 1 + src/headers/tomcrypt_custom.h | 7 +++ src/headers/tomcrypt_hkdf.h | 26 ++++++++ src/misc/hkdf/hkdf.c | 113 ++++++++++++++++++++++++++++++++++ 12 files changed, 206 insertions(+), 5 deletions(-) create mode 100644 src/headers/tomcrypt_hkdf.h create mode 100644 src/misc/hkdf/hkdf.c diff --git a/libtomcrypt.dsp b/libtomcrypt.dsp index a6dbe7a..83b4af9 100644 --- a/libtomcrypt.dsp +++ b/libtomcrypt.dsp @@ -825,6 +825,11 @@ SOURCE=.\src\misc\error_to_string.c SOURCE=.\src\misc\zeromem.c # End Source File # End Group +# Begin Source File + +SOURCE=.\src\misc\hkdf\hkdf.c +# End Source File +# End Group # Begin Group "modes" # PROP Default_Filter "" diff --git a/libtomcrypt_VS2005.vcproj b/libtomcrypt_VS2005.vcproj index 6a93fa2..9eeb4f8 100644 --- a/libtomcrypt_VS2005.vcproj +++ b/libtomcrypt_VS2005.vcproj @@ -2954,6 +2954,28 @@ /> + + + + + + + + diff --git a/libtomcrypt_VS2008.vcproj b/libtomcrypt_VS2008.vcproj index a854068..3e1e851 100644 --- a/libtomcrypt_VS2008.vcproj +++ b/libtomcrypt_VS2008.vcproj @@ -2946,6 +2946,28 @@ /> + + + + + + + + diff --git a/makefile b/makefile index f2d54a9..e9ef4e6 100644 --- a/makefile +++ b/makefile @@ -156,7 +156,8 @@ src/misc/crypt/crypt_prng_is_valid.o src/misc/crypt/crypt_register_cipher.o \ src/misc/crypt/crypt_register_hash.o src/misc/crypt/crypt_register_prng.o \ src/misc/crypt/crypt_unregister_cipher.o src/misc/crypt/crypt_unregister_hash.o \ src/misc/crypt/crypt_unregister_prng.o src/misc/error_to_string.o src/misc/pkcs5/pkcs_5_1.o \ -src/misc/pkcs5/pkcs_5_2.o src/misc/zeromem.o src/modes/cbc/cbc_decrypt.o src/modes/cbc/cbc_done.o \ +src/misc/pkcs5/pkcs_5_2.o src/misc/zeromem.o src/misc/hkdf/hkdf.o \ +src/modes/cbc/cbc_decrypt.o src/modes/cbc/cbc_done.o \ src/modes/cbc/cbc_encrypt.o src/modes/cbc/cbc_getiv.o src/modes/cbc/cbc_setiv.o \ src/modes/cbc/cbc_start.o src/modes/cfb/cfb_decrypt.o src/modes/cfb/cfb_done.o \ src/modes/cfb/cfb_encrypt.o src/modes/cfb/cfb_getiv.o src/modes/cfb/cfb_setiv.o \ diff --git a/makefile.icc b/makefile.icc index 35be3d6..71bb112 100644 --- a/makefile.icc +++ b/makefile.icc @@ -141,7 +141,8 @@ src/misc/crypt/crypt_prng_is_valid.o src/misc/crypt/crypt_register_cipher.o \ src/misc/crypt/crypt_register_hash.o src/misc/crypt/crypt_register_prng.o \ src/misc/crypt/crypt_unregister_cipher.o src/misc/crypt/crypt_unregister_hash.o \ src/misc/crypt/crypt_unregister_prng.o src/misc/error_to_string.o src/misc/pkcs5/pkcs_5_1.o \ -src/misc/pkcs5/pkcs_5_2.o src/misc/zeromem.o src/modes/cbc/cbc_decrypt.o src/modes/cbc/cbc_done.o \ +src/misc/pkcs5/pkcs_5_2.o src/misc/zeromem.o src/misc/hkdf/hkdf.o \ +src/modes/cbc/cbc_decrypt.o src/modes/cbc/cbc_done.o \ src/modes/cbc/cbc_encrypt.o src/modes/cbc/cbc_getiv.o src/modes/cbc/cbc_setiv.o \ src/modes/cbc/cbc_start.o src/modes/cfb/cfb_decrypt.o src/modes/cfb/cfb_done.o \ src/modes/cfb/cfb_encrypt.o src/modes/cfb/cfb_getiv.o src/modes/cfb/cfb_setiv.o \ diff --git a/makefile.msvc b/makefile.msvc index 8b4892a..a0ffe6a 100644 --- a/makefile.msvc +++ b/makefile.msvc @@ -51,7 +51,8 @@ src/misc/crypt/crypt_prng_is_valid.obj src/misc/crypt/crypt_register_cipher.obj src/misc/crypt/crypt_register_hash.obj src/misc/crypt/crypt_register_prng.obj \ src/misc/crypt/crypt_unregister_cipher.obj src/misc/crypt/crypt_unregister_hash.obj \ src/misc/crypt/crypt_unregister_prng.obj src/misc/error_to_string.obj src/misc/pkcs5/pkcs_5_1.obj \ -src/misc/pkcs5/pkcs_5_2.obj src/misc/zeromem.obj src/modes/cbc/cbc_decrypt.obj src/modes/cbc/cbc_done.obj \ +src/misc/pkcs5/pkcs_5_2.obj src/misc/zeromem.obj src/misc/hkdf/hkdf.obj \ +src/modes/cbc/cbc_decrypt.obj src/modes/cbc/cbc_done.obj \ src/modes/cbc/cbc_encrypt.obj src/modes/cbc/cbc_getiv.obj src/modes/cbc/cbc_setiv.obj \ src/modes/cbc/cbc_start.obj src/modes/cfb/cfb_decrypt.obj src/modes/cfb/cfb_done.obj \ src/modes/cfb/cfb_encrypt.obj src/modes/cfb/cfb_getiv.obj src/modes/cfb/cfb_setiv.obj \ diff --git a/makefile.shared b/makefile.shared index 97012ee..2848c36 100644 --- a/makefile.shared +++ b/makefile.shared @@ -146,7 +146,8 @@ src/misc/crypt/crypt_prng_is_valid.o src/misc/crypt/crypt_register_cipher.o \ src/misc/crypt/crypt_register_hash.o src/misc/crypt/crypt_register_prng.o \ src/misc/crypt/crypt_unregister_cipher.o src/misc/crypt/crypt_unregister_hash.o \ src/misc/crypt/crypt_unregister_prng.o src/misc/error_to_string.o src/misc/pkcs5/pkcs_5_1.o \ -src/misc/pkcs5/pkcs_5_2.o src/misc/zeromem.o src/modes/cbc/cbc_decrypt.o src/modes/cbc/cbc_done.o \ +src/misc/pkcs5/pkcs_5_2.o src/misc/zeromem.o src/misc/hkdf/hkdf.o \ +src/modes/cbc/cbc_decrypt.o src/modes/cbc/cbc_done.o \ src/modes/cbc/cbc_encrypt.o src/modes/cbc/cbc_getiv.o src/modes/cbc/cbc_setiv.o \ src/modes/cbc/cbc_start.o src/modes/cfb/cfb_decrypt.o src/modes/cfb/cfb_done.o \ src/modes/cfb/cfb_encrypt.o src/modes/cfb/cfb_getiv.o src/modes/cfb/cfb_setiv.o \ diff --git a/makefile.unix b/makefile.unix index 792c1f3..53882e2 100644 --- a/makefile.unix +++ b/makefile.unix @@ -87,7 +87,8 @@ src/misc/crypt/crypt_prng_is_valid.o src/misc/crypt/crypt_register_cipher.o \ src/misc/crypt/crypt_register_hash.o src/misc/crypt/crypt_register_prng.o \ src/misc/crypt/crypt_unregister_cipher.o src/misc/crypt/crypt_unregister_hash.o \ src/misc/crypt/crypt_unregister_prng.o src/misc/error_to_string.o src/misc/pkcs5/pkcs_5_1.o \ -src/misc/pkcs5/pkcs_5_2.o src/misc/zeromem.o src/modes/cbc/cbc_decrypt.o src/modes/cbc/cbc_done.o \ +src/misc/pkcs5/pkcs_5_2.o src/misc/zeromem.o src/misc/hkdf/hkdf.o \ +src/modes/cbc/cbc_decrypt.o src/modes/cbc/cbc_done.o \ src/modes/cbc/cbc_encrypt.o src/modes/cbc/cbc_getiv.o src/modes/cbc/cbc_setiv.o \ src/modes/cbc/cbc_start.o src/modes/cfb/cfb_decrypt.o src/modes/cfb/cfb_done.o \ src/modes/cfb/cfb_encrypt.o src/modes/cfb/cfb_getiv.o src/modes/cfb/cfb_setiv.o \ diff --git a/src/headers/tomcrypt.h b/src/headers/tomcrypt.h index ad27eec..da5e4f9 100644 --- a/src/headers/tomcrypt.h +++ b/src/headers/tomcrypt.h @@ -74,6 +74,7 @@ enum { #include #include #include +#include #ifdef __cplusplus } diff --git a/src/headers/tomcrypt_custom.h b/src/headers/tomcrypt_custom.h index 97de5de..4f25ba7 100644 --- a/src/headers/tomcrypt_custom.h +++ b/src/headers/tomcrypt_custom.h @@ -360,6 +360,13 @@ #endif /* LTC_NO_PKCS */ +/* LTC_HKDF Key Derivation/Expansion stuff */ +#ifndef LTC_NO_HKDF + +#define LTC_HKDF + +#endif /* LTC_NO_HKDF */ + /* cleanup */ #ifdef LTC_MECC diff --git a/src/headers/tomcrypt_hkdf.h b/src/headers/tomcrypt_hkdf.h new file mode 100644 index 0000000..882fc83 --- /dev/null +++ b/src/headers/tomcrypt_hkdf.h @@ -0,0 +1,26 @@ +/* LTC_HKDF Header Info */ + +/* ===> LTC_HKDF -- RFC5869 HMAC-based Key Derivation Function <=== */ +#ifdef LTC_HKDF + +int hkdf_extract(int hash_idx, + const unsigned char *salt, unsigned long saltlen, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen); + +int hkdf_expand(int hash_idx, + const unsigned char *info, unsigned long infolen, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long outlen); + +int hkdf(int hash_idx, + const unsigned char *salt, unsigned long saltlen, + const unsigned char *info, unsigned long infolen, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long outlen); + +#endif /* LTC_HKDF */ + +/* $Source$ */ +/* $Revision$ */ +/* $Date$ */ diff --git a/src/misc/hkdf/hkdf.c b/src/misc/hkdf/hkdf.c new file mode 100644 index 0000000..b067663 --- /dev/null +++ b/src/misc/hkdf/hkdf.c @@ -0,0 +1,113 @@ +#include +#include +#include + +#include + +#ifndef MIN +#define MIN(a,b) ((a)<(b))?(a):(b) +#endif + +/* This is mostly just a wrapper around hmac_memory */ +int hkdf_extract(int hash_idx, const unsigned char *salt, unsigned long saltlen, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen) +{ + /* libtomcrypt chokes on a zero length HMAC key, so we need to check for + that. HMAC specifies that keys shorter than the hash's blocksize are + 0 padded to the block size. HKDF specifies that a NULL salt is to be + substituted with a salt comprised of hashLen 0 bytes. HMAC's padding + means that in either case the HMAC is actually using a blocksize long + zero filled key. Unless blocksize < hashLen (which wouldn't make any + sense), we can use a single 0 byte as the HMAC key and still generate + valid results for HKDF. */ + if (salt == NULL || saltlen == 0) { + return hmac_memory(hash_idx, "", 1, in, inlen, out, outlen); + } else { + return hmac_memory(hash_idx, salt, saltlen, in, inlen, out, outlen); + } +} + +int hkdf_expand(int hash_idx, const unsigned char *info, unsigned long infolen, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long outlen) +{ + const unsigned long hashsize = hash_descriptor[hash_idx].hashsize; + int err; + unsigned char N; + unsigned long Noutlen, outoff; + + unsigned char *T, *dat; + unsigned long Tlen, datlen; + + /* RFC5869 parameter restrictions */ + if (inlen < hashsize || outlen > hashsize * 255) + return CRYPT_INVALID_ARG; + if (info == NULL && infolen != 0) + return CRYPT_INVALID_ARG; + assert(out != NULL); + + Tlen = hashsize + infolen + 1; + T = XMALLOC(Tlen); /* Replace with static buffer? */ + if (T == NULL) { + return CRYPT_MEM; + } + XMEMCPY(T + hashsize, info, infolen); + + /* HMAC data T(1) doesn't include a previous hash value */ + dat = T + hashsize; + datlen = Tlen - hashsize; + + N = 0; + outoff = 0; /* offset in out to write to */ + while (1) { /* an exit condition breaks mid-loop */ + Noutlen = MIN(hashsize, outlen - outoff); + T[Tlen - 1] = ++N; + if ((err = hmac_memory(hash_idx, in, inlen, dat, datlen, + out + outoff, &Noutlen)) != CRYPT_OK) { + zeromem(T, Tlen); + XFREE(T); + return err; + } + outoff += Noutlen; + + if (outoff >= outlen) /* loop exit condition */ + break; + + /* All subsequent HMAC data T(N) DOES include the previous hash value */ + XMEMCPY(T, out + hashsize * (N-1), hashsize); + if (N == 1) { + dat = T; + datlen = Tlen; + } + } + zeromem(T, Tlen); + XFREE(T); + return CRYPT_OK; +} + +/* all in one step */ +int hkdf(int hash_idx, const unsigned char *salt, unsigned long saltlen, + const unsigned char *info, unsigned long infolen, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long outlen) +{ + unsigned long hashsize = hash_descriptor[hash_idx].hashsize; + int err; + unsigned char *extracted = XMALLOC(hashsize); /* replace with static buffer? */ + if (extracted == NULL) { + return CRYPT_MEM; + } + if ((err = hkdf_extract(hash_idx, salt, saltlen, in, inlen, extracted, &hashsize)) != 0) { + zeromem(extracted, hashsize); + XFREE(extracted); + return err; + } + err = hkdf_expand(hash_idx, extracted, hashsize, info, infolen, out, outlen); + zeromem(extracted, hashsize); + XFREE(extracted); + return err; +} + + +/* vim: set ts=2 sw=2 et ai si: */