Index: test.cpp
===================================================================
--- test.cpp	(revision 521)
+++ test.cpp	(working copy)
@@ -841,6 +841,7 @@
 	case 67: result = ValidateCCM(); break;
 	case 68: result = ValidateGCM(); break;
 	case 69: result = ValidateCMAC(); break;
+    case 70: result = ValidateHKDF(); break;
 	default: return false;
 	}
 
Index: validate.h
===================================================================
--- validate.h	(revision 521)
+++ validate.h	(working copy)
@@ -25,6 +25,7 @@
 
 bool ValidateCipherModes();
 bool ValidatePBKDF();
+bool ValidateHKDF();
 
 bool ValidateDES();
 bool ValidateIDEA();
Index: validat3.cpp
===================================================================
--- validat3.cpp	(revision 521)
+++ validat3.cpp	(working copy)
@@ -19,6 +19,7 @@
 
 #include "integer.h"
 #include "pwdbased.h"
+#include "hkdf.h"
 #include "filters.h"
 #include "hex.h"
 #include "files.h"
@@ -108,6 +109,7 @@
 	return HashModuleTest(md, testSet, sizeof(testSet)/sizeof(testSet[0]));
 }
 
+
 bool ValidateMD2()
 {
 	HashTestTuple testSet[] = 
@@ -589,3 +591,269 @@
 
 	return pass;
 }
+
+
+bool ValidateHKDF() 
+{
+    bool pass = true;
+    {
+        byte ikm[80] = { 
+            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+            0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+            0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21,
+            0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
+            0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+            0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
+            0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f };
+        byte salt[80] = { 
+            0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+            0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+            0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81,
+            0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d,
+            0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+            0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5,
+            0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf };
+        byte info[80] = { 
+            0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
+            0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
+            0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1,
+            0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd,
+            0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+            0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
+            0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };
+        byte okm[83] = { 
+            0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1, 0xc8, 0xe7,
+            0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34, 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e,
+            0xfa, 0xd8, 0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c, 0x59, 0x04,
+            0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72, 0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59,
+            0x0e, 0x09, 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8, 0x36, 0x77,
+            0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71, 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec,
+            0x3e, 0x87, 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f, 0x1d, 0x87, 0 };
+        int l = 82;
+        byte result[84];
+        cout << "\nHKDF<SHA256> #1 validation suite running...\n\n";
+        memset (result, 0, sizeof(result));
+        HMACKeyDerivationFunction<SHA256> hkdf;
+        hkdf.DeriveKey(result, l, ikm, sizeof(ikm), salt, 
+                       sizeof(salt), info, sizeof(info));
+        pass = pass && ( memcmp(result, okm, sizeof(okm)) == 0 );
+    }
+    {
+        byte ikm[22] = { 
+            0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+            0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b };
+        byte salt[13] = { 
+            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+            0x0a, 0x0b, 0x0c };
+        byte info[10] = { 
+            0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 };
+        byte okm[43] = { 
+            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, 0 };
+        int l = 42;
+        byte result[44];
+        cout << "\nHKDF<SHA256> #2 validation suite running...\n\n";
+        memset (result, 0, sizeof(result));
+
+        HMACKeyDerivationFunction<SHA256> hkdf;
+        hkdf.DeriveKey(result, l, ikm, sizeof(ikm), salt, 
+                       sizeof(salt), info, sizeof(info));
+        pass = pass && ( memcmp(result, okm, sizeof(okm)) == 0 );
+    }
+    {
+        byte ikm[22] = { 
+            0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+            0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b };
+        byte okm[43] = { 
+            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, 0 };
+        byte result[44];
+        int l = 42;
+        cout << "\nHKDF<SHA256> #3 validation suite running...\n\n";
+
+        memset (result, 0, sizeof(result));
+        HMACKeyDerivationFunction<SHA256> hkdf;
+        hkdf.DeriveKey(result, l, ikm, sizeof(ikm), NULL, 0, NULL, 0);
+        pass = pass && ( memcmp(result, okm, sizeof(okm)) == 0 );
+    }
+    {
+        byte ikm[11] = { 
+            0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+            0x0b };
+        byte salt[13] = { 
+            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+            0x0a, 0x0b, 0x0c };
+        byte info[10] = { 
+            0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 };
+        byte okm[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 result[84];
+        int l = 42;
+        cout << "\nHKDF<SHA1> #1 validation suite running...\n\n";
+
+        memset (result, 0, sizeof(result));
+
+        HMACKeyDerivationFunction<SHA1> hkdf;
+        hkdf.DeriveKey(result, l, ikm, sizeof(ikm), salt, 
+                       sizeof(salt), info, sizeof(info));
+
+        pass = pass && ( memcmp(result, okm, sizeof(okm)) == 0 );
+        pass = pass && ( memcmp(result + l, "\0", 2) == 0);
+    }
+    {
+        byte ikm[80] = { 
+            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+            0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+            0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21,
+            0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
+            0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+            0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
+            0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f };
+        byte salt[80] = { 
+            0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+            0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+            0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81,
+            0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d,
+            0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+            0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5,
+            0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf };
+        byte info[80] = { 
+            0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
+            0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
+            0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1,
+            0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd,
+            0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+            0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
+            0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };
+        byte okm[82] = { 
+            0x0b, 0xd7, 0x70, 0xa7, 0x4d, 0x11, 0x60, 0xf7, 0xc9, 0xf1,
+            0x2c, 0xd5, 0x91, 0x2a, 0x06, 0xeb, 0xff, 0x6a, 0xdc, 0xae, 0x89, 0x9d,
+            0x92, 0x19, 0x1f, 0xe4, 0x30, 0x56, 0x73, 0xba, 0x2f, 0xfe, 0x8f, 0xa3,
+            0xf1, 0xa4, 0xe5, 0xad, 0x79, 0xf3, 0xf3, 0x34, 0xb3, 0xb2, 0x02, 0xb2,
+            0x17, 0x3c, 0x48, 0x6e, 0xa3, 0x7c, 0xe3, 0xd3, 0x97, 0xed, 0x03, 0x4c,
+            0x7f, 0x9d, 0xfe, 0xb1, 0x5c, 0x5e, 0x92, 0x73, 0x36, 0xd0, 0x44, 0x1f,
+            0x4c, 0x43, 0x00, 0xe2, 0xcf, 0xf0, 0xd0, 0x90, 0x0b, 0x52, 0xd3, 0xb4 };
+        byte result[84];
+        int l = 82;
+        cout << "\nHKDF<SHA1> #2 validation suite running...\n\n";
+
+        memset (result, 0, sizeof(result));
+        HMACKeyDerivationFunction<SHA1> hkdf;
+        hkdf.DeriveKey(result, l, ikm, sizeof(ikm), salt, 
+                       sizeof(salt), info, sizeof(info));
+        pass = pass && ( memcmp(result, okm, sizeof(okm)) == 0 );
+        pass = pass && ( memcmp(result + l, "\0", 2) == 0);
+    }
+    {
+        byte ikm[22] = { 
+            0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+            0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b };
+        byte okm[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 result[44];
+        int l = 42;
+        cout << "\nHKDF<SHA1> #3 validation suite running...\n\n";
+
+        memset (result, 0, sizeof(result));
+        HMACKeyDerivationFunction<SHA1> hkdf;
+        hkdf.DeriveKey(result, l, ikm, sizeof(ikm), NULL, 0, NULL, 0);
+        pass = pass && ( memcmp(result, okm, sizeof(okm)) == 0 );
+        pass = pass && ( memcmp(result + l, "\0", 2) == 0);
+    }
+    {
+        byte ikm[80] = { 
+            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+            0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+            0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21,
+            0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
+            0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+            0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
+            0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f };
+        byte salt[80] = { 
+            0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+            0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+            0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81,
+            0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d,
+            0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+            0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5,
+            0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf };
+        byte info1[34] = { 
+            0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+            0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3,
+            0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+            0xd0, 0xd1 };
+        byte info2[46] = { 
+            0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
+            0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5,
+            0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1,
+            0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd,
+            0xfe, 0xff };
+        byte okm[82] = { 
+            0x0b, 0xd7, 0x70, 0xa7, 0x4d, 0x11, 0x60, 0xf7, 0xc9, 0xf1,
+            0x2c, 0xd5, 0x91, 0x2a, 0x06, 0xeb, 0xff, 0x6a, 0xdc, 0xae, 0x89, 0x9d,
+            0x92, 0x19, 0x1f, 0xe4, 0x30, 0x56, 0x73, 0xba, 0x2f, 0xfe, 0x8f, 0xa3,
+            0xf1, 0xa4, 0xe5, 0xad, 0x79, 0xf3, 0xf3, 0x34, 0xb3, 0xb2, 0x02, 0xb2,
+            0x17, 0x3c, 0x48, 0x6e, 0xa3, 0x7c, 0xe3, 0xd3, 0x97, 0xed, 0x03, 0x4c,
+            0x7f, 0x9d, 0xfe, 0xb1, 0x5c, 0x5e, 0x92, 0x73, 0x36, 0xd0, 0x44, 0x1f,
+            0x4c, 0x43, 0x00, 0xe2, 0xcf, 0xf0, 0xd0, 0x90, 0x0b, 0x52, 0xd3, 0xb4 };
+        byte result[84];
+        int l = 82;
+        cout << "\nHKDF<SHA1> #4 validation suite running...\n\n";
+
+        memset (result, 0, sizeof(result));
+        HMACKeyDerivationFunction<SHA1> hkdf;
+        hkdf.SetKey(ikm, sizeof(ikm), salt, sizeof(salt));
+        hkdf.Update(info1, sizeof(info1));
+        hkdf.Update(info2, sizeof(info2));
+        hkdf.Finish(result, l);
+        pass = pass && ( memcmp(result, okm, sizeof(okm)) == 0 );
+        pass = pass && ( memcmp(result + l, "\0", 2) == 0);
+    }
+    {
+        byte key[64] = {
+            0x8b, 0x56, 0x40, 0x97, 0x7a, 0x62, 0x5d, 0x7e, 
+            0x86, 0x8a, 0x48, 0x98, 0xd4, 0x17, 0x8d, 0x71, 
+            0xed, 0x3d, 0xe8, 0xe6, 0x1d, 0x3f, 0x76, 0xa4, 
+            0xbf, 0x20, 0xd6, 0x7a, 0xf2, 0x5a, 0xf7, 0xe9, 
+            0x70, 0x95, 0x2b, 0x48, 0xcb, 0x6e, 0x5c, 0x0a, 
+            0x9a, 0x3b, 0xac, 0x11, 0x97, 0xdf, 0x34, 0xc2, 
+            0xcb, 0xff, 0xc4, 0x4c, 0xa1, 0x28, 0x90, 0x7f, 
+            0xce, 0x7d, 0xa1, 0xa5, 0x7f, 0xb6, 0xcb, 0x27 };
+        byte info[64] = { 
+            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 
+            0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 
+            0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 
+            0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 
+            0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 };
+        byte expected[64] = { 
+            0x16, 0x4a, 0x96, 0x38, 0xda, 0x6e, 0x6d, 0x52, 
+            0x37, 0x5d, 0x04, 0xec, 0x31, 0x06, 0xd5, 0xd3, 
+            0x25, 0x42, 0xda, 0x62, 0x7a, 0xd1, 0x9e, 0xf2, 
+            0x63, 0xc1, 0x6c, 0xfa, 0xcb, 0x8d, 0x19, 0x23, 
+            0x6d, 0x25, 0x5f, 0x1e, 0x7b, 0x3a, 0xce, 0xd1, 
+            0x69, 0x5c, 0x81, 0xc6, 0x6e, 0xfb, 0x33, 0x40, 
+            0x28, 0x1e, 0x3a, 0xc5, 0x90, 0x7e, 0x25, 0x82, 
+            0xf1, 0xb3, 0x60, 0x59, 0xe2, 0xe9, 0x73, 0x38 };
+        byte cppHMAC[64];
+        cout << "\nHKDF<SHA512> #1 validation suite running...\n\n";
+        HMAC<SHA512> hmac;
+        hmac.SetKey(key, sizeof(key));
+        hmac.CalculateTruncatedDigest(cppHMAC, sizeof(cppHMAC), info, sizeof(info));
+        pass = pass && ( memcmp(cppHMAC, expected, sizeof(cppHMAC)) == 0 );
+    }
+    return pass;
+}
+
Index: hkdf.h
===================================================================
--- hkdf.h	(revision 0)
+++ hkdf.h	(revision 0)
@@ -0,0 +1,262 @@
+/**
+ *     Copyright (c), 2010, ClickLock.com
+ *
+ *     Permission is hereby granted, free of charge, to any person obtaining a copy
+ *     of this software and associated documentation files (the "Software"), to deal
+ *     in the Software without restriction, including without limitation the rights
+ *     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *     copies of the Software, and to permit persons to whom the Software is
+ *     furnished to do so, subject to the following conditions:
+ * 
+ *     The above copyright notice and this permission notice shall be included in
+ *     all copies or substantial portions of the Software.
+ *
+ *     @brief Hash-based KDF as defined in RFC 5869
+ *     @see http://www.rfc-editor.org/rfc/rfc5869.txt
+ *     @author Nils Durner, Travis Jensen
+ *
+ *     Portions of this file based on:
+ *         https://gnunet.org/svn/gnunet/src/util/crypto_hkdf.c
+ *     with the following information, copyright and license:
+ *
+ *     Copyright (c) 2010 Nils Durner
+ * 
+ */
+
+#ifndef CRYPTOPP_HKDF_H
+#define CRYPTOPP_HKDF_H
+
+#include <cstdlib>
+
+#include "cryptlib.h"
+#include "hmac.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/**
+ * Key deriver based on HKDF. For more details on the HKDF algorithm, see RFC 5869
+ * (http://tools.ietf.org/html/rfc5869).
+ *
+ * T is the hash transform to use for the extraction phase.
+ */
+template <class T> class HMACKeyDerivationFunction {
+public:
+    HMACKeyDerivationFunction();
+    virtual ~HMACKeyDerivationFunction();
+
+    size_t MaxDerivedKeyLength() const { T t; return 255 * t.DigestSize(); }
+    /**
+     * Sets the Source Key Material
+     */
+    virtual void SetKey(const byte *skm, size_t skmLen, 
+                        const byte *salt = NULL, size_t saltLen = 0);
+    /**
+     * Adds additional context information to the hash
+     */
+    virtual void Update(const byte *context, size_t contextLen);
+
+    /**
+     * Computes the actual derived key of the given length. keyLen must be less than
+     * or equal to HMACKeyDerivationFunction::MaxDerivedKeyLength()
+     */
+    virtual void Finish(byte *key, size_t keyLen);
+
+    /**
+     * Shortcut for deriving a key if you don't want to call Update and Finish
+     * yourself.
+     */
+    virtual void DeriveKey(byte *derived, size_t derivedLen, 
+                           const byte *skm, const int skmLen,
+                           const byte * salt = NULL, const int saltLen = 0,
+                           const byte * context = NULL, const int contextLen = 0);
+
+protected:
+    byte * sourceKey;
+    size_t sourceKeyLen;
+    byte * salt;
+    size_t saltLen;
+    byte * context;
+    int contextLen;
+    CryptoPP::HMAC<T> hmac;
+
+    /**
+     * (Re-)allocates a buffer, clears the memory (only the newly allocated part),
+     * performing error checking and throwing an exception if the allocation fails.  
+     * Passing 0 in for numBytes will free the buffer and return NULL.
+     */
+    byte * AllocBuffer(size_t new_size, byte * prevBuffer = NULL, size_t prev_size = 0);
+};
+
+template <class T>
+HMACKeyDerivationFunction<T>::HMACKeyDerivationFunction()
+:sourceKey(NULL), sourceKeyLen(0), salt(NULL), saltLen(0),
+    context(NULL), contextLen(0), hmac() {
+}
+
+
+template <class T>
+HMACKeyDerivationFunction<T>::~HMACKeyDerivationFunction() {
+    if (sourceKey) {
+        free(sourceKey);
+    }
+    if (salt) {
+        free(salt);
+    }
+    if (context) {
+        free(context);
+    }
+    sourceKeyLen = saltLen = contextLen = 0;
+    sourceKey = salt = context = NULL;
+}
+
+template <class T>
+byte * HMACKeyDerivationFunction<T>::AllocBuffer(size_t new_size, byte * prevBuffer, 
+                                                 size_t prev_size ) {
+    if (new_size <= 0 && prevBuffer == NULL) {
+        throw InvalidArgument("You must either specify a positive size of buffer to allocate or give a buffer to free.");
+    }
+
+    byte * buffer = NULL;
+    if (new_size > 0) {
+        buffer = (byte *) realloc(prevBuffer, new_size);
+        if (buffer == NULL) {
+            throw OS_Error(Exception::OTHER_ERROR, 
+                           "Unable to allocation buffer",
+                           "Alloc", 7);
+        } 
+
+        if (buffer && new_size > prev_size) {
+            ::memset(buffer + prev_size, 0, (new_size - prev_size));
+        }
+    }
+    else {
+        // realloc is supposed to free if new_size is zero, but in practice, it
+        // doesn't seem to work. There are some indications it might be platform
+        // specific. We'll explicitly free just to be sure.
+        free(prevBuffer);
+    }
+    return buffer;
+}
+
+
+template <class T>
+void HMACKeyDerivationFunction<T>::SetKey(const byte *skm, size_t skmLen, 
+                                          const byte *salt, size_t saltLen) {
+    if (skm == NULL || skmLen <= 0)  {
+        throw InvalidArgument("Source Key cannot be empty");
+    }
+    sourceKeyLen = skmLen;
+    sourceKey = this->AllocBuffer(skmLen, sourceKey);
+    ::memcpy(sourceKey, skm, sourceKeyLen);
+
+    if (salt != NULL && saltLen > 0) {
+        this->saltLen = saltLen;
+        this->salt = this->AllocBuffer(saltLen);
+        ::memcpy(this->salt, salt, saltLen);
+    }
+}
+
+template <class T>
+void HMACKeyDerivationFunction<T>::Update(const byte *ctx, size_t ctxLen) {
+    if (ctx == NULL || ctxLen <= 0)  {
+        throw InvalidArgument("Context and length cannot be empty or negative");
+    }
+    int curLen = contextLen;
+    int newLen = curLen + ctxLen;
+    context = this->AllocBuffer(newLen, context, curLen);
+    ::memcpy(context + curLen, ctx, ctxLen);
+    contextLen = newLen;
+}
+
+template <class T>
+void HMACKeyDerivationFunction<T>::DeriveKey(byte *derived, size_t derivedLen, 
+                       const byte *skm, const int skmLen,
+                       const byte * salt, const int saltLen,
+                       const byte * context, const int contextLen) {
+    this->SetKey(skm, skmLen, salt, saltLen);
+    if (context && contextLen > 0) {
+        this->Update(context, contextLen);
+    }
+    this->Finish(derived, derivedLen);
+}
+
+template <class T>
+void HMACKeyDerivationFunction<T>::Finish(byte *key, size_t keyLen) {
+    unsigned long i, t, d;
+    T hash;
+    HMAC<T> hmac;
+
+    unsigned int hash_len = hash.DigestSize();
+    byte prk[hash_len];
+    int ret;
+
+    if (keyLen == 0)
+        throw InvalidArgument("HKDF: hash function length can't be zero");
+
+    // FIXME: what is the check for?
+    if (keyLen > (2 ^ 32 * hash_len))
+        throw InvalidArgument("HDKF: output length is too big?");
+
+    ::memset (key, 0, keyLen);
+    ::memset (prk, 0, hash_len);
+
+    hmac.SetKey(salt, saltLen);
+    hmac.CalculateTruncatedDigest(prk, sizeof(prk), sourceKey, sourceKeyLen);
+
+    t = keyLen / hash_len;
+    d = keyLen % hash_len;
+    byte hc[hash_len];
+    int hmacLen = hmac.DigestSize();
+    ::memset (hc, hash_len, 0);
+
+    /* K(1) */
+    {
+        size_t plain_len = hash_len + contextLen + 1;
+        byte plain[plain_len];
+        byte *dst;
+
+        dst = plain + hash_len;
+
+        if (contextLen > 0) {
+            ::memcpy (dst, context, contextLen);
+        }
+        if (t > 0)
+        {
+            ::memset (plain + hash_len + contextLen, 1, 1);
+            hmac.SetKey(prk, hash_len);
+            hmac.CalculateDigest(hc, &plain[hash_len], contextLen + 1);
+            ::memcpy (key, hc, keyLen);
+            key += hash_len;
+        }
+
+        /* K(i+1) */
+        for (i = 1; i < t; i++)
+        {
+            ::memcpy (plain, key - hash_len, hash_len);
+            ::memset (plain + hash_len + contextLen, i + 1, 1);
+            hmac.SetKey(prk, hash_len);
+            hmac.CalculateDigest(hc, plain, plain_len);
+            ::memcpy (key, hc, hash_len);
+            key += hash_len;
+        }
+
+        /* K(t):d */
+        if (d > 0)
+        {
+            if (t > 0)
+                ::memcpy (plain, key - hash_len, hash_len);
+            ::memset (plain + hash_len + contextLen, i + 1, 1);
+            hmac.SetKey(prk, hash_len);
+            if (t > 0)
+                hmac.CalculateDigest(hc, plain, plain_len);
+            else
+                hmac.CalculateDigest(hc, plain + hash_len, plain_len - hash_len);
+
+            ::memcpy (key, hc, d);
+        }
+    }
+}
+
+NAMESPACE_END
+
+#endif
Index: validat1.cpp
===================================================================
--- validat1.cpp	(revision 521)
+++ validat1.cpp	(working copy)
@@ -64,6 +64,7 @@
 	pass=ValidateTTMAC() && pass;
 
 	pass=ValidatePBKDF() && pass;
+    pass=ValidateHKDF() && pass;
 
 	pass=ValidateDES() && pass;
 	pass=ValidateCipherModes() && pass;
