Hey Jeffrey,

looks good.
As you mind bringing up the point of KDFs, we /maybe /should consider
making some sort of "kdf.h", which will feature all KDFs we have in the
library (they're rather simple so we can put them into one header) and
we may also design a standard interface / abstract base class
"KeyDerivationFunction" so people can easily exchange P1363 with HKDF,
after the class has been designed. At the moment we're doing this stuff
via consistency in the definition, but having a base class for our
(three?) KDFs would be better I think...

Another point:
The first line of hkdf.h looks "wrong" / inconsistent with the rest of
the library (well some don't even have that line :( )
The standard formulation for this first line is:

//<filename> - written and placed in the public domain by <author>

BR

JPM

Am 03.07.2015 um 11:20 schrieb Jeffrey Walton:
> Whoops.... I did not perform the `git add`, so the main file was
> omitted...
>
> Its attached and below.
>
> // hkdf.h - written by Jeffrey Walton. Copyright assigned to Crypto++
> project
>
> #ifndef CRYPTOPP_HASH_KEY_DERIVATION_FUNCTION_H
> #define CRYPTOPP_HASH_KEY_DERIVATION_FUNCTION_H
>
> #include "cryptlib.h"
> #include "hmac.h"
> #include "hrtimer.h"
>
> #include <cstring>
>
> NAMESPACE_BEGIN(CryptoPP)
>
> //! abstract base class for key derivation function
> class KeyDerivationFunction
> {
> public:
>     virtual size_t MaxDerivedKeyLength() const =0;
>     virtual bool UsesContext() const =0;
>     //! derive key from secret
>     virtual unsigned int DeriveKey(byte *derived, size_t derivedLen,
> const byte *secret, size_t secretLen, const byte *salt, size_t
> saltLen, const byte* context=NULL, size_t contextLen=0) const =0;
>    
>     // If salt is missing, then use the NULL vector. The length
> depends on the Hash function.
>     static const byte s_NullVector[64];
> };
>
> const byte KeyDerivationFunction::s_NullVector[64] =
> {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
>
> //! HKDF from RFC 5869, T should be a HashTransformation class
> template <class T>
> class CRYPTOPP_DLL HKDF : public KeyDerivationFunction
> {
> public:
>     size_t MaxDerivedKeyLength() const {return
> static_cast<size_t>(T::DIGESTSIZE) * 255;}
>     bool UsesContext() const {return true;}
>     unsigned int DeriveKey(byte *derived, size_t derivedLen, const
> byte *secret, size_t secretLen, const byte *salt, size_t saltLen,
> const byte* context, size_t contextLen) const;
> };
>
> template <class T>
> unsigned int HKDF<T>::DeriveKey(byte *derived, size_t derivedLen,
> const byte *secret, size_t secretLen, const byte *salt, size_t
> saltLen, const byte* context, size_t contextLen) const
> {
>     static const size_t DIGEST_SIZE = static_cast<size_t>(T::DIGESTSIZE);
>     CRYPTOPP_COMPILE_ASSERT(DIGEST_SIZE <= COUNTOF(s_NullVector));
>    
>     assert(derived && derivedLen);
>     assert(secret && secretLen);
>     assert(derivedLen <= MaxDerivedKeyLength());
>
>     if(derivedLen > MaxDerivedKeyLength())
>         throw InvalidArgument("HKDF: derivedLen must be less than or
> equal to MaxDerivedKeyLength");
>
>     HMAC<T> hmac;
>     SecByteBlock prk(DIGEST_SIZE), buffer(DIGEST_SIZE);
>
>     // Extract
>     const byte* key = (salt ? salt : s_NullVector);
>     const size_t klen = (salt ? saltLen : DIGEST_SIZE);
>
>     hmac.SetKey(key, klen);
>     hmac.CalculateDigest(prk, secret, secretLen);
>
>     // Expand
>     hmac.SetKey(prk.data(), prk.size());
>     byte block = 0;
>     while (derivedLen > 0)
>     {
>         if(block++) {hmac.Update(buffer, buffer.size());}
>         if(context) {hmac.Update(context, contextLen);}
>         hmac.CalculateDigest(buffer, &block, 1);
>
>         size_t segmentLen = STDMIN(derivedLen, DIGEST_SIZE);
>         std::memcpy(derived, buffer, segmentLen);
>
>         derived += segmentLen;
>         derivedLen -= segmentLen;
>     }
>
>     return 1;
> }
>
> NAMESPACE_END
>
> #endif // CRYPTOPP_HASH_KEY_DERIVATION_FUNCTION_H
>
> On Friday, July 3, 2015 at 5:17:15 AM UTC-4, Jeffrey Walton wrote:
>
>     I'd like to add the following to the library. It provides Krawczyk
>     and Eronen's HKDF.
>
>     The patch has a few more changes, like the addition of COUNTOF to
>     validat3.cpp, but don't focus on them.
>
>     Any comments or objections?
>
>     **********
>     diff --git a/config.h b/config.h
>     index d853b33..1667598 100644
>     --- a/config.h
>     +++ b/config.h
>     @@ -96,6 +96,12 @@ typedef unsigned char byte;        // put in
>     global namespace to avoid ambiguity with
>      
>      #define CRYPTOPP_UNUSED(x) ((void)x)        // cast to void.
>     Portable way to suppress unused variable
>      
>     +#if defined(_MSC_VER) && (_MSC_VER >= 1400)        // VS2005
>     added _countof macro
>     +# defined COUNTOF(x) _countof(x)
>     +#else
>     +# define COUNTOF(x) (sizeof(x)/sizeof(x[0]))
>     +#endif
>     +
>      NAMESPACE_BEGIN(CryptoPP)
>      
>      typedef unsigned short word16;
>     diff --git a/validat1.cpp b/validat1.cpp
>     index 7c4ca2f..4287a9f 100644
>     --- a/validat1.cpp
>     +++ b/validat1.cpp
>     @@ -67,6 +67,7 @@ bool ValidateAll(bool thorough)
>          pass=ValidateTTMAC() && pass;
>      
>          pass=ValidatePBKDF() && pass;
>     +    pass=ValidateHKDF() && pass;
>      
>          pass=ValidateDES() && pass;
>          pass=ValidateCipherModes() && pass;
>     diff --git a/validat3.cpp b/validat3.cpp
>     index 07b6334..ff49f51 100644
>     --- a/validat3.cpp
>     +++ b/validat3.cpp
>     @@ -16,6 +16,7 @@
>      
>      #include "hmac.h"
>      #include "ttmac.h"
>     +#include "hkdf.h"
>      
>      #include "integer.h"
>      #include "pwdbased.h"
>     @@ -568,25 +568,102 @@ bool ValidatePBKDF()
>              {3, 1000, "007100750065006500670000", "263216FCC2FAB31C",
>     "5EC4C7A80DF652294C3925B6489A7AB857C83476"}
>          };
>      
>     -    PKCS12_PBKDF<SHA1> pbkdf;
>     +    PKCS12_PBKDF<SHA1> pbkdf1;
>      
>          cout << "\nPKCS #12 PBKDF validation suite running...\n\n";
>     -    pass = TestPBKDF(pbkdf, testSet,
>     sizeof(testSet)/sizeof(testSet[0])) && pass;
>     -    }
>     +    pass = TestPBKDF(pbkdf1, testSet1, COUNTOF(testSet1)) && pass;
>      
>     -    {
>          // from draft-ietf-smime-password-03.txt, at
>     http://www.imc.org/draft-ietf-smime-password
>     <http://www.imc.org/draft-ietf-smime-password>
>     -    PBKDF_TestTuple testSet[] =
>     +    static const PBKDF_TestTuple testSet2[] =
>          {
>              {0, 5, "70617373776f7264", "1234567878563412",
>     "D1DAA78615F287E6"},
>              {0, 500,
>     
> "416C6C206E2D656E746974696573206D75737420636F6D6D756E69636174652077697468206F74686572206E2d656E74697469657320766961206E2D3120656E746974656568656568656573",
>     "1234567878563412","6A8970BF68C92CAEA84A8DF28510858607126380CC47AB2D"}
>          };
>      
>     -    PKCS5_PBKDF2_HMAC<SHA1> pbkdf;
>     +    PKCS5_PBKDF2_HMAC<SHA1> pbkdf2;
>      
>          cout << "\nPKCS #5 PBKDF2 validation suite running...\n\n";
>     -    pass = TestPBKDF(pbkdf, testSet,
>     sizeof(testSet)/sizeof(testSet[0])) && pass;
>     +    pass = TestPBKDF(pbkdf2, testSet2, COUNTOF(testSet2)) && pass;
>     +
>     +    return pass;
>     +}
>     +
>     +struct HKDF_TestTuple
>     +{
>     +    const char *hexSecret, *hexSalt, *hexContext, *hexDerivedKey;
>     +    size_t len;
>     +};
>     +
>     +bool TestHKDF(KeyDerivationFunction &kdf, const HKDF_TestTuple
>     *testSet, unsigned int testSetSize)
>     +{
>     +    bool pass = true;
>     +    static const string EMPTY = "";
>     +
>     +    for (unsigned int i=0; i<testSetSize; i++)
>     +    {
>     +        const HKDF_TestTuple &tuple = testSet[i];
>     +
>     +        string secret, context, salt, derivedKey;
>     +        StringSource(tuple.hexSecret, true, new HexDecoder(new
>     StringSink(secret)));
>     +        StringSource(tuple.hexSalt ? tuple.hexSalt : EMPTY, true,
>     new HexDecoder(new StringSink(salt)));
>     +        StringSource(tuple.hexContext ? tuple.hexContext : EMPTY,
>     true, new HexDecoder(new StringSink(context)));
>     +        StringSource(tuple.hexDerivedKey, true, new
>     HexDecoder(new StringSink(derivedKey)));
>     +
>     +        SecByteBlock derived(derivedKey.size());
>     +        assert(derived.size() == tuple.len);
>     +
>     +        kdf.DeriveKey(derived, derived.size(), (byte
>     *)secret.data(), secret.size(), (byte *)salt.data(), salt.size(),
>     (byte*)context.data(), context.size());
>     +        bool fail = !VerifyBufsEqual(derived,
>     reinterpret_cast<const unsigned char*>(derivedKey.data()),
>     derived.size());
>     +        pass = pass && !fail;
>     +
>     +        HexEncoder enc(new FileSink(cout));
>     +        cout << (fail ? "FAILED   " : "passed   ");
>     +        cout << " " << tuple.hexSecret << " " << (tuple.hexSalt ?
>     tuple.hexSalt : "<NO SALT>");
>     +        cout << " " << (tuple.hexContext ? tuple.hexContext :
>     "<NO CTX>") << " ";
>     +        enc.Put(derived, derived.size());
>     +        cout << endl;
>          }
>      
>          return pass;
>      }
>     +
>     +bool ValidateHKDF()
>     +{
>     +    bool pass = true;
>     +
>     +    // SHA-1 from RFC 5869, Appendix A,
>     https://tools.ietf.org/html/rfc5869
>     <https://tools.ietf.org/html/rfc5869>
>     +    static const HKDF_TestTuple testSet1[] =
>     +    {
>     +        // Test Case #4
>     +        {"0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c",
>     "f0f1f2f3f4f5f6f7f8f9", "085a01ea1b10f36933068b56efa5ad81
>     a4f14b822f5b091568a9cdd4f155fda2 c22e422478d305f3f896", 42},
>     +        // Test Case #5
>     +        {"000102030405060708090a0b0c0d0e0f
>     101112131415161718191a1b1c1d1e1f 202122232425262728292a2b2c2d2e2f
>     303132333435363738393a3b3c3d3e3f
>     404142434445464748494a4b4c4d4e4f",
>     "606162636465666768696a6b6c6d6e6f 707172737475767778797a7b7c7d7e7f
>     808182838485868788898a8b8c8d8e8f 909192939495969798999a9b9c9d9e9f
>     a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
>     "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
>     d0d1d2d3d4d5d6d7d8d9dadbdcdddedf e0e1e2e3e4e5e6e7e8e9eaebecedeeef
>     f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
>     "0bd770a74d1160f7c9f12cd5912a06eb ff6adcae899d92191fe4305673ba2ffe
>     8fa3f1a4e5ad79f3f334b3b202b2173c 486ea37ce3d397ed034c7f9dfeb15c5e
>     927336d0441f4c4300e2cff0d0900b52 d3b4", 82},
>     +        // Test Case #6
>     +        {"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", NULL,
>     NULL, "0ac1af7002b3d761d1e55298da9d0506
>     b9ae52057220a306e07b6b87e8df21d0 ea00033de03984d34918", 42}
>     +    };
>     +
>     +    HKDF<SHA1> kdf1;
>     +
>     +    cout << "\nRFC 5869 HKDF(SHA-1) validation suite running...\n\n";
>     +    pass = TestHKDF(kdf1, testSet1, COUNTOF(testSet1)) && pass;
>     +
>     +
>     +    // SHA-256 from RFC 5869, Appendix A,
>     https://tools.ietf.org/html/rfc5869
>     <https://tools.ietf.org/html/rfc5869>
>     +    static const HKDF_TestTuple testSet2[] =
>     +    {
>     +        // Test Case #1
>     +        {"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
>     "000102030405060708090a0b0c", "f0f1f2f3f4f5f6f7f8f9",
>     "3cb25f25faacd57a90434f64d0362f2a 2d2d0a90cf1a5a4c5db02d56ecc4c5bf
>     34007208d5b887185865", 42},
>     +        // Test Case #2
>     +        {"000102030405060708090a0b0c0d0e0f
>     101112131415161718191a1b1c1d1e1f 202122232425262728292a2b2c2d2e2f
>     303132333435363738393a3b3c3d3e3f
>     404142434445464748494a4b4c4d4e4f",
>     "606162636465666768696a6b6c6d6e6f 707172737475767778797a7b7c7d7e7f
>     808182838485868788898a8b8c8d8e8f 909192939495969798999a9b9c9d9e9f
>     a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
>     "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
>     d0d1d2d3d4d5d6d7d8d9dadbdcdddedf e0e1e2e3e4e5e6e7e8e9eaebecedeeef
>     f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
>     "b11e398dc80327a1c8e7f78c596a4934 4f012eda2d4efad8a050cc4c19afa97c
>     59045a99cac7827271cb41c65e590e09 da3275600c2f09b8367793a9aca3db71
>     cc30c58179ec3e87c14c01d5c1f3434f 1d87", 82},
>     +        // Test Case #3
>     +        {"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", NULL,
>     NULL, "8da4e775a563c18f715f802a063c5a31
>     b8a11f5c5ee1879ec3454e5f3c738d2d 9d201395faa4b61a96c8",42}
>     +    };
>     +
>     +    HKDF<SHA256> kdf2;
>     +
>     +    cout << "\nRFC 5869 HKDF(SHA-256) validation suite
>     running...\n\n";
>     +    pass = TestHKDF(kdf2, testSet2, COUNTOF(testSet2)) && pass;
>     +
>     +    return pass;
>     +}
>     +
>     diff --git a/validate.h b/validate.h
>     index 0ab23cb..620f88a 100644
>     --- a/validate.h
>     +++ b/validate.h
>     @@ -25,6 +25,7 @@ bool ValidateTTMAC();
>      
>      bool ValidateCipherModes();
>      bool ValidatePBKDF();
>     +bool ValidateHKDF();
>      
>      bool ValidateDES();
>      bool ValidateIDEA();
>
> -- 
> -- 
> You received this message because you are subscribed to the "Crypto++
> Users" Google Group.
> To unsubscribe, send an email to
> [email protected].
> More information about Crypto++ and this group is available at
> http://www.cryptopp.com.
> ---
> You received this message because you are subscribed to the Google
> Groups "Crypto++ Users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to [email protected]
> <mailto:[email protected]>.
> For more options, visit https://groups.google.com/d/optout.

-- 
-- 
You received this message because you are subscribed to the "Crypto++ Users" 
Google Group.
To unsubscribe, send an email to [email protected].
More information about Crypto++ and this group is available at 
http://www.cryptopp.com.
--- 
You received this message because you are subscribed to the Google Groups 
"Crypto++ Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Attachment: smime.p7s
Description: S/MIME Cryptographic Signature

Reply via email to