// 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; }
// Decrypt the supplied data bool SecureDataManager::decrypt(const ByteString& encrypted, ByteString& plaintext) { // Check the object logged in state if ((!userLoggedIn && !soLoggedIn) || (maskedKey.size() != 32)) { return false; } // Do not attempt decryption of empty byte strings if (encrypted.size() == 0) { plaintext = ByteString(""); return true; } AESKey theKey(256); ByteString unmaskedKey; { MutexLocker lock(dataMgrMutex); unmask(unmaskedKey); theKey.setKeyBits(unmaskedKey); remask(unmaskedKey); } // Take the IV from the input data ByteString IV = encrypted.substr(0, aes->getBlockSize()); if (IV.size() != aes->getBlockSize()) { ERROR_MSG("Invalid IV in encrypted data"); return false; } ByteString finalBlock; if (!aes->decryptInit(&theKey, SymMode::CBC, IV) || !aes->decryptUpdate(encrypted.substr(aes->getBlockSize()), plaintext) || !aes->decryptFinal(finalBlock)) { return false; } plaintext += finalBlock; return true; }
void GOSTTests::testHash() { // Get an RNG and GOST R 34.11-94 hash instance CPPUNIT_ASSERT((rng = CryptoFactory::i()->getRNG()) != NULL); CPPUNIT_ASSERT((hash = CryptoFactory::i()->getHashAlgorithm("gost")) != NULL); // Generate some random input data ByteString b; ByteString osslHash, gostHash; CPPUNIT_ASSERT(rng->generateRandom(b, 53287)); // Write it to file writeTmpFile(b); // Use OpenSSL externally to hash it #ifndef _WIN32 CPPUNIT_ASSERT(system("openssl dgst -engine gost -md_gost94 -binary < gost-hashtest.tmp > gost-hashtest-out.tmp 2> /dev/null") == 0); #else CPPUNIT_ASSERT(system("openssl dgst -engine gost -md_gost94 -binary < gost-hashtest.tmp > gost-hashtest-out.tmp 2> nul") == 0); #endif // Read the hash from file readTmpFile(osslHash); // Now recreate the hash using our implementation in a single operation CPPUNIT_ASSERT(hash->hashInit()); CPPUNIT_ASSERT(hash->hashUpdate(b)); CPPUNIT_ASSERT(hash->hashFinal(gostHash)); CPPUNIT_ASSERT(osslHash == gostHash); // Now recreate the hash in a single part operation gostHash.wipe(); CPPUNIT_ASSERT(hash->hashInit()); CPPUNIT_ASSERT(hash->hashUpdate(b.substr(0, 567))); CPPUNIT_ASSERT(hash->hashUpdate(b.substr(567, 989))); CPPUNIT_ASSERT(hash->hashUpdate(b.substr(567 + 989))); CPPUNIT_ASSERT(hash->hashFinal(gostHash)); CPPUNIT_ASSERT(osslHash == gostHash); CryptoFactory::i()->recycleHashAlgorithm(hash); hash = NULL; rng = NULL; }
void HashTests::testMD5() { // Get an RNG and MD5 hash instance CPPUNIT_ASSERT((rng = CryptoFactory::i()->getRNG()) != NULL); CPPUNIT_ASSERT((hash = CryptoFactory::i()->getHashAlgorithm("md5")) != NULL); // Generate some random input data ByteString b; ByteString osslHash, shsmHash; CPPUNIT_ASSERT(rng->generateRandom(b, 52237)); // Write it to file writeTmpFile(b); // Use OpenSSL externally to hash it CPPUNIT_ASSERT(system("cat shsmv2-hashtest.tmp | openssl md5 -binary > shsmv2-hashtest-out.tmp") == 0); // Read the hash from file readTmpFile(osslHash); // Now recreate the hash using our implementation in a single operation CPPUNIT_ASSERT(hash->hashInit()); CPPUNIT_ASSERT(hash->hashUpdate(b)); CPPUNIT_ASSERT(hash->hashFinal(shsmHash)); CPPUNIT_ASSERT(osslHash == shsmHash); // Now recreate the hash in a multiple part operation shsmHash.wipe(); CPPUNIT_ASSERT(hash->hashInit()); CPPUNIT_ASSERT(hash->hashUpdate(b.substr(0, 567))); CPPUNIT_ASSERT(hash->hashUpdate(b.substr(567, 989))); CPPUNIT_ASSERT(hash->hashUpdate(b.substr(567 + 989))); CPPUNIT_ASSERT(hash->hashFinal(shsmHash)); CPPUNIT_ASSERT(osslHash == shsmHash); CryptoFactory::i()->recycleHashAlgorithm(hash); hash = NULL; rng = NULL; }
void GOSTTests::testHmac() { // Get an RNG and HMAC GOST R34.11-94 instance CPPUNIT_ASSERT((rng = CryptoFactory::i()->getRNG()) != NULL); CPPUNIT_ASSERT((mac = CryptoFactory::i()->getMacAlgorithm("hmac-gost")) != NULL); // Key char pk[] = "a_key_for_HMAC-GOST_R-34.11-94_test"; ByteString k((unsigned char *)pk, sizeof(pk)); SymmetricKey key; CPPUNIT_ASSERT(key.setKeyBits(k)); // Generate some random input data ByteString b; CPPUNIT_ASSERT(rng->generateRandom(b, 53287)); // Sign the MAC using our implementation in a single operation ByteString mResult1; CPPUNIT_ASSERT(mac->signInit(&key)); CPPUNIT_ASSERT(mac->signUpdate(b)); CPPUNIT_ASSERT(mac->signFinal(mResult1)); // Sign the MAC in a multiple part operation ByteString mResult2; CPPUNIT_ASSERT(mac->signInit(&key)); CPPUNIT_ASSERT(mac->signUpdate(b.substr(0, 567))); CPPUNIT_ASSERT(mac->signUpdate(b.substr(567, 989))); CPPUNIT_ASSERT(mac->signUpdate(b.substr(567 + 989))); CPPUNIT_ASSERT(mac->signFinal(mResult2)); // Now verify the MAC using our implementation in a single operation CPPUNIT_ASSERT(mac->verifyInit(&key)); CPPUNIT_ASSERT(mac->verifyUpdate(b)); CPPUNIT_ASSERT(mac->verifyFinal(mResult2)); // Now verify the MAC in a multiple part operation CPPUNIT_ASSERT(mac->verifyInit(&key)); CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(0, 567))); CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(567, 989))); CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(567 + 989))); CPPUNIT_ASSERT(mac->verifyFinal(mResult1)); // Check if bad key is refused mResult1[10] ^= 0x11; CPPUNIT_ASSERT(mac->verifyInit(&key)); CPPUNIT_ASSERT(mac->verifyUpdate(b)); CPPUNIT_ASSERT(!mac->verifyFinal(mResult1)); CryptoFactory::i()->recycleMacAlgorithm(mac); mac = NULL; rng = NULL; }
// Set from OpenSSL representation void OSSLGOSTPublicKey::setFromOSSL(const EVP_PKEY* pkey) { ByteString der; int len = i2d_PUBKEY((EVP_PKEY*) pkey, NULL); if (len != 37 + 64) { ERROR_MSG("bad GOST public key encoding length %d", len); return; } der.resize(len); unsigned char *p = &der[0]; i2d_PUBKEY((EVP_PKEY*) pkey, &p); // can check: der is prefix + 64 bytes setQ(der.substr(37)); ByteString inEC; const EC_KEY* eckey = (const EC_KEY*) EVP_PKEY_get0((EVP_PKEY*) pkey); int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey)); inEC.resize(i2d_ASN1_OBJECT(OBJ_nid2obj(nid), NULL)); p = &inEC[0]; i2d_ASN1_OBJECT(OBJ_nid2obj(nid), &p); setEC(inEC); }
void DSATests::testSigningVerifying() { AsymmetricKeyPair* kp; // Key sizes to test std::vector<size_t> keySizes; #ifndef WITH_FIPS keySizes.push_back(512); keySizes.push_back(768); keySizes.push_back(1024); keySizes.push_back(1536); #else keySizes.push_back(1024); #endif #ifndef WITH_BOTAN keySizes.push_back(2048); #endif // Mechanisms to test std::vector<AsymMech::Type> mechanisms; mechanisms.push_back(AsymMech::DSA_SHA1); mechanisms.push_back(AsymMech::DSA_SHA224); mechanisms.push_back(AsymMech::DSA_SHA256); for (std::vector<size_t>::iterator k = keySizes.begin(); k != keySizes.end(); k++) { // Generate parameters AsymmetricParameters* p; CPPUNIT_ASSERT(dsa->generateParameters(&p, (void*) *k)); // Generate key-pair CPPUNIT_ASSERT(dsa->generateKeyPair(&kp, p)); // Generate some data to sign ByteString dataToSign; RNG* rng = CryptoFactory::i()->getRNG(); CPPUNIT_ASSERT(rng->generateRandom(dataToSign, 567)); // Test mechanisms that perform internal hashing for (std::vector<AsymMech::Type>::iterator m = mechanisms.begin(); m != mechanisms.end(); m++) { ByteString blockSignature, singlePartSignature; // Sign the data in blocks CPPUNIT_ASSERT(dsa->signInit(kp->getPrivateKey(), *m)); CPPUNIT_ASSERT(dsa->signUpdate(dataToSign.substr(0, 134))); CPPUNIT_ASSERT(dsa->signUpdate(dataToSign.substr(134, 289))); CPPUNIT_ASSERT(dsa->signUpdate(dataToSign.substr(134 + 289))); CPPUNIT_ASSERT(dsa->signFinal(blockSignature)); // Sign the data in one pass CPPUNIT_ASSERT(dsa->sign(kp->getPrivateKey(), dataToSign, singlePartSignature, *m)); // Now perform multi-pass verification CPPUNIT_ASSERT(dsa->verifyInit(kp->getPublicKey(), *m)); CPPUNIT_ASSERT(dsa->verifyUpdate(dataToSign.substr(0, 125))); CPPUNIT_ASSERT(dsa->verifyUpdate(dataToSign.substr(125, 247))); CPPUNIT_ASSERT(dsa->verifyUpdate(dataToSign.substr(125 + 247))); CPPUNIT_ASSERT(dsa->verifyFinal(blockSignature)); // And single-pass verification CPPUNIT_ASSERT(dsa->verify(kp->getPublicKey(), dataToSign, singlePartSignature, *m)); } // Test mechanisms that do not perform internal hashing CPPUNIT_ASSERT(rng->generateRandom(dataToSign, *k >= 2048 ? 32 : 20)); // Sign the data ByteString signature; CPPUNIT_ASSERT(dsa->sign(kp->getPrivateKey(), dataToSign, signature, AsymMech::DSA)); // Verify the signature CPPUNIT_ASSERT(dsa->verify(kp->getPublicKey(), dataToSign, signature, AsymMech::DSA)); dsa->recycleKeyPair(kp); dsa->recycleParameters(p); } }
void RSATests::testSigningVerifying() { AsymmetricKeyPair* kp; RSAParameters p; // Public exponents to test std::vector<ByteString> exponents; exponents.push_back("010001"); exponents.push_back("03"); exponents.push_back("0B"); exponents.push_back("11"); // Key sizes to test std::vector<size_t> keySizes; keySizes.push_back(1024); keySizes.push_back(1280); keySizes.push_back(2048); //keySizes.push_back(4096); // Mechanisms to test std::vector<AsymMech::Type> mechanisms; #ifndef WITH_FIPS mechanisms.push_back(AsymMech::RSA_MD5_PKCS); #endif mechanisms.push_back(AsymMech::RSA_SHA1_PKCS); mechanisms.push_back(AsymMech::RSA_SHA224_PKCS); mechanisms.push_back(AsymMech::RSA_SHA256_PKCS); mechanisms.push_back(AsymMech::RSA_SHA384_PKCS); mechanisms.push_back(AsymMech::RSA_SHA512_PKCS); mechanisms.push_back(AsymMech::RSA_SHA1_PKCS_PSS); mechanisms.push_back(AsymMech::RSA_SHA224_PKCS_PSS); mechanisms.push_back(AsymMech::RSA_SHA256_PKCS_PSS); mechanisms.push_back(AsymMech::RSA_SHA384_PKCS_PSS); mechanisms.push_back(AsymMech::RSA_SHA512_PKCS_PSS); #ifndef WITH_FIPS mechanisms.push_back(AsymMech::RSA_SSL); #endif /* Max salt length for SHA512 and 1024-bit RSA is 62 bytes */ RSA_PKCS_PSS_PARAMS pssParams[] = { { HashAlgo::SHA1, AsymRSAMGF::MGF1_SHA1, 20 }, { HashAlgo::SHA224, AsymRSAMGF::MGF1_SHA224, 0 }, { HashAlgo::SHA256, AsymRSAMGF::MGF1_SHA256, 0 }, { HashAlgo::SHA384, AsymRSAMGF::MGF1_SHA384, 48 }, { HashAlgo::SHA512, AsymRSAMGF::MGF1_SHA512, 62 } }; for (std::vector<ByteString>::iterator e = exponents.begin(); e != exponents.end(); e++) { for (std::vector<size_t>::iterator k = keySizes.begin(); k != keySizes.end(); k++) { p.setE(*e); p.setBitLength(*k); // Generate key-pair CPPUNIT_ASSERT(rsa->generateKeyPair(&kp, &p)); // Generate some data to sign ByteString dataToSign; RNG* rng = CryptoFactory::i()->getRNG(); CPPUNIT_ASSERT(rng->generateRandom(dataToSign, 567)); // Test mechanisms that perform internal hashing for (std::vector<AsymMech::Type>::iterator m = mechanisms.begin(); m != mechanisms.end(); m++) { ByteString blockSignature, singlePartSignature; void* param = NULL; size_t paramLen = 0; bool isPSS = false; switch (*m) { case AsymMech::RSA_SHA1_PKCS_PSS: param = &pssParams[0]; paramLen = sizeof(pssParams[0]); isPSS = true; break; case AsymMech::RSA_SHA224_PKCS_PSS: param = &pssParams[1]; paramLen = sizeof(pssParams[1]); isPSS = true; break; case AsymMech::RSA_SHA256_PKCS_PSS: param = &pssParams[2]; paramLen = sizeof(pssParams[2]); isPSS = true; break; case AsymMech::RSA_SHA384_PKCS_PSS: param = &pssParams[3]; paramLen = sizeof(pssParams[3]); isPSS = true; break; case AsymMech::RSA_SHA512_PKCS_PSS: param = &pssParams[4]; paramLen = sizeof(pssParams[4]); isPSS = true; break; default: break; } // Sign the data in blocks CPPUNIT_ASSERT(rsa->signInit(kp->getPrivateKey(), *m, param, paramLen)); CPPUNIT_ASSERT(rsa->signUpdate(dataToSign.substr(0, 134))); CPPUNIT_ASSERT(rsa->signUpdate(dataToSign.substr(134, 289))); CPPUNIT_ASSERT(rsa->signUpdate(dataToSign.substr(134 + 289))); CPPUNIT_ASSERT(rsa->signFinal(blockSignature)); // Sign the data in one pass CPPUNIT_ASSERT(rsa->sign(kp->getPrivateKey(), dataToSign, singlePartSignature, *m, param, paramLen)); // If it is not a PSS signature, check if the two signatures match if (!isPSS) { // Check if the two signatures match CPPUNIT_ASSERT(blockSignature == singlePartSignature); } // Now perform multi-pass verification CPPUNIT_ASSERT(rsa->verifyInit(kp->getPublicKey(), *m, param, paramLen)); CPPUNIT_ASSERT(rsa->verifyUpdate(dataToSign.substr(0, 125))); CPPUNIT_ASSERT(rsa->verifyUpdate(dataToSign.substr(125, 247))); CPPUNIT_ASSERT(rsa->verifyUpdate(dataToSign.substr(125 + 247))); CPPUNIT_ASSERT(rsa->verifyFinal(blockSignature)); // And single-pass verification CPPUNIT_ASSERT(rsa->verify(kp->getPublicKey(), dataToSign, singlePartSignature, *m, param, paramLen)); } // Test mechanisms that do not perform internal hashing // Test PKCS #1 signing CPPUNIT_ASSERT(rng->generateRandom(dataToSign, 35)); // Sign the data ByteString signature; CPPUNIT_ASSERT(rsa->sign(kp->getPrivateKey(), dataToSign, signature, AsymMech::RSA_PKCS)); // Verify the signature CPPUNIT_ASSERT(rsa->verify(kp->getPublicKey(), dataToSign, signature, AsymMech::RSA_PKCS)); // Test raw RSA signing size_t byteSize = *k >> 3; CPPUNIT_ASSERT(rng->generateRandom(dataToSign, byteSize)); // Strip the topmost bit dataToSign[0] &= 0x7F; // Sign the data CPPUNIT_ASSERT(rsa->sign(kp->getPrivateKey(), dataToSign, signature, AsymMech::RSA)); // Verify the signature CPPUNIT_ASSERT(rsa->verify(kp->getPublicKey(), dataToSign, signature, AsymMech::RSA)); #ifdef WITH_RAW_PSS // Test raw (SHA1) PKCS PSS signing CPPUNIT_ASSERT(rng->generateRandom(dataToSign, 20)); CPPUNIT_ASSERT(rsa->sign(kp->getPrivateKey(), dataToSign, signature, AsymMech::RSA_PKCS_PSS, &pssParams[0], sizeof(pssParams[0]))); CPPUNIT_ASSERT(rsa->verify(kp->getPublicKey(), dataToSign, signature, AsymMech::RSA_PKCS_PSS, &pssParams[0], sizeof(pssParams[0]))); // Test raw (SHA224) PKCS PSS signing CPPUNIT_ASSERT(rng->generateRandom(dataToSign, 28)); CPPUNIT_ASSERT(rsa->sign(kp->getPrivateKey(), dataToSign, signature, AsymMech::RSA_PKCS_PSS, &pssParams[1], sizeof(pssParams[1]))); CPPUNIT_ASSERT(rsa->verify(kp->getPublicKey(), dataToSign, signature, AsymMech::RSA_PKCS_PSS, &pssParams[1], sizeof(pssParams[1]))); // Test raw (SHA256) PKCS PSS signing CPPUNIT_ASSERT(rng->generateRandom(dataToSign, 32)); CPPUNIT_ASSERT(rsa->sign(kp->getPrivateKey(), dataToSign, signature, AsymMech::RSA_PKCS_PSS, &pssParams[2], sizeof(pssParams[2]))); CPPUNIT_ASSERT(rsa->verify(kp->getPublicKey(), dataToSign, signature, AsymMech::RSA_PKCS_PSS, &pssParams[2], sizeof(pssParams[2]))); // Test raw (SHA384) PKCS PSS signing CPPUNIT_ASSERT(rng->generateRandom(dataToSign, 48)); CPPUNIT_ASSERT(rsa->sign(kp->getPrivateKey(), dataToSign, signature, AsymMech::RSA_PKCS_PSS, &pssParams[3], sizeof(pssParams[3]))); CPPUNIT_ASSERT(rsa->verify(kp->getPublicKey(), dataToSign, signature, AsymMech::RSA_PKCS_PSS, &pssParams[3], sizeof(pssParams[3]))); // Test raw (SHA512) PKCS PSS signing CPPUNIT_ASSERT(rng->generateRandom(dataToSign, 64)); CPPUNIT_ASSERT(rsa->sign(kp->getPrivateKey(), dataToSign, signature, AsymMech::RSA_PKCS_PSS, &pssParams[4], sizeof(pssParams[4]))); CPPUNIT_ASSERT(rsa->verify(kp->getPublicKey(), dataToSign, signature, AsymMech::RSA_PKCS_PSS, &pssParams[4], sizeof(pssParams[4]))); #endif rsa->recycleKeyPair(kp); } } }