void CTwofishModule::setKey(Tools::CSecureString const &rUserKey, Tools::CSecureMemory const &rGeneratedKey) { mKey.allocate(gKeySize); size_t Iterations = gPasswordIterations; if (rGeneratedKey == gGenericSalt) { Iterations = gPasswordIterationsWithoutSalt; } PKCS5_PBKDF2_HMAC<SHA256> KeyGenerator; KeyGenerator.DeriveKey( &mKey[0], mKey.getSize(), 0x00, reinterpret_cast<byte const *>(&rUserKey[0]), (unsigned int)rUserKey.getSize(), &rGeneratedKey[0], (unsigned int)rGeneratedKey.getSize(), (unsigned int)Iterations); ASSERT(mKey.getSize() == gKeySize); return; }
Encryptor::Encryptor(const std::string& pass, const std::string& theSalt) { // Initialize the random pool AutoSeededRandomPool prng; Encryptor::byteString passphrase; passphrase.assign(pass.begin(), pass.end()); Encryptor::byteString salt; salt.assign(theSalt.begin(), theSalt.end()); PKCS5_PBKDF2_HMAC<CryptoPP::SHA512> passToKey; key = new byte[AES_SIZE]; passToKey.DeriveKey(key, AES_SIZE, '\0', passphrase.c_str(), passphrase.size(), salt.c_str(), salt.size(), ITERATIONS); // prng.GenerateBlock(key, sizeof(key)); }
ConstBufferPtr SecTpm::exportPrivateKeyPkcs5FromTpm(const Name& keyName, const std::string& passwordStr) { using namespace CryptoPP; uint8_t salt[8] = {0}; uint8_t iv[8] = {0}; // derive key if (!generateRandomBlock(salt, 8) || !generateRandomBlock(iv, 8)) BOOST_THROW_EXCEPTION(Error("Cannot generate salt or iv")); uint32_t iterationCount = 2048; PKCS5_PBKDF2_HMAC<SHA1> keyGenerator; size_t derivedLen = 24; // For DES-EDE3-CBC-PAD byte derived[24] = {0}; byte purpose = 0; try { keyGenerator.DeriveKey(derived, derivedLen, purpose, reinterpret_cast<const byte*>(passwordStr.c_str()), passwordStr.size(), salt, 8, iterationCount); } catch (const CryptoPP::Exception& e) { BOOST_THROW_EXCEPTION(Error("Cannot derived the encryption key")); } // encrypt CBC_Mode< DES_EDE3 >::Encryption e; e.SetKeyWithIV(derived, derivedLen, iv); ConstBufferPtr pkcs8PrivateKey = exportPrivateKeyPkcs8FromTpm(keyName); if (pkcs8PrivateKey == nullptr) BOOST_THROW_EXCEPTION(Error("Cannot export the private key, #1")); OBufferStream encryptedOs; try { StringSource stringSource(pkcs8PrivateKey->buf(), pkcs8PrivateKey->size(), true, new StreamTransformationFilter(e, new FileSink(encryptedOs))); } catch (const CryptoPP::Exception& e) { BOOST_THROW_EXCEPTION(Error("Cannot export the private key, #2")); } // encode Oid pbes2Id("1.2.840.113549.1.5.13"); Oid pbkdf2Id("1.2.840.113549.1.5.12"); Oid pbes2encsId("1.2.840.113549.3.7"); OBufferStream pkcs8Os; try { FileSink sink(pkcs8Os); // EncryptedPrivateKeyInfo ::= SEQUENCE { // encryptionAlgorithm EncryptionAlgorithmIdentifier, // encryptedData OCTET STRING } DERSequenceEncoder encryptedPrivateKeyInfo(sink); { // EncryptionAlgorithmIdentifier ::= SEQUENCE { // algorithm OBJECT IDENTIFIER {{PBES2-id}}, // parameters SEQUENCE {{PBES2-params}} } DERSequenceEncoder encryptionAlgorithm(encryptedPrivateKeyInfo); { pbes2Id.encode(encryptionAlgorithm); // PBES2-params ::= SEQUENCE { // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} } DERSequenceEncoder pbes2Params(encryptionAlgorithm); { // AlgorithmIdentifier ::= SEQUENCE { // algorithm OBJECT IDENTIFIER {{PBKDF2-id}}, // parameters SEQUENCE {{PBKDF2-params}} } DERSequenceEncoder pbes2KDFs(pbes2Params); { pbkdf2Id.encode(pbes2KDFs); // AlgorithmIdentifier ::= SEQUENCE { // salt OCTET STRING, // iterationCount INTEGER (1..MAX), // keyLength INTEGER (1..MAX) OPTIONAL, // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 } DERSequenceEncoder pbkdf2Params(pbes2KDFs); { DEREncodeOctetString(pbkdf2Params, salt, 8); DEREncodeUnsigned<uint32_t>(pbkdf2Params, iterationCount, INTEGER); } pbkdf2Params.MessageEnd(); } pbes2KDFs.MessageEnd(); // AlgorithmIdentifier ::= SEQUENCE { // algorithm OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}}, // parameters OCTET STRING} {{iv}} } DERSequenceEncoder pbes2Encs(pbes2Params); { pbes2encsId.encode(pbes2Encs); DEREncodeOctetString(pbes2Encs, iv, 8); } pbes2Encs.MessageEnd(); } pbes2Params.MessageEnd(); } encryptionAlgorithm.MessageEnd(); DEREncodeOctetString(encryptedPrivateKeyInfo, encryptedOs.buf()->buf(), encryptedOs.buf()->size()); } encryptedPrivateKeyInfo.MessageEnd(); return pkcs8Os.buf(); } catch (const CryptoPP::Exception& e) { BOOST_THROW_EXCEPTION(Error("Cannot export the private key, #3")); } }
bool SecTpm::importPrivateKeyPkcs5IntoTpm(const Name& keyName, const uint8_t* buf, size_t size, const std::string& passwordStr) { using namespace CryptoPP; Oid pbes2Id; Oid pbkdf2Id; SecByteBlock saltBlock; uint32_t iterationCount; Oid pbes2encsId; SecByteBlock ivBlock; SecByteBlock encryptedDataBlock; try { // decode some decoding processes are not necessary for now, // because we assume only one encryption scheme. StringSource source(buf, size, true); // EncryptedPrivateKeyInfo ::= SEQUENCE { // encryptionAlgorithm EncryptionAlgorithmIdentifier, // encryptedData OCTET STRING } BERSequenceDecoder encryptedPrivateKeyInfo(source); { // EncryptionAlgorithmIdentifier ::= SEQUENCE { // algorithm OBJECT IDENTIFIER {{PBES2-id}}, // parameters SEQUENCE {{PBES2-params}} } BERSequenceDecoder encryptionAlgorithm(encryptedPrivateKeyInfo); { pbes2Id.decode(encryptionAlgorithm); // PBES2-params ::= SEQUENCE { // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} } BERSequenceDecoder pbes2Params(encryptionAlgorithm); { // AlgorithmIdentifier ::= SEQUENCE { // algorithm OBJECT IDENTIFIER {{PBKDF2-id}}, // parameters SEQUENCE {{PBKDF2-params}} } BERSequenceDecoder pbes2KDFs(pbes2Params); { pbkdf2Id.decode(pbes2KDFs); // AlgorithmIdentifier ::= SEQUENCE { // salt OCTET STRING, // iterationCount INTEGER (1..MAX), // keyLength INTEGER (1..MAX) OPTIONAL, // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 } BERSequenceDecoder pbkdf2Params(pbes2KDFs); { BERDecodeOctetString(pbkdf2Params, saltBlock); BERDecodeUnsigned<uint32_t>(pbkdf2Params, iterationCount, INTEGER); } pbkdf2Params.MessageEnd(); } pbes2KDFs.MessageEnd(); // AlgorithmIdentifier ::= SEQUENCE { // algorithm OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}}, // parameters OCTET STRING} {{iv}} } BERSequenceDecoder pbes2Encs(pbes2Params); { pbes2encsId.decode(pbes2Encs); BERDecodeOctetString(pbes2Encs, ivBlock); } pbes2Encs.MessageEnd(); } pbes2Params.MessageEnd(); } encryptionAlgorithm.MessageEnd(); BERDecodeOctetString(encryptedPrivateKeyInfo, encryptedDataBlock); } encryptedPrivateKeyInfo.MessageEnd(); } catch (const CryptoPP::Exception& e) { return false; } PKCS5_PBKDF2_HMAC<SHA1> keyGenerator; size_t derivedLen = 24; //For DES-EDE3-CBC-PAD byte derived[24] = {0}; byte purpose = 0; try { keyGenerator.DeriveKey(derived, derivedLen, purpose, reinterpret_cast<const byte*>(passwordStr.c_str()), passwordStr.size(), saltBlock.BytePtr(), saltBlock.size(), iterationCount); } catch (const CryptoPP::Exception& e) { return false; } //decrypt CBC_Mode< DES_EDE3 >::Decryption d; d.SetKeyWithIV(derived, derivedLen, ivBlock.BytePtr()); OBufferStream privateKeyOs; try { StringSource encryptedSource(encryptedDataBlock.BytePtr(), encryptedDataBlock.size(), true, new StreamTransformationFilter(d, new FileSink(privateKeyOs))); } catch (const CryptoPP::Exception& e) { return false; } if (!importPrivateKeyPkcs8IntoTpm(keyName, privateKeyOs.buf()->buf(), privateKeyOs.buf()->size())) return false; // determine key type StringSource privateKeySource(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size(), true); KeyType publicKeyType = KeyType::NONE; SecByteBlock rawKeyBits; // PrivateKeyInfo ::= SEQUENCE { // INTEGER, // SEQUENCE, // OCTECT STRING} BERSequenceDecoder privateKeyInfo(privateKeySource); { uint32_t versionNum; BERDecodeUnsigned<uint32_t>(privateKeyInfo, versionNum, INTEGER); BERSequenceDecoder sequenceDecoder(privateKeyInfo); { Oid keyTypeOid; keyTypeOid.decode(sequenceDecoder); if (keyTypeOid == oid::RSA) publicKeyType = KeyType::RSA; else if (keyTypeOid == oid::ECDSA) publicKeyType = KeyType::EC; else return false; // Unsupported key type; } } // derive public key OBufferStream publicKeyOs; try { switch (publicKeyType) { case KeyType::RSA: { RSA::PrivateKey privateKey; privateKey.Load(StringStore(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()).Ref()); RSAFunction publicKey(privateKey); FileSink publicKeySink(publicKeyOs); publicKey.DEREncode(publicKeySink); publicKeySink.MessageEnd(); break; } case KeyType::EC: { ECDSA<ECP, SHA256>::PrivateKey privateKey; privateKey.Load(StringStore(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()).Ref()); ECDSA<ECP, SHA256>::PublicKey publicKey; privateKey.MakePublicKey(publicKey); publicKey.AccessGroupParameters().SetEncodeAsOID(true); FileSink publicKeySink(publicKeyOs); publicKey.DEREncode(publicKeySink); publicKeySink.MessageEnd(); break; } default: return false; } } catch (const CryptoPP::Exception& e) { return false; } if (!importPublicKeyPkcs1IntoTpm(keyName, publicKeyOs.buf()->buf(), publicKeyOs.buf()->size())) return false; return true; }
int main(int argc, char * argv[]) { using namespace std; using namespace CryptoPP; string password = ""; unsigned int iterations = 1; // AutoSeededX917RNG<AES> rng; // SecByteBlock iv(AES::BLOCKSIZE); // rng.GenerateBlock(iv,iv.size()); // See NIST SP 800-132 for detailed recommendations on length, generation and // format of the salt. This test program will just generate a random one. That // might not be sufficient for every application. // SecByteBlock pwsalt(AES::DEFAULT_KEYLENGTH); // rng.GenerateBlock(pwsalt,pwsalt.size()); SecByteBlock recoveredsalt(AES::DEFAULT_KEYLENGTH); StringSource saltDecoder(HEXSALT,true,new HexDecoder(new ArraySink(recoveredsalt, recoveredsalt.size()))); SecByteBlock recoverediv(AES::BLOCKSIZE); StringSource ivDecoder(HEXIV,true,new HexDecoder(new ArraySink(recoverediv, recoverediv.size()))); SecByteBlock derivedkey(AES::DEFAULT_KEYLENGTH); cout << "Password is " << password << endl; cout << "Deriving key from password:"******"Done" << endl; string message = "ceciestuntest"; string ciphertext; CBC_Mode<AES>::Encryption aesencryption(derivedkey,derivedkey.size(), recoverediv); // encrypt message using key derived above, storing the hex encoded result into ciphertext StringSource encryptor(message,true, new StreamTransformationFilter(aesencryption, new HexEncoder( new StringSink(ciphertext))) ); // hex encode salt and IV for "transport" // string hexsalt, hexiv; // ArraySource saltEncoder(pwsalt,pwsalt.size(), true, new HexEncoder(new StringSink(hexsalt))); // ArraySource ivEncoder(iv,iv.size(), true, new HexEncoder(new StringSink(hexiv))); cout << "Salt: " << HEXSALT << endl; cout << "IV: " << HEXIV << endl; cout << "Ciphertext: " << ciphertext << endl; // now recover the plain text given the password, salt, IV and ciphertext SecByteBlock recoveredkey(AES::DEFAULT_KEYLENGTH); cout << "Re-deriving encryption key based on encoded values above." << endl; pbkdf.DeriveKey(recoveredkey, recoveredkey.size(), 0x00, (byte *) password.data(), password.size(), recoveredsalt, recoveredsalt.size(), iterations); cout << "Done." << endl; CBC_Mode<AES>::Decryption aesdecryption(recoveredkey, recoveredkey.size(), recoverediv); string recoveredtext; cout << "-------------------------" << endl; ciphertext = "F4302E98C80FC97FE72BA52CFF810B5C"; cout << "Ciphertext: " << ciphertext << endl; try { StringSource decryptor(ciphertext, true, new HexDecoder( new StreamTransformationFilter(aesdecryption, new StringSink(recoveredtext)) )); } catch(Exception e) { cerr << "\nException raised: " << e.what() << endl; } cout << "Recovered plaintext value: " << recoveredtext << endl; return 0; }