Crypto++
default.cpp
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 
9 NAMESPACE_BEGIN(CryptoPP)
10 
11 static const unsigned int MASH_ITERATIONS = 200;
12 static const unsigned int SALTLENGTH = 8;
13 static const unsigned int BLOCKSIZE = Default_BlockCipher::Encryption::BLOCKSIZE;
14 static 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 
22 static 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 
59 static 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 
72 DefaultEncryptor::DefaultEncryptor(const char *passphrase, BufferedTransformation *attachment)
73  : ProxyFilter(NULL, 0, 0, attachment), m_passphrase((const byte *)passphrase, strlen(passphrase))
74 {
75 }
76 
77 DefaultEncryptor::DefaultEncryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment)
78  : ProxyFilter(NULL, 0, 0, attachment), m_passphrase(passphrase, passphraseLength)
79 {
80 }
81 
82 
83 void 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 
118 void DefaultEncryptor::LastPut(const byte *inString, size_t length)
119 {
120  m_filter->MessageEnd();
121 }
122 
123 // ********************************************************
124 
125 DefaultDecryptor::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 
133 DefaultDecryptor::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 
141 void DefaultDecryptor::FirstPut(const byte *inString)
142 {
143  CheckKey(inString, inString+SALTLENGTH);
144 }
145 
146 void 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 
161 void 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 
195 static 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 
204 DefaultEncryptorWithMAC::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 
211 DefaultEncryptorWithMAC::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 
218 void DefaultEncryptorWithMAC::LastPut(const byte *inString, size_t length)
219 {
220  m_filter->MessageEnd();
221 }
222 
223 // ********************************************************
224 
225 DefaultDecryptorWithMAC::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 
233 DefaultDecryptorWithMAC::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 
241 DefaultDecryptor::State DefaultDecryptorWithMAC::CurrentState() const
242 {
243  return static_cast<const DefaultDecryptor *>(m_filter.get())->CurrentState();
244 }
245 
246 bool DefaultDecryptorWithMAC::CheckLastMAC() const
247 {
248  return m_hashVerifier->GetLastResult();
249 }
250 
251 void DefaultDecryptorWithMAC::LastPut(const byte *inString, size_t length)
252 {
253  m_filter->MessageEnd();
254  if (m_throwException && !CheckLastMAC())
255  throw MACBadErr();
256 }
257 
258 NAMESPACE_END
exception thrown when an invalid argument is detected
Definition: cryptlib.h:145
Base class for Filter classes that are proxies for a chain of other filters.
Definition: filters.h:539
Password-Based Encryptor using DES-EDE2.
Definition: default.h:17
a block of memory allocated using A
Definition: secblock.h:238
interface for buffered transformations
Definition: cryptlib.h:771
Password-Based Decryptor using DES-EDE2.
Definition: default.h:33
Filter Wrapper for HashTransformation.
Definition: filters.h:310
Filter Wrapper for HashTransformation.
Definition: filters.h:291
size_t Put(byte inByte, bool blocking=true)
input a byte for processing
Definition: cryptlib.h:785
BufferedTransformation * AttachedTransformation()
returns the object immediately attached to this object or NULL for no attachment
Definition: filters.cpp:26
DES-EDE2
Definition: des.h:62
SHA-1
Definition: sha.h:9
const char * IV()
ConstByteArrayParameter, also accepts const byte * for backwards compatibility.
Definition: argnames.h:16
Filter Wrapper for StreamTransformation, optionally handling padding/unpadding when needed...
Definition: filters.h:262
HMAC
Definition: hmac.h:40
virtual void Final(byte *digest)
compute hash for current message, then restart for a new message
Definition: cryptlib.h:545