// Generic login function bool SecureDataManager::login(const ByteString& passphrase, const ByteString& encryptedKey) { // Log out first this->logout(); // First, take the salt from the encrypted key ByteString salt = encryptedKey.substr(0,8); // Then, take the IV from the encrypted key ByteString IV = encryptedKey.substr(8, aes->getBlockSize()); // Now, take the encrypted data from the encrypted key ByteString encryptedKeyData = encryptedKey.substr(8 + aes->getBlockSize()); // Derive the PBE key AESKey* pbeKey = NULL; if (!RFC4880::PBEDeriveKey(passphrase, salt, &pbeKey)) { return false; } // Decrypt the key data ByteString decryptedKeyData; ByteString finalBlock; // NOTE: The login will fail here if incorrect passphrase is supplied if (!aes->decryptInit(pbeKey, SymMode::CBC, IV) || !aes->decryptUpdate(encryptedKeyData, decryptedKeyData) || !aes->decryptFinal(finalBlock)) { delete pbeKey; return false; } delete pbeKey; decryptedKeyData += finalBlock; // Check the magic if (decryptedKeyData.substr(0, 3) != magic) { // The passphrase was incorrect DEBUG_MSG("Incorrect passphrase supplied"); return false; } // Strip off the magic ByteString key = decryptedKeyData.substr(3); // And mask the key decryptedKeyData.wipe(); MutexLocker lock(dataMgrMutex); remask(key); return true; }
// Encode into PKCS#8 DER ByteString OSSLECPrivateKey::PKCS8Encode() { ByteString der; if (eckey == NULL) return der; EVP_PKEY* pkey = EVP_PKEY_new(); if (pkey == NULL) return der; if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) { EVP_PKEY_free(pkey); return der; } PKCS8_PRIV_KEY_INFO* p8inf = EVP_PKEY2PKCS8(pkey); EVP_PKEY_free(pkey); if (p8inf == NULL) return der; int len = i2d_PKCS8_PRIV_KEY_INFO(p8inf, NULL); if (len < 0) { PKCS8_PRIV_KEY_INFO_free(p8inf); return der; } der.resize(len); unsigned char* priv = &der[0]; int len2 = i2d_PKCS8_PRIV_KEY_INFO(p8inf, &priv); PKCS8_PRIV_KEY_INFO_free(p8inf); if (len2 != len) der.wipe(); return der; }
void GOSTTests::readTmpFile(ByteString& data) { unsigned char buf[256]; data.wipe(); #ifdef _WIN32 FILE* in = fopen("gost-hashtest-out.tmp", "r"); #else FILE* in = fopen("gost-hashtest-out.tmp", "rb"); #endif CPPUNIT_ASSERT(in != NULL); int read = 0; do { read = fread(buf, 1, 256, in); data += ByteString(buf, read); } while (read > 0); CPPUNIT_ASSERT(read == 0); CPPUNIT_ASSERT(!fclose(in)); }
// Generate random data bool BotanRNG::generateRandom(ByteString& data, const size_t len) { data.wipe(len); if (len > 0) rng->randomize(&data[0], len); return true; }
// Encrypt the supplied data bool SecureDataManager::encrypt(const ByteString& plaintext, ByteString& encrypted) { // Check the object logged in state if ((!userLoggedIn && !soLoggedIn) || (maskedKey.size() != 32)) { return false; } AESKey theKey(256); ByteString unmaskedKey; { MutexLocker lock(dataMgrMutex); unmask(unmaskedKey); theKey.setKeyBits(unmaskedKey); remask(unmaskedKey); } // Wipe encrypted data block encrypted.wipe(); // Generate random IV ByteString IV; if (!rng->generateRandom(IV, aes->getBlockSize())) return false; ByteString finalBlock; if (!aes->encryptInit(&theKey, SymMode::CBC, IV) || !aes->encryptUpdate(plaintext, encrypted) || !aes->encryptFinal(finalBlock)) { return false; } encrypted += finalBlock; // Add IV to output data encrypted = IV + encrypted; return true; }
void HashTests::readTmpFile(ByteString& data) { unsigned char buf[256]; data.wipe(); FILE* in = fopen("shsmv2-hashtest-out.tmp", "r"); CPPUNIT_ASSERT(in != NULL); int read = 0; do { read = fread(buf, 1, 256, in); data += ByteString(buf, read); } while (read > 0); CPPUNIT_ASSERT(read == 0); CPPUNIT_ASSERT(!fclose(in)); }
// Encryption functions bool BotanSymmetricAlgorithm::encryptInit(const SymmetricKey* key, const std::string mode /* = "cbc" */, const ByteString& IV /* = ByteString()*/, bool padding /* = true */) { // Call the superclass initialiser if (!SymmetricAlgorithm::encryptInit(key, mode, IV, padding)) { return false; } // Check the IV if ((IV.size() > 0) && (IV.size() != getBlockSize())) { ERROR_MSG("Invalid IV size (%d bytes, expected %d bytes)", IV.size(), getBlockSize()); ByteString dummy; SymmetricAlgorithm::encryptFinal(dummy); return false; } ByteString iv; if (IV.size() > 0) { iv = IV; } else { iv.wipe(getBlockSize()); } // Set the padding mode (PCKS7 or NoPadding) if (padding) { currentPaddingMode = "PKCS7"; } else { currentPaddingMode = "NoPadding"; } // Determine the cipher std::string cipherName = getCipher(); if (cipherName == "") { ERROR_MSG("Invalid encryption cipher"); ByteString dummy; SymmetricAlgorithm::encryptFinal(dummy); return false; } // Allocate the context try { Botan::SymmetricKey botanKey = Botan::SymmetricKey(key->getKeyBits().const_byte_str(), key->getKeyBits().size()); Botan::InitializationVector botanIV = Botan::InitializationVector(IV.const_byte_str(), IV.size()); if (mode == "ecb") { cryption = new Botan::Pipe(Botan::get_cipher(cipherName, botanKey, Botan::ENCRYPTION)); } else { cryption = new Botan::Pipe(Botan::get_cipher(cipherName, botanKey, botanIV, Botan::ENCRYPTION)); } cryption->start_msg(); } catch (...) { ERROR_MSG("Failed to create the encryption token"); ByteString dummy; SymmetricAlgorithm::encryptFinal(dummy); delete cryption; cryption = NULL; return false; } return true; }
// Generate random data bool OSSLRNG::generateRandom(ByteString& data, const size_t len) { data.wipe(len); return RAND_bytes(&data[0], len); }
// Generic function for creating an encrypted version of the key from the specified passphrase bool SecureDataManager::pbeEncryptKey(const ByteString& passphrase, ByteString& encryptedKey) { // Generate salt ByteString salt; if (!rng->generateRandom(salt, 8)) return false; // Derive the key using RFC4880 PBE AESKey* pbeKey = NULL; if (!RFC4880::PBEDeriveKey(passphrase, salt, &pbeKey)) { return false; } // Add the salt encryptedKey.wipe(); encryptedKey += salt; // Generate random IV ByteString IV; if (!rng->generateRandom(IV, aes->getBlockSize())) return false; // Add the IV encryptedKey += IV; // Encrypt the data ByteString block; if (!aes->encryptInit(pbeKey, SymMode::CBC, IV)) { delete pbeKey; return false; } // First, add the magic if (!aes->encryptUpdate(magic, block)) { delete pbeKey; return false; } encryptedKey += block; // Then, add the key itself ByteString key; { MutexLocker lock(dataMgrMutex); unmask(key); bool rv = aes->encryptUpdate(key, block); remask(key); if (!rv) { delete pbeKey; return false; } } encryptedKey += block; // And finalise encryption if (!aes->encryptFinal(block)) { delete pbeKey; return false; } encryptedKey += block; delete pbeKey; return true; }
bool BotanDH::deriveKey(SymmetricKey **ppSymmetricKey, PublicKey* publicKey, PrivateKey* privateKey) { // Check parameters if ((ppSymmetricKey == NULL) || (publicKey == NULL) || (privateKey == NULL)) { return false; } // Get keys Botan::DH_PublicKey* pub = ((BotanDHPublicKey*) publicKey)->getBotanKey(); BotanDH_PrivateKey* priv = ((BotanDHPrivateKey*) privateKey)->getBotanKey(); if (pub == NULL || priv == NULL || priv->impl == NULL) { ERROR_MSG("Failed to get Botan DH keys"); return false; } // Derive the secret Botan::SymmetricKey sk; try { #if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,33) BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG(); Botan::PK_Key_Agreement ka(*priv->impl, *rng->getRNG(), "Raw"); #else Botan::PK_Key_Agreement ka(*priv->impl, "Raw"); #endif sk = ka.derive_key(0, pub->public_value()); } catch (std::exception& e) { ERROR_MSG("Botan DH key agreement failed: %s", e.what()); return false; } ByteString secret; // We compensate that Botan removes leading zeros int size = ((BotanDHPublicKey*) publicKey)->getOutputLength(); int keySize = sk.length(); secret.wipe(size); memcpy(&secret[0] + size - keySize, sk.begin(), keySize); *ppSymmetricKey = new SymmetricKey(secret.size() * 8); if (*ppSymmetricKey == NULL) { ERROR_MSG("Can't create DH secret"); return false; } if (!(*ppSymmetricKey)->setKeyBits(secret)) { delete *ppSymmetricKey; *ppSymmetricKey = NULL; return false; } return true; }