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: */