default.cpp
// default.cpp - 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 <time.h>
#include <memory>
NAMESPACE_BEGIN(CryptoPP)
static const unsigned int MASH_ITERATIONS = 200;
static const unsigned int SALTLENGTH = 8;
static const unsigned int BLOCKSIZE = DefaultBlockCipher::Encryption::BLOCKSIZE;
static const unsigned int KEYLENGTH = DefaultBlockCipher::Encryption::DEFAULT_KEYLENGTH;
// The purpose of this function Mash() is to take an arbitrary length input
// string and *deterministicly* 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.
static void Mash(const byte *in, size_t inLen, byte *out, size_t outLen, int iterations)
{
if (BytePrecision(outLen) > 2)
throw InvalidArgument("Mash: output legnth too large");
size_t bufSize = RoundUpToMultipleOf(outLen, (size_t)DefaultHashModule::DIGESTSIZE);
byte b[2];
SecByteBlock buf(bufSize);
SecByteBlock outBuf(bufSize);
DefaultHashModule hash;
unsigned int i;
for(i=0; i<outLen; i+=DefaultHashModule::DIGESTSIZE)
{
b[0] = (byte) (i >> 8);
b[1] = (byte) i;
hash.Update(b, 2);
hash.Update(in, inLen);
hash.Final(outBuf+i);
}
while (iterations-- > 1)
{
memcpy(buf, outBuf, bufSize);
for (i=0; i<bufSize; i+=DefaultHashModule::DIGESTSIZE)
{
b[0] = (byte) (i >> 8);
b[1] = (byte) i;
hash.Update(b, 2);
hash.Update(buf, bufSize);
hash.Final(outBuf+i);
}
}
memcpy(out, outBuf, outLen);
}
static void GenerateKeyIV(const byte *passphrase, size_t passphraseLength, const byte *salt, size_t saltLength, byte *key, byte *IV)
{
SecByteBlock temp(passphraseLength+saltLength);
memcpy(temp, passphrase, passphraseLength);
memcpy(temp+passphraseLength, salt, saltLength);
SecByteBlock keyIV(KEYLENGTH+BLOCKSIZE);
Mash(temp, passphraseLength + saltLength, keyIV, KEYLENGTH+BLOCKSIZE, MASH_ITERATIONS);
memcpy(key, keyIV, KEYLENGTH);
memcpy(IV, keyIV+KEYLENGTH, BLOCKSIZE);
}
// ********************************************************
DefaultEncryptor::DefaultEncryptor(const char *passphrase, BufferedTransformation *attachment)
: ProxyFilter(NULL, 0, 0, attachment), m_passphrase((const byte *)passphrase, strlen(passphrase))
{
}
DefaultEncryptor::DefaultEncryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment)
: ProxyFilter(NULL, 0, 0, attachment), m_passphrase(passphrase, passphraseLength)
{
}
void DefaultEncryptor::FirstPut(const byte *)
{
// VC60 workaround: __LINE__ expansion bug
CRYPTOPP_COMPILE_ASSERT_INSTANCE(SALTLENGTH <= DefaultHashModule::DIGESTSIZE, 1);
CRYPTOPP_COMPILE_ASSERT_INSTANCE(BLOCKSIZE <= DefaultHashModule::DIGESTSIZE, 2);
SecByteBlock salt(DefaultHashModule::DIGESTSIZE), keyCheck(DefaultHashModule::DIGESTSIZE);
DefaultHashModule hash;
// use hash(passphrase | time | clock) as salt
hash.Update(m_passphrase, m_passphrase.size());
time_t t=time(0);
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, key, IV);
m_cipher.SetKeyWithIV(key, key.size(), IV);
SetFilter(new StreamTransformationFilter(m_cipher));
m_filter->Put(keyCheck, BLOCKSIZE);
}
void DefaultEncryptor::LastPut(const byte *inString, size_t length)
{
CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);
m_filter->MessageEnd();
}
// ********************************************************
DefaultDecryptor::DefaultDecryptor(const char *p, BufferedTransformation *attachment, bool throwException)
: ProxyFilter(NULL, SALTLENGTH+BLOCKSIZE, 0, attachment)
, m_state(WAITING_FOR_KEYCHECK)
, m_passphrase((const byte *)p, strlen(p))
, m_throwException(throwException)
{
}
DefaultDecryptor::DefaultDecryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment, bool throwException)
: ProxyFilter(NULL, SALTLENGTH+BLOCKSIZE, 0, attachment)
, m_state(WAITING_FOR_KEYCHECK)
, m_passphrase(passphrase, passphraseLength)
, m_throwException(throwException)
{
}
void DefaultDecryptor::FirstPut(const byte *inString)
{
CheckKey(inString, inString+SALTLENGTH);
}
void DefaultDecryptor::LastPut(const byte *inString, size_t length)
{
CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);
if (m_filter.get() == NULL)
{
m_state = KEY_BAD;
if (m_throwException)
throw KeyBadErr();
}
else
{
m_filter->MessageEnd();
m_state = WAITING_FOR_KEYCHECK;
}
}
void DefaultDecryptor::CheckKey(const byte *salt, const byte *keyCheck)
{
SecByteBlock check(STDMAX((unsigned int)2*BLOCKSIZE, (unsigned int)DefaultHashModule::DIGESTSIZE));
DefaultHashModule 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, key, IV);
m_cipher.SetKeyWithIV(key, key.size(), IV);
member_ptr<StreamTransformationFilter> decryptor(new StreamTransformationFilter(m_cipher));
decryptor->Put(keyCheck, BLOCKSIZE);
decryptor->ForceNextPut();
decryptor->Get(check+BLOCKSIZE, BLOCKSIZE);
SetFilter(decryptor.release());
if (!VerifyBufsEqual(check, check+BLOCKSIZE, BLOCKSIZE))
{
m_state = KEY_BAD;
if (m_throwException)
throw KeyBadErr();
}
else
m_state = KEY_GOOD;
}
// ********************************************************
static DefaultMAC * NewDefaultEncryptorMAC(const byte *passphrase, size_t passphraseLength)
{
size_t macKeyLength = DefaultMAC::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 DefaultMAC(macKey, macKeyLength);
}
DefaultEncryptorWithMAC::DefaultEncryptorWithMAC(const char *passphrase, BufferedTransformation *attachment)
: ProxyFilter(NULL, 0, 0, attachment)
, m_mac(NewDefaultEncryptorMAC((const byte *)passphrase, strlen(passphrase)))
{
SetFilter(new HashFilter(*m_mac, new DefaultEncryptor(passphrase), true));
}
DefaultEncryptorWithMAC::DefaultEncryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment)
: ProxyFilter(NULL, 0, 0, attachment)
, m_mac(NewDefaultEncryptorMAC(passphrase, passphraseLength))
{
SetFilter(new HashFilter(*m_mac, new DefaultEncryptor(passphrase, passphraseLength), true));
}
void DefaultEncryptorWithMAC::LastPut(const byte *inString, size_t length)
{
CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);
m_filter->MessageEnd();
}
// ********************************************************
DefaultDecryptorWithMAC::DefaultDecryptorWithMAC(const char *passphrase, BufferedTransformation *attachment, bool throwException)
: ProxyFilter(NULL, 0, 0, attachment)
, m_mac(NewDefaultEncryptorMAC((const byte *)passphrase, strlen(passphrase)))
, m_throwException(throwException)
{
SetFilter(new DefaultDecryptor(passphrase, m_hashVerifier=new HashVerifier(*m_mac, NULL, HashVerifier::PUT_MESSAGE), throwException));
}
DefaultDecryptorWithMAC::DefaultDecryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment, bool throwException)
: ProxyFilter(NULL, 0, 0, attachment)
, m_mac(NewDefaultEncryptorMAC(passphrase, passphraseLength))
, m_throwException(throwException)
{
SetFilter(new DefaultDecryptor(passphrase, passphraseLength, m_hashVerifier=new HashVerifier(*m_mac, NULL, HashVerifier::PUT_MESSAGE), throwException));
}
DefaultDecryptor::State DefaultDecryptorWithMAC::CurrentState() const
{
return static_cast<const DefaultDecryptor *>(m_filter.get())->CurrentState();
}
bool DefaultDecryptorWithMAC::CheckLastMAC() const
{
return m_hashVerifier->GetLastResult();
}
void DefaultDecryptorWithMAC::LastPut(const byte *inString, size_t length)
{
CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);
m_filter->MessageEnd();
if (m_throwException && !CheckLastMAC())
throw MACBadErr();
}
NAMESPACE_END
InvalidArgument
An invalid argument was detected.
Definition: cryptlib.h:182
ProxyFilter
Base class for Filter classes that are proxies for a chain of other filters.
Definition: filters.h:885
DefaultEncryptor
Password-Based Encryptor using TripleDES.
Definition: default.h:29
BytePrecision
unsigned int BytePrecision(const T &value)
Returns the number of 8-bit bytes or octets required for a value.
Definition: misc.h:623
cryptlib.h
Abstract base classes that provide a uniform interface to this library.
smartptr.h
Classes for automatic resource management.
default.h
Classes for DefaultEncryptor, DefaultDecryptor, DefaultEncryptorWithMAC and DefaultDecryptorWithMAC.
config.h
Library configuration file.
SecByteBlock
SecBlock<byte> typedef.
Definition: secblock.h:731
VariableKeyLength< 16, 0, INT_MAX >::StaticGetValidKeyLength
static size_t StaticGetValidKeyLength(size_t keylength)
Provides a valid key length for the algorithm provided by a static function.
Definition: seckey.h:216
DefaultDecryptor::KeyBadErr
Definition: default.h:79
BufferedTransformation
Interface for buffered transformations.
Definition: cryptlib.h:1352
DefaultDecryptorWithMAC::MACBadErr
Excpetion thrown when an incorrect MAC is encountered.
Definition: default.h:146
DefaultDecryptor
Password-Based Decryptor using TripleDES.
Definition: default.h:57
member_ptr
Pointer that overloads operator ->
Definition: smartptr.h:39
DefaultDecryptor::DefaultDecryptor
DefaultDecryptor(const char *passphrase, BufferedTransformation *attachment=NULL, bool throwException=true)
Constructs a DefaultDecryptor.
Definition: default.cpp:136
DefaultMAC
HMAC< DefaultHashModule > DefaultMAC
Default HMAC for use withDefaultEncryptorWithMAC and DefaultDecryptorWithMAC.
Definition: default.h:23
queue.h
Classes for an unlimited queue to store bytes.
HashVerificationFilter
Filter wrapper for HashTransformation.
Definition: filters.h:535
HashFilter
Filter wrapper for HashTransformation.
Definition: filters.h:508
BufferedTransformation::Put
size_t Put(byte inByte, bool blocking=true)
Input a byte for processing.
Definition: cryptlib.h:1378
Filter::AttachedTransformation
BufferedTransformation * AttachedTransformation()
Retrieve attached transformation.
Definition: filters.cpp:36
HashVerificationFilter::PUT_MESSAGE
Indicates the message should be passed to an attached transformation.
Definition: filters.h:556
SHA1
SHA-1
Definition: sha.h:21
filters.h
Implementation of BufferedTransformation&#39;s attachment interface.
Name::IV
const char * IV()
ConstByteArrayParameter, also accepts const byte * for backwards compatibility.
Definition: argnames.h:21
StreamTransformationFilter
Filter wrapper for StreamTransformation.
Definition: filters.h:476
HMAC
HMAC.
Definition: hmac.h:50
DefaultEncryptor::DefaultEncryptor
DefaultEncryptor(const char *passphrase, BufferedTransformation *attachment=NULL)
Construct a DefaultEncryptor.
Definition: default.cpp:82
FilterWithBufferedInput::ForceNextPut
void ForceNextPut()
Definition: filters.cpp:448
VerifyBufsEqual
bool VerifyBufsEqual(const byte *buf1, const byte *buf2, size_t count)
Performs a near constant-time comparison of two equally sized buffers.
Definition: misc.cpp:96
RoundUpToMultipleOf
T1 RoundUpToMultipleOf(const T1 &n, const T2 &m)
Rounds a value up to a multiple of a second value.
Definition: misc.h:865
STDMAX
const T & STDMAX(const T &a, const T &b)
Replacement function for std::max.
Definition: misc.h:477
BufferedTransformation::Get
virtual size_t Get(byte &outByte)
Retrieve a 8-bit byte.
Definition: cryptlib.cpp:519
CryptoPP
Crypto++ library namespace.
HashTransformation::Final
virtual void Final(byte *digest)
Computes the hash of the current message.
Definition: cryptlib.h:954
ProxyFilter::SetFilter
void SetFilter(Filter *filter)
Sets the OutputProxy filter.
Definition: filters.cpp:503
DefaultDecryptorWithMAC::DefaultDecryptorWithMAC
DefaultDecryptorWithMAC(const char *passphrase, BufferedTransformation *attachment=NULL, bool throwException=true)
Constructs a DefaultDecryptor.
Definition: default.cpp:238
SecBlock::size
size_type size() const
Provides the count of elements in the SecBlock.
Definition: secblock.h:524
DefaultEncryptorWithMAC::DefaultEncryptorWithMAC
DefaultEncryptorWithMAC(const char *passphrase, BufferedTransformation *attachment=NULL)
Constructs a DefaultEncryptorWithMAC.
Definition: default.cpp:216