void BenchMark(const char *name, RandomNumberGenerator &rng, double timeTotal) { const int BUF_SIZE = 2048U; AlignedSecByteBlock buf(BUF_SIZE); Test::GlobalRNG().GenerateBlock(buf, BUF_SIZE); buf.SetMark(16); SymmetricCipher * cipher = dynamic_cast<SymmetricCipher*>(&rng); if (cipher != NULLPTR) { const size_t size = cipher->DefaultKeyLength(); if (cipher->IsResynchronizable()) cipher->SetKeyWithIV(buf, size, buf+size); else cipher->SetKey(buf, size); } unsigned long long blocks = 1; double timeTaken; clock_t start = ::clock(); do { rng.GenerateBlock(buf, buf.size()); blocks++; timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND; } while (timeTaken < timeTotal); OutputResultBytes(name, double(blocks) * BUF_SIZE, timeTaken); }
bool TestModeIV(SymmetricCipher &e, SymmetricCipher &d) { SecByteBlock lastIV, iv(e.IVSize()); StreamTransformationFilter filter(e, new StreamTransformationFilter(d)); byte plaintext[20480]; for (unsigned int i=1; i<sizeof(plaintext); i*=2) { e.GetNextIV(GlobalRNG(), iv); if (iv == lastIV) return false; else lastIV = iv; e.Resynchronize(iv); d.Resynchronize(iv); unsigned int length = STDMAX(GlobalRNG().GenerateWord32(0, i), (word32)e.MinLastBlockSize()); GlobalRNG().GenerateBlock(plaintext, length); if (!TestFilter(filter, plaintext, length, plaintext, length)) return false; } return true; }
void TestSymmetricCipher(TestData &v, const NameValuePairs &overrideParameters) { std::string name = GetRequiredDatum(v, "Name"); std::string test = GetRequiredDatum(v, "Test"); std::string key = GetDecodedDatum(v, "Key"); std::string plaintext = GetDecodedDatum(v, "Plaintext"); TestDataNameValuePairs testDataPairs(v); CombinedNameValuePairs pairs(overrideParameters, testDataPairs); if (test == "Encrypt" || test == "EncryptXorDigest" || test == "Resync" || test == "EncryptionMCT" || test == "DecryptionMCT") { static member_ptr<SymmetricCipher> encryptor, decryptor; static std::string lastName; if (name != lastName) { encryptor.reset(ObjectFactoryRegistry<SymmetricCipher, ENCRYPTION>::Registry().CreateObject(name.c_str())); decryptor.reset(ObjectFactoryRegistry<SymmetricCipher, DECRYPTION>::Registry().CreateObject(name.c_str())); lastName = name; } ConstByteArrayParameter iv; if (pairs.GetValue(Name::IV(), iv) && iv.size() != encryptor->IVSize()) SignalTestFailure(); if (test == "Resync") { encryptor->Resynchronize(iv.begin(), (int)iv.size()); decryptor->Resynchronize(iv.begin(), (int)iv.size()); } else { encryptor->SetKey((const byte *)key.data(), key.size(), pairs); decryptor->SetKey((const byte *)key.data(), key.size(), pairs); } int seek = pairs.GetIntValueWithDefault("Seek", 0); if (seek) { encryptor->Seek(seek); decryptor->Seek(seek); } std::string encrypted, xorDigest, ciphertext, ciphertextXorDigest; if (test == "EncryptionMCT" || test == "DecryptionMCT") { SymmetricCipher *cipher = encryptor.get(); SecByteBlock buf((byte *)plaintext.data(), plaintext.size()), keybuf((byte *)key.data(), key.size()); if (test == "DecryptionMCT") { cipher = decryptor.get(); ciphertext = GetDecodedDatum(v, "Ciphertext"); buf.Assign((byte *)ciphertext.data(), ciphertext.size()); } for (int i=0; i<400; i++) { encrypted.reserve(10000 * plaintext.size()); for (int j=0; j<10000; j++) { cipher->ProcessString(buf.begin(), buf.size()); encrypted.append((char *)buf.begin(), buf.size()); } encrypted.erase(0, encrypted.size() - keybuf.size()); xorbuf(keybuf.begin(), (const byte *)encrypted.data(), keybuf.size()); cipher->SetKey(keybuf, keybuf.size()); } encrypted.assign((char *)buf.begin(), buf.size()); ciphertext = GetDecodedDatum(v, test == "EncryptionMCT" ? "Ciphertext" : "Plaintext"); if (encrypted != ciphertext) { std::cout << "incorrectly encrypted: "; StringSource xx(encrypted, false, new HexEncoder(new FileSink(std::cout))); xx.Pump(256); xx.Flush(false); std::cout << "\n"; SignalTestFailure(); } return; } StreamTransformationFilter encFilter(*encryptor, new StringSink(encrypted), StreamTransformationFilter::NO_PADDING); RandomizedTransfer(StringStore(plaintext).Ref(), encFilter, true); encFilter.MessageEnd(); /*{ std::string z; encryptor->Seek(seek); StringSource ss(plaintext, false, new StreamTransformationFilter(*encryptor, new StringSink(z), StreamTransformationFilter::NO_PADDING)); while (ss.Pump(64)) {} ss.PumpAll(); for (int i=0; i<z.length(); i++) assert(encrypted[i] == z[i]); }*/ if (test != "EncryptXorDigest") ciphertext = GetDecodedDatum(v, "Ciphertext"); else { ciphertextXorDigest = GetDecodedDatum(v, "CiphertextXorDigest"); xorDigest.append(encrypted, 0, 64); for (size_t i=64; i<encrypted.size(); i++) xorDigest[i%64] ^= encrypted[i]; } if (test != "EncryptXorDigest" ? encrypted != ciphertext : xorDigest != ciphertextXorDigest) { std::cout << "incorrectly encrypted: "; StringSource xx(encrypted, false, new HexEncoder(new FileSink(std::cout))); xx.Pump(2048); xx.Flush(false); std::cout << "\n"; SignalTestFailure(); } std::string decrypted; StreamTransformationFilter decFilter(*decryptor, new StringSink(decrypted), StreamTransformationFilter::NO_PADDING); RandomizedTransfer(StringStore(encrypted).Ref(), decFilter, true); decFilter.MessageEnd(); if (decrypted != plaintext) { std::cout << "incorrectly decrypted: "; StringSource xx(decrypted, false, new HexEncoder(new FileSink(std::cout))); xx.Pump(256); xx.Flush(false); std::cout << "\n"; SignalTestFailure(); } } else { std::cout << "unexpected test name\n"; SignalTestError(); } }
void PEM_CipherForAlgorithm(const EncapsulatedHeader& header, const char* password, size_t length, auto_ptr<StreamTransformation>& stream) { unsigned int ksize, vsize; string algorithm(header.m_algorithm); std::transform(algorithm.begin(), algorithm.end(), algorithm.begin(), (int(*)(int))std::toupper); if(algorithm == "AES-256-CBC") { ksize = 32; vsize = 16; stream = auto_ptr<StreamTransformation>(new CBC_Mode<AES>::Decryption); } else if(algorithm == "AES-192-CBC") { ksize = 24; vsize = 16; stream = auto_ptr<StreamTransformation>(new CBC_Mode<AES>::Decryption); } else if(algorithm == "AES-128-CBC") { ksize = 16; vsize = 16; stream = auto_ptr<StreamTransformation>(new CBC_Mode<AES>::Decryption); } else if(algorithm == "CAMELLIA-256-CBC") { ksize = 32; vsize = 16; stream = auto_ptr<StreamTransformation>(new CBC_Mode<Camellia>::Decryption); } else if(algorithm == "CAMELLIA-192-CBC") { ksize = 24; vsize = 16; stream = auto_ptr<StreamTransformation>(new CBC_Mode<Camellia>::Decryption); } else if(algorithm == "CAMELLIA-128-CBC") { ksize = 16; vsize = 16; stream = auto_ptr<StreamTransformation>(new CBC_Mode<Camellia>::Decryption); } else if(algorithm == "DES-EDE3-CBC") { ksize = 24; vsize = 8; stream = auto_ptr<StreamTransformation>(new CBC_Mode<DES_EDE3>::Decryption); } else if(algorithm == "IDEA-CBC") { ksize = 16; vsize = 8; stream = auto_ptr<StreamTransformation>(new CBC_Mode<IDEA>::Decryption); } else if(algorithm == "DES-CBC") { ksize = 8; vsize = 8; stream = auto_ptr<StreamTransformation>(new CBC_Mode<DES>::Decryption); } else { throw NotImplemented("PEM_CipherForAlgorithm: '" + header.m_algorithm + "' is not implemented"); } const unsigned char* _pword = reinterpret_cast<const unsigned char*>(password); const size_t _plen = length; // Decode the IV. It used as the Salt in EVP_BytesToKey, // and its used as the IV in the cipher. HexDecoder hex; hex.Put((const byte*)header.m_iv.data(), header.m_iv.size()); hex.MessageEnd(); // If the IV size is wrong, SetKeyWithIV will throw an exception. size_t size = hex.MaxRetrievable(); size = std::min(size, static_cast<size_t>(vsize)); SecByteBlock _key(ksize); SecByteBlock _iv(size); SecByteBlock _salt(size); hex.Get(_iv.data(), _iv.size()); // The IV pulls double duty. First, the first PKCS5_SALT_LEN bytes are used // as the Salt in EVP_BytesToKey. Second, its used as the IV in the cipher. _salt = _iv; assert(_salt.size() >= OPENSSL_PKCS5_SALT_LEN); // MD5 is engrained OpenSSL goodness. MD5, IV and Password are IN; KEY is OUT. // {NULL,0} parameters are the OUT IV. However, the original IV in the PEM // header is used; and not the derived IV. Weak::MD5 md5; int ret = OPENSSL_EVP_BytesToKey(md5, _iv.data(), _pword, _plen, 1, _key.data(), _key.size(), NULL, 0); if(ret != static_cast<int>(ksize)) throw Exception(Exception::OTHER_ERROR, "PEM_CipherForAlgorithm: EVP_BytesToKey failed"); SymmetricCipher* cipher = dynamic_cast<SymmetricCipher*>(stream.get()); assert(cipher != NULL); cipher->SetKeyWithIV(_key.data(), _key.size(), _iv.data(), _iv.size()); }