ext-cryptopp/default.cpp

308 lines
11 KiB
C++
Raw Normal View History

// default.cpp - originally written and placed in the public domain by Wei Dai
2015-11-05 06:59:46 +00:00
#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 <time.h>
#include <memory>
NAMESPACE_BEGIN(CryptoPP)
// The purpose of this function Mash() is to take an arbitrary length input
2022-01-04 10:06:35 +00:00
// string and *deterministically* produce an arbitrary length output string such
2015-11-05 06:59:46 +00:00
// 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 <class H>
2015-11-05 06:59:46 +00:00
static void Mash(const byte *in, size_t inLen, byte *out, size_t outLen, int iterations)
{
if (BytePrecision(outLen) > 2)
2022-01-04 10:06:35 +00:00
throw InvalidArgument("Mash: output length too large");
2015-11-05 06:59:46 +00:00
size_t bufSize = RoundUpToMultipleOf(outLen, (size_t)H::DIGESTSIZE);
2015-11-05 06:59:46 +00:00
byte b[2];
SecByteBlock buf(bufSize);
SecByteBlock outBuf(bufSize);
H hash;
2015-11-05 06:59:46 +00:00
unsigned int i;
for(i=0; i<outLen; i+=H::DIGESTSIZE)
2015-11-05 06:59:46 +00:00
{
b[0] = (byte) (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<bufSize; i+=H::DIGESTSIZE)
2015-11-05 06:59:46 +00:00
{
b[0] = (byte) (i >> 8);
b[1] = (byte) i;
hash.Update(b, 2);
hash.Update(buf, bufSize);
hash.Final(outBuf+i);
}
}
std::memcpy(out, outBuf, outLen);
2015-11-05 06:59:46 +00:00
}
template <class BC, class H, class Info>
static void GenerateKeyIV(const byte *passphrase, size_t passphraseLength, const byte *salt, size_t saltLength, unsigned int iterations, byte *key, byte *IV)
2015-11-05 06:59:46 +00:00
{
// 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<H>(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);
2015-11-05 06:59:46 +00:00
}
// ********************************************************
template <class BC, class H, class Info>
DataEncryptor<BC,H,Info>::DataEncryptor(const char *passphrase, BufferedTransformation *attachment)
2017-03-01 11:10:06 +00:00
: ProxyFilter(NULLPTR, 0, 0, attachment), m_passphrase((const byte *)passphrase, strlen(passphrase))
2015-11-05 06:59:46 +00:00
{
2017-08-11 21:15:13 +00:00
CRYPTOPP_COMPILE_ASSERT((int)SALTLENGTH <= DIGESTSIZE);
CRYPTOPP_COMPILE_ASSERT((int)BLOCKSIZE <= (int)DIGESTSIZE);
2015-11-05 06:59:46 +00:00
}
template <class BC, class H, class Info>
DataEncryptor<BC,H,Info>::DataEncryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment)
2017-03-01 11:10:06 +00:00
: ProxyFilter(NULLPTR, 0, 0, attachment), m_passphrase(passphrase, passphraseLength)
2015-11-05 06:59:46 +00:00
{
2017-08-11 21:15:13 +00:00
CRYPTOPP_COMPILE_ASSERT((int)SALTLENGTH <= (int)DIGESTSIZE);
CRYPTOPP_COMPILE_ASSERT((int)BLOCKSIZE <= (int)DIGESTSIZE);
2015-11-05 06:59:46 +00:00
}
template <class BC, class H, class Info>
void DataEncryptor<BC,H,Info>::FirstPut(const byte *)
2015-11-05 06:59:46 +00:00
{
SecByteBlock salt(DIGESTSIZE), keyCheck(DIGESTSIZE);
H hash;
2015-11-05 06:59:46 +00:00
// use hash(passphrase | time | clock) as salt
hash.Update(m_passphrase, m_passphrase.size());
2017-03-01 11:10:06 +00:00
time_t t=time(NULLPTR);
2015-11-05 06:59:46 +00:00
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<BC,H,Info>(m_passphrase, m_passphrase.size(), salt, SALTLENGTH, ITERATIONS, key, IV);
2015-11-05 06:59:46 +00:00
m_cipher.SetKeyWithIV(key, key.size(), IV);
SetFilter(new StreamTransformationFilter(m_cipher));
m_filter->Put(keyCheck, BLOCKSIZE);
}
template <class BC, class H, class Info>
void DataEncryptor<BC,H,Info>::LastPut(const byte *inString, size_t length)
2015-11-05 06:59:46 +00:00
{
CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);
m_filter->MessageEnd();
}
// ********************************************************
template <class BC, class H, class Info>
DataDecryptor<BC,H,Info>::DataDecryptor(const char *p, BufferedTransformation *attachment, bool throwException)
: ProxyFilter(NULLPTR, EnumToInt(SALTLENGTH)+EnumToInt(BLOCKSIZE), 0, attachment)
2015-11-05 06:59:46 +00:00
, m_state(WAITING_FOR_KEYCHECK)
, m_passphrase((const byte *)p, strlen(p))
, m_throwException(throwException)
{
2017-08-11 21:15:13 +00:00
CRYPTOPP_COMPILE_ASSERT((int)SALTLENGTH <= (int)DIGESTSIZE);
CRYPTOPP_COMPILE_ASSERT((int)BLOCKSIZE <= (int)DIGESTSIZE);
2015-11-05 06:59:46 +00:00
}
template <class BC, class H, class Info>
DataDecryptor<BC,H,Info>::DataDecryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment, bool throwException)
: ProxyFilter(NULLPTR, EnumToInt(SALTLENGTH)+EnumToInt(BLOCKSIZE), 0, attachment)
2015-11-05 06:59:46 +00:00
, m_state(WAITING_FOR_KEYCHECK)
, m_passphrase(passphrase, passphraseLength)
, m_throwException(throwException)
{
2017-08-11 21:15:13 +00:00
CRYPTOPP_COMPILE_ASSERT((int)SALTLENGTH <= (int)DIGESTSIZE);
CRYPTOPP_COMPILE_ASSERT((int)BLOCKSIZE <= (int)DIGESTSIZE);
2015-11-05 06:59:46 +00:00
}
template <class BC, class H, class Info>
void DataDecryptor<BC,H,Info>::FirstPut(const byte *inString)
2015-11-05 06:59:46 +00:00
{
CheckKey(inString, inString+SALTLENGTH);
}
template <class BC, class H, class Info>
void DataDecryptor<BC,H,Info>::LastPut(const byte *inString, size_t length)
2015-11-05 06:59:46 +00:00
{
CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);
2017-03-01 11:10:06 +00:00
if (m_filter.get() == NULLPTR)
2015-11-05 06:59:46 +00:00
{
m_state = KEY_BAD;
if (m_throwException)
throw KeyBadErr();
}
else
{
m_filter->MessageEnd();
m_state = WAITING_FOR_KEYCHECK;
}
}
template <class BC, class H, class Info>
void DataDecryptor<BC,H,Info>::CheckKey(const byte *salt, const byte *keyCheck)
2015-11-05 06:59:46 +00:00
{
SecByteBlock check(STDMAX((unsigned int)2*BLOCKSIZE, (unsigned int)DIGESTSIZE));
2015-11-05 06:59:46 +00:00
H hash;
2015-11-05 06:59:46 +00:00
hash.Update(m_passphrase, m_passphrase.size());
hash.Update(salt, SALTLENGTH);
hash.Final(check);
SecByteBlock key(KEYLENGTH);
SecByteBlock IV(BLOCKSIZE);
GenerateKeyIV<BC,H,Info>(m_passphrase, m_passphrase.size(), salt, SALTLENGTH, ITERATIONS, key, IV);
2015-11-05 06:59:46 +00:00
m_cipher.SetKeyWithIV(key, key.size(), IV);
member_ptr<StreamTransformationFilter> decryptor(new StreamTransformationFilter(m_cipher));
decryptor->Put(keyCheck, BLOCKSIZE);
decryptor->ForceNextPut();
decryptor->Get(check+EnumToInt(BLOCKSIZE), BLOCKSIZE);
2015-11-05 06:59:46 +00:00
SetFilter(decryptor.release());
if (!VerifyBufsEqual(check, check+EnumToInt(BLOCKSIZE), BLOCKSIZE))
2015-11-05 06:59:46 +00:00
{
m_state = KEY_BAD;
if (m_throwException)
throw KeyBadErr();
}
else
m_state = KEY_GOOD;
}
// ********************************************************
template <class H, class MAC>
static MAC* NewDataEncryptorMAC(const byte *passphrase, size_t passphraseLength)
2015-11-05 06:59:46 +00:00
{
size_t macKeyLength = MAC::StaticGetValidKeyLength(16);
SecByteBlock macKey(macKeyLength);
2015-11-05 06:59:46 +00:00
// since the MAC is encrypted there is no reason to mash the passphrase for many iterations
Mash<H>(passphrase, passphraseLength, macKey, macKeyLength, 1);
return new MAC(macKey, macKeyLength);
2015-11-05 06:59:46 +00:00
}
template <class BC, class H, class MAC, class Info>
DataEncryptorWithMAC<BC,H,MAC,Info>::DataEncryptorWithMAC(const char *passphrase, BufferedTransformation *attachment)
2017-03-01 11:10:06 +00:00
: ProxyFilter(NULLPTR, 0, 0, attachment)
, m_mac(NewDataEncryptorMAC<H,MAC>((const byte *)passphrase, strlen(passphrase)))
2015-11-05 06:59:46 +00:00
{
SetFilter(new HashFilter(*m_mac, new DataEncryptor<BC,H,Info>(passphrase), true));
2015-11-05 06:59:46 +00:00
}
template <class BC, class H, class MAC, class Info>
DataEncryptorWithMAC<BC,H,MAC,Info>::DataEncryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment)
2017-03-01 11:10:06 +00:00
: ProxyFilter(NULLPTR, 0, 0, attachment)
, m_mac(NewDataEncryptorMAC<H,MAC>(passphrase, passphraseLength))
2015-11-05 06:59:46 +00:00
{
SetFilter(new HashFilter(*m_mac, new DataEncryptor<BC,H,Info>(passphrase, passphraseLength), true));
2015-11-05 06:59:46 +00:00
}
template <class BC, class H, class MAC, class Info>
void DataEncryptorWithMAC<BC,H,MAC,Info>::LastPut(const byte *inString, size_t length)
2015-11-05 06:59:46 +00:00
{
CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);
m_filter->MessageEnd();
}
// ********************************************************
template <class BC, class H, class MAC, class Info>
DataDecryptorWithMAC<BC,H,MAC,Info>::DataDecryptorWithMAC(const char *passphrase, BufferedTransformation *attachment, bool throwException)
2017-03-01 11:10:06 +00:00
: ProxyFilter(NULLPTR, 0, 0, attachment)
, m_mac(NewDataEncryptorMAC<H,MAC>((const byte *)passphrase, strlen(passphrase)))
2015-11-05 06:59:46 +00:00
, m_throwException(throwException)
{
2017-03-01 11:10:06 +00:00
SetFilter(new DataDecryptor<BC,H,Info>(passphrase, m_hashVerifier=new HashVerificationFilter(*m_mac, NULLPTR, HashVerificationFilter::PUT_MESSAGE), throwException));
2015-11-05 06:59:46 +00:00
}
template <class BC, class H, class MAC, class Info>
DataDecryptorWithMAC<BC,H,MAC,Info>::DataDecryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment, bool throwException)
2017-03-01 11:10:06 +00:00
: ProxyFilter(NULLPTR, 0, 0, attachment)
, m_mac(NewDataEncryptorMAC<H,MAC>(passphrase, passphraseLength))
2015-11-05 06:59:46 +00:00
, m_throwException(throwException)
{
2017-03-01 11:10:06 +00:00
SetFilter(new DataDecryptor<BC,H,Info>(passphrase, passphraseLength, m_hashVerifier=new HashVerificationFilter(*m_mac, NULLPTR, HashVerificationFilter::PUT_MESSAGE), throwException));
2015-11-05 06:59:46 +00:00
}
template <class BC, class H, class MAC, class Info>
typename DataDecryptor<BC,H,Info>::State DataDecryptorWithMAC<BC,H,MAC,Info>::CurrentState() const
2015-11-05 06:59:46 +00:00
{
return static_cast<const DataDecryptor<BC,H,Info> *>(m_filter.get())->CurrentState();
2015-11-05 06:59:46 +00:00
}
template <class BC, class H, class MAC, class Info>
bool DataDecryptorWithMAC<BC,H,MAC,Info>::CheckLastMAC() const
2015-11-05 06:59:46 +00:00
{
return m_hashVerifier->GetLastResult();
}
template <class BC, class H, class MAC, class Info>
void DataDecryptorWithMAC<BC,H,MAC,Info>::LastPut(const byte *inString, size_t length)
2015-11-05 06:59:46 +00:00
{
CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);
m_filter->MessageEnd();
if (m_throwException && !CheckLastMAC())
throw MACBadErr();
}
2016-12-11 11:44:18 +00:00
template struct DataParametersInfo<LegacyBlockCipher::BLOCKSIZE, LegacyBlockCipher::DEFAULT_KEYLENGTH, LegacyHashModule::DIGESTSIZE, 8, 200>;
template struct DataParametersInfo<DefaultBlockCipher::BLOCKSIZE, DefaultBlockCipher::DEFAULT_KEYLENGTH, DefaultHashModule::DIGESTSIZE, 8, 2500>;
template class DataEncryptor<LegacyBlockCipher,LegacyHashModule,LegacyParametersInfo>;
template class DataDecryptor<LegacyBlockCipher,LegacyHashModule,LegacyParametersInfo>;
template class DataEncryptor<DefaultBlockCipher,DefaultHashModule,DefaultParametersInfo>;
template class DataDecryptor<DefaultBlockCipher,DefaultHashModule,DefaultParametersInfo>;
template class DataEncryptorWithMAC<LegacyBlockCipher,LegacyHashModule,LegacyMAC,LegacyParametersInfo>;
template class DataDecryptorWithMAC<LegacyBlockCipher,LegacyHashModule,LegacyMAC,LegacyParametersInfo>;
template class DataEncryptorWithMAC<DefaultBlockCipher,DefaultHashModule,DefaultMAC,DefaultParametersInfo>;
template class DataDecryptorWithMAC<DefaultBlockCipher,DefaultHashModule,DefaultMAC,DefaultParametersInfo>;
2015-11-23 00:17:15 +00:00
NAMESPACE_END