Path: blob/a-new-beginning/SharedDependencies/Sources/cryptopp/default.cpp
2 views
// default.cpp - originally written and placed in the public domain by Wei Dai12#include "pch.h"3#include "config.h"45#if CRYPTOPP_MSC_VERSION6# pragma warning(disable: 4127 4189)7#endif89#include "cryptlib.h"10#include "filters.h"11#include "smartptr.h"12#include "default.h"13#include "queue.h"1415#include <time.h>16#include <memory>1718NAMESPACE_BEGIN(CryptoPP)1920// The purpose of this function Mash() is to take an arbitrary length input21// string and *deterministically* produce an arbitrary length output string such22// that (1) it looks random, (2) no information about the input is23// deducible from it, and (3) it contains as much entropy as it can hold, or24// the amount of entropy in the input string, whichever is smaller.2526template <class H>27static void Mash(const byte *in, size_t inLen, byte *out, size_t outLen, int iterations)28{29if (BytePrecision(outLen) > 2)30throw InvalidArgument("Mash: output length too large");3132size_t bufSize = RoundUpToMultipleOf(outLen, (size_t)H::DIGESTSIZE);33byte b[2];34SecByteBlock buf(bufSize);35SecByteBlock outBuf(bufSize);36H hash;3738unsigned int i;39for(i=0; i<outLen; i+=H::DIGESTSIZE)40{41b[0] = (byte) (i >> 8);42b[1] = (byte) i;43hash.Update(b, 2);44hash.Update(in, inLen);45hash.Final(outBuf+i);46}4748while (iterations-- > 1)49{50std::memcpy(buf, outBuf, bufSize);51for (i=0; i<bufSize; i+=H::DIGESTSIZE)52{53b[0] = (byte) (i >> 8);54b[1] = (byte) i;55hash.Update(b, 2);56hash.Update(buf, bufSize);57hash.Final(outBuf+i);58}59}6061std::memcpy(out, outBuf, outLen);62}6364template <class BC, class H, class Info>65static void GenerateKeyIV(const byte *passphrase, size_t passphraseLength, const byte *salt, size_t saltLength, unsigned int iterations, byte *key, byte *IV)66{67// UBsan. User supplied params, may be NULL68SecByteBlock temp(passphraseLength+saltLength);69if (passphrase != NULLPTR)70std::memcpy(temp, passphrase, passphraseLength);71if (salt != NULLPTR)72std::memcpy(temp+passphraseLength, salt, saltLength);7374// OK. Derived params, cannot be NULL75SecByteBlock keyIV(EnumToInt(Info::KEYLENGTH)+EnumToInt(+Info::BLOCKSIZE));76Mash<H>(temp, passphraseLength + saltLength, keyIV, EnumToInt(Info::KEYLENGTH)+EnumToInt(+Info::BLOCKSIZE), iterations);77std::memcpy(key, keyIV, Info::KEYLENGTH);78std::memcpy(IV, keyIV+Info::KEYLENGTH, Info::BLOCKSIZE);79}8081// ********************************************************8283template <class BC, class H, class Info>84DataEncryptor<BC,H,Info>::DataEncryptor(const char *passphrase, BufferedTransformation *attachment)85: ProxyFilter(NULLPTR, 0, 0, attachment), m_passphrase((const byte *)passphrase, strlen(passphrase))86{87CRYPTOPP_COMPILE_ASSERT((int)SALTLENGTH <= DIGESTSIZE);88CRYPTOPP_COMPILE_ASSERT((int)BLOCKSIZE <= (int)DIGESTSIZE);89}9091template <class BC, class H, class Info>92DataEncryptor<BC,H,Info>::DataEncryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment)93: ProxyFilter(NULLPTR, 0, 0, attachment), m_passphrase(passphrase, passphraseLength)94{95CRYPTOPP_COMPILE_ASSERT((int)SALTLENGTH <= (int)DIGESTSIZE);96CRYPTOPP_COMPILE_ASSERT((int)BLOCKSIZE <= (int)DIGESTSIZE);97}9899template <class BC, class H, class Info>100void DataEncryptor<BC,H,Info>::FirstPut(const byte *)101{102SecByteBlock salt(DIGESTSIZE), keyCheck(DIGESTSIZE);103H hash;104105// use hash(passphrase | time | clock) as salt106hash.Update(m_passphrase, m_passphrase.size());107time_t t=time(NULLPTR);108hash.Update((byte *)&t, sizeof(t));109clock_t c=clock();110hash.Update((byte *)&c, sizeof(c));111hash.Final(salt);112113// use hash(passphrase | salt) as key check114hash.Update(m_passphrase, m_passphrase.size());115hash.Update(salt, SALTLENGTH);116hash.Final(keyCheck);117118AttachedTransformation()->Put(salt, SALTLENGTH);119120// mash passphrase and salt together into key and IV121SecByteBlock key(KEYLENGTH);122SecByteBlock IV(BLOCKSIZE);123GenerateKeyIV<BC,H,Info>(m_passphrase, m_passphrase.size(), salt, SALTLENGTH, ITERATIONS, key, IV);124125m_cipher.SetKeyWithIV(key, key.size(), IV);126SetFilter(new StreamTransformationFilter(m_cipher));127128m_filter->Put(keyCheck, BLOCKSIZE);129}130131template <class BC, class H, class Info>132void DataEncryptor<BC,H,Info>::LastPut(const byte *inString, size_t length)133{134CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);135m_filter->MessageEnd();136}137138// ********************************************************139140template <class BC, class H, class Info>141DataDecryptor<BC,H,Info>::DataDecryptor(const char *p, BufferedTransformation *attachment, bool throwException)142: ProxyFilter(NULLPTR, EnumToInt(SALTLENGTH)+EnumToInt(BLOCKSIZE), 0, attachment)143, m_state(WAITING_FOR_KEYCHECK)144, m_passphrase((const byte *)p, strlen(p))145, m_throwException(throwException)146{147CRYPTOPP_COMPILE_ASSERT((int)SALTLENGTH <= (int)DIGESTSIZE);148CRYPTOPP_COMPILE_ASSERT((int)BLOCKSIZE <= (int)DIGESTSIZE);149}150151template <class BC, class H, class Info>152DataDecryptor<BC,H,Info>::DataDecryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment, bool throwException)153: ProxyFilter(NULLPTR, EnumToInt(SALTLENGTH)+EnumToInt(BLOCKSIZE), 0, attachment)154, m_state(WAITING_FOR_KEYCHECK)155, m_passphrase(passphrase, passphraseLength)156, m_throwException(throwException)157{158CRYPTOPP_COMPILE_ASSERT((int)SALTLENGTH <= (int)DIGESTSIZE);159CRYPTOPP_COMPILE_ASSERT((int)BLOCKSIZE <= (int)DIGESTSIZE);160}161162template <class BC, class H, class Info>163void DataDecryptor<BC,H,Info>::FirstPut(const byte *inString)164{165CheckKey(inString, inString+SALTLENGTH);166}167168template <class BC, class H, class Info>169void DataDecryptor<BC,H,Info>::LastPut(const byte *inString, size_t length)170{171CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);172if (m_filter.get() == NULLPTR)173{174m_state = KEY_BAD;175if (m_throwException)176throw KeyBadErr();177}178else179{180m_filter->MessageEnd();181m_state = WAITING_FOR_KEYCHECK;182}183}184185template <class BC, class H, class Info>186void DataDecryptor<BC,H,Info>::CheckKey(const byte *salt, const byte *keyCheck)187{188SecByteBlock check(STDMAX((unsigned int)2*BLOCKSIZE, (unsigned int)DIGESTSIZE));189190H hash;191hash.Update(m_passphrase, m_passphrase.size());192hash.Update(salt, SALTLENGTH);193hash.Final(check);194195SecByteBlock key(KEYLENGTH);196SecByteBlock IV(BLOCKSIZE);197GenerateKeyIV<BC,H,Info>(m_passphrase, m_passphrase.size(), salt, SALTLENGTH, ITERATIONS, key, IV);198199m_cipher.SetKeyWithIV(key, key.size(), IV);200member_ptr<StreamTransformationFilter> decryptor(new StreamTransformationFilter(m_cipher));201202decryptor->Put(keyCheck, BLOCKSIZE);203decryptor->ForceNextPut();204decryptor->Get(check+EnumToInt(BLOCKSIZE), BLOCKSIZE);205206SetFilter(decryptor.release());207208if (!VerifyBufsEqual(check, check+EnumToInt(BLOCKSIZE), BLOCKSIZE))209{210m_state = KEY_BAD;211if (m_throwException)212throw KeyBadErr();213}214else215m_state = KEY_GOOD;216}217218// ********************************************************219220template <class H, class MAC>221static MAC* NewDataEncryptorMAC(const byte *passphrase, size_t passphraseLength)222{223size_t macKeyLength = MAC::StaticGetValidKeyLength(16);224SecByteBlock macKey(macKeyLength);225// since the MAC is encrypted there is no reason to mash the passphrase for many iterations226Mash<H>(passphrase, passphraseLength, macKey, macKeyLength, 1);227return new MAC(macKey, macKeyLength);228}229230template <class BC, class H, class MAC, class Info>231DataEncryptorWithMAC<BC,H,MAC,Info>::DataEncryptorWithMAC(const char *passphrase, BufferedTransformation *attachment)232: ProxyFilter(NULLPTR, 0, 0, attachment)233, m_mac(NewDataEncryptorMAC<H,MAC>((const byte *)passphrase, strlen(passphrase)))234{235SetFilter(new HashFilter(*m_mac, new DataEncryptor<BC,H,Info>(passphrase), true));236}237238template <class BC, class H, class MAC, class Info>239DataEncryptorWithMAC<BC,H,MAC,Info>::DataEncryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment)240: ProxyFilter(NULLPTR, 0, 0, attachment)241, m_mac(NewDataEncryptorMAC<H,MAC>(passphrase, passphraseLength))242{243SetFilter(new HashFilter(*m_mac, new DataEncryptor<BC,H,Info>(passphrase, passphraseLength), true));244}245246template <class BC, class H, class MAC, class Info>247void DataEncryptorWithMAC<BC,H,MAC,Info>::LastPut(const byte *inString, size_t length)248{249CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);250m_filter->MessageEnd();251}252253// ********************************************************254255template <class BC, class H, class MAC, class Info>256DataDecryptorWithMAC<BC,H,MAC,Info>::DataDecryptorWithMAC(const char *passphrase, BufferedTransformation *attachment, bool throwException)257: ProxyFilter(NULLPTR, 0, 0, attachment)258, m_mac(NewDataEncryptorMAC<H,MAC>((const byte *)passphrase, strlen(passphrase)))259, m_throwException(throwException)260{261SetFilter(new DataDecryptor<BC,H,Info>(passphrase, m_hashVerifier=new HashVerificationFilter(*m_mac, NULLPTR, HashVerificationFilter::PUT_MESSAGE), throwException));262}263264template <class BC, class H, class MAC, class Info>265DataDecryptorWithMAC<BC,H,MAC,Info>::DataDecryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment, bool throwException)266: ProxyFilter(NULLPTR, 0, 0, attachment)267, m_mac(NewDataEncryptorMAC<H,MAC>(passphrase, passphraseLength))268, m_throwException(throwException)269{270SetFilter(new DataDecryptor<BC,H,Info>(passphrase, passphraseLength, m_hashVerifier=new HashVerificationFilter(*m_mac, NULLPTR, HashVerificationFilter::PUT_MESSAGE), throwException));271}272273template <class BC, class H, class MAC, class Info>274typename DataDecryptor<BC,H,Info>::State DataDecryptorWithMAC<BC,H,MAC,Info>::CurrentState() const275{276return static_cast<const DataDecryptor<BC,H,Info> *>(m_filter.get())->CurrentState();277}278279template <class BC, class H, class MAC, class Info>280bool DataDecryptorWithMAC<BC,H,MAC,Info>::CheckLastMAC() const281{282return m_hashVerifier->GetLastResult();283}284285template <class BC, class H, class MAC, class Info>286void DataDecryptorWithMAC<BC,H,MAC,Info>::LastPut(const byte *inString, size_t length)287{288CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);289m_filter->MessageEnd();290if (m_throwException && !CheckLastMAC())291throw MACBadErr();292}293294template struct DataParametersInfo<LegacyBlockCipher::BLOCKSIZE, LegacyBlockCipher::DEFAULT_KEYLENGTH, LegacyHashModule::DIGESTSIZE, 8, 200>;295template struct DataParametersInfo<DefaultBlockCipher::BLOCKSIZE, DefaultBlockCipher::DEFAULT_KEYLENGTH, DefaultHashModule::DIGESTSIZE, 8, 2500>;296297template class DataEncryptor<LegacyBlockCipher,LegacyHashModule,LegacyParametersInfo>;298template class DataDecryptor<LegacyBlockCipher,LegacyHashModule,LegacyParametersInfo>;299template class DataEncryptor<DefaultBlockCipher,DefaultHashModule,DefaultParametersInfo>;300template class DataDecryptor<DefaultBlockCipher,DefaultHashModule,DefaultParametersInfo>;301template class DataEncryptorWithMAC<LegacyBlockCipher,LegacyHashModule,LegacyMAC,LegacyParametersInfo>;302template class DataDecryptorWithMAC<LegacyBlockCipher,LegacyHashModule,LegacyMAC,LegacyParametersInfo>;303template class DataEncryptorWithMAC<DefaultBlockCipher,DefaultHashModule,DefaultMAC,DefaultParametersInfo>;304template class DataDecryptorWithMAC<DefaultBlockCipher,DefaultHashModule,DefaultMAC,DefaultParametersInfo>;305306NAMESPACE_END307308309