PKCS5 PBKDF2 HMAC

From Crypto++ Wiki
Jump to navigation Jump to search
PKCS5_PBKDF2_HMAC
Documentation
#include <cryptopp/pwdbased.h>

PKCS5_PBKDF2_HMAC is an early key derivation function (KDF) specified by PKCS #5. The function takes a secret seed, usage and iteration count and outputs key material.

PKCS5_PBKDF2_HMAC derives from KeyDerivationFunction interface. PKCS5_PBKDF2_HMAC provides two DeriveKey member functions. The first member function is required by KeyDerivationFunction and accepts a NameValuePairs object to pass arbitrary parameters. The second DeriveKey overload provides a specialized DeriveKey with parameters tuned for PKCS5_PBKDF2_HMAC.

PKCS5_PBKDF2_HMAC is an older standard. Early KDFs from the bygone era include P1363_KDF2, PKCS12_PBKDF, PKCS5_PBKDF1 and PKCS5_PBKDF2_HMAC. New applications should consider using a modern KDF, like HKDF. HKDF is state of the art extract-then-expand derivation function with provable security properties.

Constructor

PKCS5_PBKDF2_HMAC provides a default constructor.

DeriveKey

unsigned int DeriveKey (byte *derived, size_t derivedLen,
                        byte purpose,
                        const byte *secret, size_t secretLen,
                        const byte *salt, size_t saltLen,
                        unsigned int iterations,
                        double timeInSeconds=0) const

derived is the buffer to receive the derived key. derivedLen is the size of the buffer, in bytes.

purpose is a purpose byte. It is unused for PKCS5_PBKDF2_HMAC.

secret is private information to use during derivation. secretLen is the size of the buffer, in bytes.

salt is possibly public information to use during derivation. saltLen is the size of the buffer, in bytes.

iterations is an iteration count.

timeInSeconds is the maximum amount of time to iterate the DeriveKey function.

DeriveKey returns the number of iteration.

salt and info are used to help distinguish one instance or run of the algorithm from another. The parameters can be NULL.

If timeInSeconds > 0.0 then DeriveKey will run for the specified amount of time. If timeInSeconds is 0.0 then DeriveKey will run for the specified number of iterations.

KeyDerivationFunction

The base class interface KeyDerivationFunction member function DeriveKey calls the overloaded DeriveKey. The following is from pwdbased.h.

template <class T>
size_t PKCS5_PBKDF2_HMAC<T>::DeriveKey(byte *derived, size_t derivedLen,
    const byte *secret, size_t secretLen, const NameValuePairs& params) const
{
    CRYPTOPP_ASSERT(secret /*&& secretLen*/);
    CRYPTOPP_ASSERT(derived && derivedLen);
    CRYPTOPP_ASSERT(derivedLen <= MaxDerivedKeyLength());
 
    byte purpose = (byte)params.GetIntValueWithDefault("Purpose", 0);
    unsigned int iterations = (unsigned int)params.GetIntValueWithDefault("Iterations", 1);
 
    double timeInSeconds = 0.0f;
    (void)params.GetValue("TimeInSeconds", timeInSeconds);
 
    ConstByteArrayParameter salt;
    (void)params.GetValue(Name::Salt(), salt);
 
    return DeriveKey(derived, derivedLen, purpose, secret, secretLen,
               salt.begin(), salt.size(), iterations, timeInSeconds);
}

Sample Program

The sample program below demonstrates a PKCS5_PBKDF2_HMAC with SHA256.

$ cat test.cxx
#include <iostream>
#include <string>

#include "cryptlib.h"
#include "pwdbased.h"
#include "sha.h"
#include "hex.h"

int main(int argc, char* argv[])
{
    using namespace CryptoPP;

    byte password[] ="password";
    size_t plen = strlen((const char*)password);

    byte salt[] = "salt";
    size_t slen = strlen((const char*)salt);

    byte derived[SHA256::DIGESTSIZE];

    PKCS5_PBKDF2_HMAC<SHA256> pbkdf;
	byte unused = 0;

    pbkdf.DeriveKey(derived, sizeof(derived), unused, password, plen, salt, slen, 1024, 0.0f);

    std::string result;
    HexEncoder encoder(new StringSink(result));

    encoder.Put(derived, sizeof(derived));
    encoder.MessageEnd();

    std::cout << "Derived: " << result << std::endl;

    return 0;
}

Running the program results in the following.

$ ./test.exe
Derived: 231AFB7DCD2E860CFD58AB13372BD12C923076C3598A121960320F6FEC8A5698

You can swap-in any hash class that provides a blocksize. The code below uses BLAKE2b as the message digest. The BLAKE2b sample below requires Commit 758939ab2e1b.

$ cat test.cxx
#include <iostream>
#include <string>

#include "cryptlib.h"
#include "pwdbased.h"
#include "blake2.h"
#include "hex.h"

int main(int argc, char* argv[])
{
    using namespace CryptoPP;

    byte password[] ="password";
    size_t plen = strlen((const char*)password);

    byte salt[] = "salt";
    size_t slen = strlen((const char*)salt);

    byte derived[BLAKE2b::DIGESTSIZE];

    PKCS5_PBKDF2_HMAC<BLAKE2b> pbkdf;
	byte unused = 0;

    pbkdf.DeriveKey(derived, sizeof(derived), unused, password, plen, salt, slen, 1024, 0.0f);

    std::string result;
    HexEncoder encoder(new StringSink(result));

    encoder.Put(derived, sizeof(derived));
    encoder.MessageEnd();

    std::cout << "Derived: " << result << std::endl;

    return 0;
}

Running the program results in the following.

$ ./test.exe
Derived: 4884867341F444153B62921E9EA54D5E56872D8DC60B20D038D2C4FC86537025F4D691D
1EBFF8997926351FAA225B2747325D3B08C7583DCE94487674B8ED817

The sample program below demonstrates a PKCS5_PBKDF2_HMAC with SHA256, and uses the derived material to key a block cipher. Notice two different labels are used. First, the label HKDF key derivation to derive the key; and second, the label HKDF iv derivation to derive the initialization vector.

$ cat test.cxx
#include <iostream>
#include <string>

#include "cryptlib.h"
#include "pwdbased.h"
#include "sha.h"
#include "files.h"
#include "aes.h"
#include "modes.h"
#include "hex.h"

int main(int argc, char* argv[])
{
    using namespace CryptoPP;

    byte password[] ="password";
    size_t plen = strlen((const char*)password);

    byte info1[] = "PKCS5_PBKDF2_HMAC key derivation";
    size_t ilen1 = strlen((const char*)info1);

    byte info2[] = "PKCS5_PBKDF2_HMAC iv derivation";
    size_t ilen2 = strlen((const char*)info2);

    byte key[AES::DEFAULT_KEYLENGTH];
    byte iv[AES::BLOCKSIZE];

    PKCS5_PBKDF2_HMAC<SHA256> pbkdf;
	byte unused = 0;

    pbkdf.DeriveKey(key, sizeof(key), unused, password, plen, info1, ilen1, 1024, 0.0f);
    pbkdf.DeriveKey(iv, sizeof(iv), unused, password, plen, info2, ilen2, 1024, 0.0f);

    std::cout << "Key: ";
    StringSource(key, sizeof(key), true, new HexEncoder(new FileSink(std::cout)));
    std::cout << std::endl;

    std::cout << "IV: ";
    StringSource(iv, sizeof(iv), true, new HexEncoder(new FileSink(std::cout)));
    std::cout << std::endl;

    CBC_Mode<AES>::Encryption enc;
    enc.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));

    // Use AES/CBC encryptor

    return 0;
}

Running the program results in the following.

$ ./test.exe 
Key: 6EF18DB878FAB921AA0397B1D3334FB6
IV: 5FD3729D1D95B914C9C3474E633B68C9

Downloads

No downloads.