// default.cpp - originally written and placed in the public domain by Wei Dai #include "pch.h" #include "config.h" #if CRYPTOPP_MSC_VERSION # pragma warning(disable: 4127 4189) #endif #include "cryptlib.h" #include "filters.h" #include "smartptr.h" #include "default.h" #include "queue.h" #include #include NAMESPACE_BEGIN(CryptoPP) // The purpose of this function Mash() is to take an arbitrary length input // string and *deterministically* produce an arbitrary length output string such // that (1) it looks random, (2) no information about the input is // deducible from it, and (3) it contains as much entropy as it can hold, or // the amount of entropy in the input string, whichever is smaller. template static void Mash(const byte *in, size_t inLen, byte *out, size_t outLen, int iterations) { if (BytePrecision(outLen) > 2) throw InvalidArgument("Mash: output length too large"); size_t bufSize = RoundUpToMultipleOf(outLen, (size_t)H::DIGESTSIZE); byte b[2]; SecByteBlock buf(bufSize); SecByteBlock outBuf(bufSize); H hash; unsigned int i; for(i=0; i> 8); b[1] = (byte) i; hash.Update(b, 2); hash.Update(in, inLen); hash.Final(outBuf+i); } while (iterations-- > 1) { std::memcpy(buf, outBuf, bufSize); for (i=0; i> 8); b[1] = (byte) i; hash.Update(b, 2); hash.Update(buf, bufSize); hash.Final(outBuf+i); } } std::memcpy(out, outBuf, outLen); } template static void GenerateKeyIV(const byte *passphrase, size_t passphraseLength, const byte *salt, size_t saltLength, unsigned int iterations, byte *key, byte *IV) { // UBsan. User supplied params, may be NULL SecByteBlock temp(passphraseLength+saltLength); if (passphrase != NULLPTR) std::memcpy(temp, passphrase, passphraseLength); if (salt != NULLPTR) std::memcpy(temp+passphraseLength, salt, saltLength); // OK. Derived params, cannot be NULL SecByteBlock keyIV(EnumToInt(Info::KEYLENGTH)+EnumToInt(+Info::BLOCKSIZE)); Mash(temp, passphraseLength + saltLength, keyIV, EnumToInt(Info::KEYLENGTH)+EnumToInt(+Info::BLOCKSIZE), iterations); std::memcpy(key, keyIV, Info::KEYLENGTH); std::memcpy(IV, keyIV+Info::KEYLENGTH, Info::BLOCKSIZE); } // ******************************************************** template DataEncryptor::DataEncryptor(const char *passphrase, BufferedTransformation *attachment) : ProxyFilter(NULLPTR, 0, 0, attachment), m_passphrase((const byte *)passphrase, strlen(passphrase)) { CRYPTOPP_COMPILE_ASSERT((int)SALTLENGTH <= DIGESTSIZE); CRYPTOPP_COMPILE_ASSERT((int)BLOCKSIZE <= (int)DIGESTSIZE); } template DataEncryptor::DataEncryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment) : ProxyFilter(NULLPTR, 0, 0, attachment), m_passphrase(passphrase, passphraseLength) { CRYPTOPP_COMPILE_ASSERT((int)SALTLENGTH <= (int)DIGESTSIZE); CRYPTOPP_COMPILE_ASSERT((int)BLOCKSIZE <= (int)DIGESTSIZE); } template void DataEncryptor::FirstPut(const byte *) { SecByteBlock salt(DIGESTSIZE), keyCheck(DIGESTSIZE); H hash; // use hash(passphrase | time | clock) as salt hash.Update(m_passphrase, m_passphrase.size()); time_t t=time(NULLPTR); hash.Update((byte *)&t, sizeof(t)); clock_t c=clock(); hash.Update((byte *)&c, sizeof(c)); hash.Final(salt); // use hash(passphrase | salt) as key check hash.Update(m_passphrase, m_passphrase.size()); hash.Update(salt, SALTLENGTH); hash.Final(keyCheck); AttachedTransformation()->Put(salt, SALTLENGTH); // mash passphrase and salt together into key and IV SecByteBlock key(KEYLENGTH); SecByteBlock IV(BLOCKSIZE); GenerateKeyIV(m_passphrase, m_passphrase.size(), salt, SALTLENGTH, ITERATIONS, key, IV); m_cipher.SetKeyWithIV(key, key.size(), IV); SetFilter(new StreamTransformationFilter(m_cipher)); m_filter->Put(keyCheck, BLOCKSIZE); } template void DataEncryptor::LastPut(const byte *inString, size_t length) { CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); m_filter->MessageEnd(); } // ******************************************************** template DataDecryptor::DataDecryptor(const char *p, BufferedTransformation *attachment, bool throwException) : ProxyFilter(NULLPTR, EnumToInt(SALTLENGTH)+EnumToInt(BLOCKSIZE), 0, attachment) , m_state(WAITING_FOR_KEYCHECK) , m_passphrase((const byte *)p, strlen(p)) , m_throwException(throwException) { CRYPTOPP_COMPILE_ASSERT((int)SALTLENGTH <= (int)DIGESTSIZE); CRYPTOPP_COMPILE_ASSERT((int)BLOCKSIZE <= (int)DIGESTSIZE); } template DataDecryptor::DataDecryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment, bool throwException) : ProxyFilter(NULLPTR, EnumToInt(SALTLENGTH)+EnumToInt(BLOCKSIZE), 0, attachment) , m_state(WAITING_FOR_KEYCHECK) , m_passphrase(passphrase, passphraseLength) , m_throwException(throwException) { CRYPTOPP_COMPILE_ASSERT((int)SALTLENGTH <= (int)DIGESTSIZE); CRYPTOPP_COMPILE_ASSERT((int)BLOCKSIZE <= (int)DIGESTSIZE); } template void DataDecryptor::FirstPut(const byte *inString) { CheckKey(inString, inString+SALTLENGTH); } template void DataDecryptor::LastPut(const byte *inString, size_t length) { CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); if (m_filter.get() == NULLPTR) { m_state = KEY_BAD; if (m_throwException) throw KeyBadErr(); } else { m_filter->MessageEnd(); m_state = WAITING_FOR_KEYCHECK; } } template void DataDecryptor::CheckKey(const byte *salt, const byte *keyCheck) { SecByteBlock check(STDMAX((unsigned int)2*BLOCKSIZE, (unsigned int)DIGESTSIZE)); H hash; hash.Update(m_passphrase, m_passphrase.size()); hash.Update(salt, SALTLENGTH); hash.Final(check); SecByteBlock key(KEYLENGTH); SecByteBlock IV(BLOCKSIZE); GenerateKeyIV(m_passphrase, m_passphrase.size(), salt, SALTLENGTH, ITERATIONS, key, IV); m_cipher.SetKeyWithIV(key, key.size(), IV); member_ptr decryptor(new StreamTransformationFilter(m_cipher)); decryptor->Put(keyCheck, BLOCKSIZE); decryptor->ForceNextPut(); decryptor->Get(check+EnumToInt(BLOCKSIZE), BLOCKSIZE); SetFilter(decryptor.release()); if (!VerifyBufsEqual(check, check+EnumToInt(BLOCKSIZE), BLOCKSIZE)) { m_state = KEY_BAD; if (m_throwException) throw KeyBadErr(); } else m_state = KEY_GOOD; } // ******************************************************** template static MAC* NewDataEncryptorMAC(const byte *passphrase, size_t passphraseLength) { size_t macKeyLength = MAC::StaticGetValidKeyLength(16); SecByteBlock macKey(macKeyLength); // since the MAC is encrypted there is no reason to mash the passphrase for many iterations Mash(passphrase, passphraseLength, macKey, macKeyLength, 1); return new MAC(macKey, macKeyLength); } template DataEncryptorWithMAC::DataEncryptorWithMAC(const char *passphrase, BufferedTransformation *attachment) : ProxyFilter(NULLPTR, 0, 0, attachment) , m_mac(NewDataEncryptorMAC((const byte *)passphrase, strlen(passphrase))) { SetFilter(new HashFilter(*m_mac, new DataEncryptor(passphrase), true)); } template DataEncryptorWithMAC::DataEncryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment) : ProxyFilter(NULLPTR, 0, 0, attachment) , m_mac(NewDataEncryptorMAC(passphrase, passphraseLength)) { SetFilter(new HashFilter(*m_mac, new DataEncryptor(passphrase, passphraseLength), true)); } template void DataEncryptorWithMAC::LastPut(const byte *inString, size_t length) { CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); m_filter->MessageEnd(); } // ******************************************************** template DataDecryptorWithMAC::DataDecryptorWithMAC(const char *passphrase, BufferedTransformation *attachment, bool throwException) : ProxyFilter(NULLPTR, 0, 0, attachment) , m_mac(NewDataEncryptorMAC((const byte *)passphrase, strlen(passphrase))) , m_throwException(throwException) { SetFilter(new DataDecryptor(passphrase, m_hashVerifier=new HashVerificationFilter(*m_mac, NULLPTR, HashVerificationFilter::PUT_MESSAGE), throwException)); } template DataDecryptorWithMAC::DataDecryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment, bool throwException) : ProxyFilter(NULLPTR, 0, 0, attachment) , m_mac(NewDataEncryptorMAC(passphrase, passphraseLength)) , m_throwException(throwException) { SetFilter(new DataDecryptor(passphrase, passphraseLength, m_hashVerifier=new HashVerificationFilter(*m_mac, NULLPTR, HashVerificationFilter::PUT_MESSAGE), throwException)); } template typename DataDecryptor::State DataDecryptorWithMAC::CurrentState() const { return static_cast *>(m_filter.get())->CurrentState(); } template bool DataDecryptorWithMAC::CheckLastMAC() const { return m_hashVerifier->GetLastResult(); } template void DataDecryptorWithMAC::LastPut(const byte *inString, size_t length) { CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); m_filter->MessageEnd(); if (m_throwException && !CheckLastMAC()) throw MACBadErr(); } template struct DataParametersInfo; template struct DataParametersInfo; template class DataEncryptor; template class DataDecryptor; template class DataEncryptor; template class DataDecryptor; template class DataEncryptorWithMAC; template class DataDecryptorWithMAC; template class DataEncryptorWithMAC; template class DataDecryptorWithMAC; NAMESPACE_END