1// default.cpp - written and placed in the public domain by Wei Dai 2 3#include "pch.h" 4#include "default.h" 5#include "queue.h" 6#include <time.h> 7#include <memory> 8 9NAMESPACE_BEGIN(CryptoPP) 10 11static const unsigned int MASH_ITERATIONS = 200; 12static const unsigned int SALTLENGTH = 8; 13static const unsigned int BLOCKSIZE = Default_BlockCipher::Encryption::BLOCKSIZE; 14static const unsigned int KEYLENGTH = Default_BlockCipher::Encryption::DEFAULT_KEYLENGTH; 15 16// The purpose of this function Mash() is to take an arbitrary length input 17// string and *deterministicly* produce an arbitrary length output string such 18// that (1) it looks random, (2) no information about the input is 19// deducible from it, and (3) it contains as much entropy as it can hold, or 20// the amount of entropy in the input string, whichever is smaller. 21 22static void Mash(const byte *in, size_t inLen, byte *out, size_t outLen, int iterations) 23{ 24 if (BytePrecision(outLen) > 2) 25 throw InvalidArgument("Mash: output legnth too large"); 26 27 size_t bufSize = RoundUpToMultipleOf(outLen, (size_t)DefaultHashModule::DIGESTSIZE); 28 byte b[2]; 29 SecByteBlock buf(bufSize); 30 SecByteBlock outBuf(bufSize); 31 DefaultHashModule hash; 32 33 unsigned int i; 34 for(i=0; i<outLen; i+=DefaultHashModule::DIGESTSIZE) 35 { 36 b[0] = (byte) (i >> 8); 37 b[1] = (byte) i; 38 hash.Update(b, 2); 39 hash.Update(in, inLen); 40 hash.Final(outBuf+i); 41 } 42 43 while (iterations-- > 1) 44 { 45 memcpy(buf, outBuf, bufSize); 46 for (i=0; i<bufSize; i+=DefaultHashModule::DIGESTSIZE) 47 { 48 b[0] = (byte) (i >> 8); 49 b[1] = (byte) i; 50 hash.Update(b, 2); 51 hash.Update(buf, bufSize); 52 hash.Final(outBuf+i); 53 } 54 } 55 56 memcpy(out, outBuf, outLen); 57} 58 59static void GenerateKeyIV(const byte *passphrase, size_t passphraseLength, const byte *salt, size_t saltLength, byte *key, byte *IV) 60{ 61 SecByteBlock temp(passphraseLength+saltLength); 62 memcpy(temp, passphrase, passphraseLength); 63 memcpy(temp+passphraseLength, salt, saltLength); 64 SecByteBlock keyIV(KEYLENGTH+BLOCKSIZE); 65 Mash(temp, passphraseLength + saltLength, keyIV, KEYLENGTH+BLOCKSIZE, MASH_ITERATIONS); 66 memcpy(key, keyIV, KEYLENGTH); 67 memcpy(IV, keyIV+KEYLENGTH, BLOCKSIZE); 68} 69 70// ******************************************************** 71 72DefaultEncryptor::DefaultEncryptor(const char *passphrase, BufferedTransformation *attachment) 73 : ProxyFilter(NULL, 0, 0, attachment), m_passphrase((const byte *)passphrase, strlen(passphrase)) 74{ 75} 76 77DefaultEncryptor::DefaultEncryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment) 78 : ProxyFilter(NULL, 0, 0, attachment), m_passphrase(passphrase, passphraseLength) 79{ 80} 81 82 83void DefaultEncryptor::FirstPut(const byte *) 84{ 85 // VC60 workaround: __LINE__ expansion bug 86 CRYPTOPP_COMPILE_ASSERT_INSTANCE(SALTLENGTH <= DefaultHashModule::DIGESTSIZE, 1); 87 CRYPTOPP_COMPILE_ASSERT_INSTANCE(BLOCKSIZE <= DefaultHashModule::DIGESTSIZE, 2); 88 89 SecByteBlock salt(DefaultHashModule::DIGESTSIZE), keyCheck(DefaultHashModule::DIGESTSIZE); 90 DefaultHashModule hash; 91 92 // use hash(passphrase | time | clock) as salt 93 hash.Update(m_passphrase, m_passphrase.size()); 94 time_t t=time(0); 95 hash.Update((byte *)&t, sizeof(t)); 96 clock_t c=clock(); 97 hash.Update((byte *)&c, sizeof(c)); 98 hash.Final(salt); 99 100 // use hash(passphrase | salt) as key check 101 hash.Update(m_passphrase, m_passphrase.size()); 102 hash.Update(salt, SALTLENGTH); 103 hash.Final(keyCheck); 104 105 AttachedTransformation()->Put(salt, SALTLENGTH); 106 107 // mash passphrase and salt together into key and IV 108 SecByteBlock key(KEYLENGTH); 109 SecByteBlock IV(BLOCKSIZE); 110 GenerateKeyIV(m_passphrase, m_passphrase.size(), salt, SALTLENGTH, key, IV); 111 112 m_cipher.SetKeyWithIV(key, key.size(), IV); 113 SetFilter(new StreamTransformationFilter(m_cipher)); 114 115 m_filter->Put(keyCheck, BLOCKSIZE); 116} 117 118void DefaultEncryptor::LastPut(const byte *inString, size_t length) 119{ 120 m_filter->MessageEnd(); 121} 122 123// ******************************************************** 124 125DefaultDecryptor::DefaultDecryptor(const char *p, BufferedTransformation *attachment, bool throwException) 126 : ProxyFilter(NULL, SALTLENGTH+BLOCKSIZE, 0, attachment) 127 , m_state(WAITING_FOR_KEYCHECK) 128 , m_passphrase((const byte *)p, strlen(p)) 129 , m_throwException(throwException) 130{ 131} 132 133DefaultDecryptor::DefaultDecryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment, bool throwException) 134 : ProxyFilter(NULL, SALTLENGTH+BLOCKSIZE, 0, attachment) 135 , m_state(WAITING_FOR_KEYCHECK) 136 , m_passphrase(passphrase, passphraseLength) 137 , m_throwException(throwException) 138{ 139} 140 141void DefaultDecryptor::FirstPut(const byte *inString) 142{ 143 CheckKey(inString, inString+SALTLENGTH); 144} 145 146void DefaultDecryptor::LastPut(const byte *inString, size_t length) 147{ 148 if (m_filter.get() == NULL) 149 { 150 m_state = KEY_BAD; 151 if (m_throwException) 152 throw KeyBadErr(); 153 } 154 else 155 { 156 m_filter->MessageEnd(); 157 m_state = WAITING_FOR_KEYCHECK; 158 } 159} 160 161void DefaultDecryptor::CheckKey(const byte *salt, const byte *keyCheck) 162{ 163 SecByteBlock check(STDMAX((unsigned int)2*BLOCKSIZE, (unsigned int)DefaultHashModule::DIGESTSIZE)); 164 165 DefaultHashModule hash; 166 hash.Update(m_passphrase, m_passphrase.size()); 167 hash.Update(salt, SALTLENGTH); 168 hash.Final(check); 169 170 SecByteBlock key(KEYLENGTH); 171 SecByteBlock IV(BLOCKSIZE); 172 GenerateKeyIV(m_passphrase, m_passphrase.size(), salt, SALTLENGTH, key, IV); 173 174 m_cipher.SetKeyWithIV(key, key.size(), IV); 175 std::auto_ptr<StreamTransformationFilter> decryptor(new StreamTransformationFilter(m_cipher)); 176 177 decryptor->Put(keyCheck, BLOCKSIZE); 178 decryptor->ForceNextPut(); 179 decryptor->Get(check+BLOCKSIZE, BLOCKSIZE); 180 181 SetFilter(decryptor.release()); 182 183 if (!VerifyBufsEqual(check, check+BLOCKSIZE, BLOCKSIZE)) 184 { 185 m_state = KEY_BAD; 186 if (m_throwException) 187 throw KeyBadErr(); 188 } 189 else 190 m_state = KEY_GOOD; 191} 192 193// ******************************************************** 194 195static DefaultMAC * NewDefaultEncryptorMAC(const byte *passphrase, size_t passphraseLength) 196{ 197 size_t macKeyLength = DefaultMAC::StaticGetValidKeyLength(16); 198 SecByteBlock macKey(macKeyLength); 199 // since the MAC is encrypted there is no reason to mash the passphrase for many iterations 200 Mash(passphrase, passphraseLength, macKey, macKeyLength, 1); 201 return new DefaultMAC(macKey, macKeyLength); 202} 203 204DefaultEncryptorWithMAC::DefaultEncryptorWithMAC(const char *passphrase, BufferedTransformation *attachment) 205 : ProxyFilter(NULL, 0, 0, attachment) 206 , m_mac(NewDefaultEncryptorMAC((const byte *)passphrase, strlen(passphrase))) 207{ 208 SetFilter(new HashFilter(*m_mac, new DefaultEncryptor(passphrase), true)); 209} 210 211DefaultEncryptorWithMAC::DefaultEncryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment) 212 : ProxyFilter(NULL, 0, 0, attachment) 213 , m_mac(NewDefaultEncryptorMAC(passphrase, passphraseLength)) 214{ 215 SetFilter(new HashFilter(*m_mac, new DefaultEncryptor(passphrase, passphraseLength), true)); 216} 217 218void DefaultEncryptorWithMAC::LastPut(const byte *inString, size_t length) 219{ 220 m_filter->MessageEnd(); 221} 222 223// ******************************************************** 224 225DefaultDecryptorWithMAC::DefaultDecryptorWithMAC(const char *passphrase, BufferedTransformation *attachment, bool throwException) 226 : ProxyFilter(NULL, 0, 0, attachment) 227 , m_mac(NewDefaultEncryptorMAC((const byte *)passphrase, strlen(passphrase))) 228 , m_throwException(throwException) 229{ 230 SetFilter(new DefaultDecryptor(passphrase, m_hashVerifier=new HashVerifier(*m_mac, NULL, HashVerifier::PUT_MESSAGE), throwException)); 231} 232 233DefaultDecryptorWithMAC::DefaultDecryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment, bool throwException) 234 : ProxyFilter(NULL, 0, 0, attachment) 235 , m_mac(NewDefaultEncryptorMAC(passphrase, passphraseLength)) 236 , m_throwException(throwException) 237{ 238 SetFilter(new DefaultDecryptor(passphrase, passphraseLength, m_hashVerifier=new HashVerifier(*m_mac, NULL, HashVerifier::PUT_MESSAGE), throwException)); 239} 240 241DefaultDecryptor::State DefaultDecryptorWithMAC::CurrentState() const 242{ 243 return static_cast<const DefaultDecryptor *>(m_filter.get())->CurrentState(); 244} 245 246bool DefaultDecryptorWithMAC::CheckLastMAC() const 247{ 248 return m_hashVerifier->GetLastResult(); 249} 250 251void DefaultDecryptorWithMAC::LastPut(const byte *inString, size_t length) 252{ 253 m_filter->MessageEnd(); 254 if (m_throwException && !CheckLastMAC()) 255 throw MACBadErr(); 256} 257 258NAMESPACE_END 259