How to use a custom key in Crypto++

3.8k views Asked by At

I have a question referring to the encryption code in this question: Crypto++ encrypt and decrypt in two different c++ programs

If I want to use a custom key/iv, how can I do this?

1

There are 1 answers

1
jww On BEST ANSWER

If I want to use a custom key/iv, how can I do this?

Just plug it into a cipher with a mode. There are plenty of modes to choose from, but you should use an authenticated encryption mode like EAX, CCM or GCM. See Category:Mode for discussion of the modes in Crypto++.

The code below takes a password or secret, keys a cipher, and then encrypts and encodes a message. Next, it decodes the encrypted message. Finally it prints some of the parameters.


try {

    // KDF parameters
    string password = "Super secret password";
    unsigned int iterations = 15000;
    char purpose = 0; // unused by Crypto++

    // 32 bytes of derived material. Used to key the cipher.
    //   16 bytes are for the key, and 16 bytes are for the iv.
    SecByteBlock derived(32);

    // KDF function
    PKCS5_PBKDF2_HMAC<SHA256> kdf;
    kdf.DeriveKey(derived.data(), derived.size(), purpose, (byte*)password.data(), password.size(), NULL, 0, iterations);

    // Encrypt a secret message
    string plaintext = "Attack at dawn", ciphertext, recovered;

    // Key the cipher
    EAX<AES>::Encryption encryptor;
    encryptor.SetKeyWithIV(derived.data(), 16, derived.data() + 16, 16);

    AuthenticatedEncryptionFilter ef(encryptor, new StringSink(ciphertext));
    ef.Put((byte*)plaintext.data(), plaintext.size());
    ef.MessageEnd();

    // Key the cipher
    EAX<AES>::Decryption decryptor;
    decryptor.SetKeyWithIV(derived.data(), 16, derived.data() + 16, 16);

    AuthenticatedDecryptionFilter df(decryptor, new StringSink(recovered));
    df.Put((byte*)ciphertext.data(), ciphertext.size());
    df.MessageEnd();

    // Done with encryption and decryption

    // Encode various parameters
    HexEncoder encoder;
    string key, iv, cipher;

    encoder.Detach(new StringSink(key));
    encoder.Put(derived.data(), 16);
    encoder.MessageEnd();

    encoder.Detach(new StringSink(iv));
    encoder.Put(derived.data() + 16, 16);
    encoder.MessageEnd();

    encoder.Detach(new StringSink(cipher));
    encoder.Put((byte*)ciphertext.data(), ciphertext.size());
    encoder.MessageEnd();

    // Print stuff
    cout << "plaintext: " << plaintext << endl;
    cout << "key: " << key << endl;
    cout << "iv: " << iv << endl;
    cout << "ciphertext: " << cipher << endl;
    cout << "recovered: " << recovered << endl;

}
catch(CryptoPP::Exception& ex)
{
    cerr << ex.what() << endl;
}

A run of the program produces the following output.

$ ./cryptopp-test.exe
plaintext: Attack at dawn
key: 7A8C7732898FB687669CB7DBEFBDD789
iv: 0AA980BABE72797E415C9B8979BF30EF
ciphertext: 197D0BD1A12577393AD1B1696B75D0FC6B8A142CF15B5F887AA965CE75F0
recovered: Attack at dawn

Even better, use an Integrated Encryption Scheme. Crypto++ provides two of them. The first is Elliptic Curve Integrated Encryption Scheme which operates over fields of elliptic curse. The second is Discrete Logarithm Integrated Encryption Scheme, which operates over the field of integers.

There's a number of non-obvious reason why its "even better", but the big one is its IND-CCA2. Other, more practical ones include: you can't reuse a security context because correct use is built into the system; and padding has been removed which greatly simplifies proofs and avoids potential oracles. The system is also predicated on Discrete Logs, which makes it a Diffie-Hellman based problem and its believed to be hard everywhere.