Crypto++  5.6.5
Free C++ class library of cryptographic schemes
default.cpp
1 // default.cpp - originally written and placed in the public domain by Wei Dai
2 
3 #include "pch.h"
4 #include "config.h"
5 
6 #if CRYPTOPP_MSC_VERSION
7 # pragma warning(disable: 4127 4189)
8 #endif
9 
10 #include "cryptlib.h"
11 #include "filters.h"
12 #include "smartptr.h"
13 #include "default.h"
14 #include "queue.h"
15 
16 #include <time.h>
17 #include <memory>
18 
19 NAMESPACE_BEGIN(CryptoPP)
20 
21 // The purpose of this function Mash() is to take an arbitrary length input
22 // string and *deterministicly* produce an arbitrary length output string such
23 // that (1) it looks random, (2) no information about the input is
24 // deducible from it, and (3) it contains as much entropy as it can hold, or
25 // the amount of entropy in the input string, whichever is smaller.
26 
27 template <class H>
28 static void Mash(const byte *in, size_t inLen, byte *out, size_t outLen, int iterations)
29 {
30  if (BytePrecision(outLen) > 2)
31  throw InvalidArgument("Mash: output legnth too large");
32 
33  size_t bufSize = RoundUpToMultipleOf(outLen, (size_t)H::DIGESTSIZE);
34  byte b[2];
35  SecByteBlock buf(bufSize);
36  SecByteBlock outBuf(bufSize);
37  H hash;
38 
39  unsigned int i;
40  for(i=0; i<outLen; i+=H::DIGESTSIZE)
41  {
42  b[0] = (byte) (i >> 8);
43  b[1] = (byte) i;
44  hash.Update(b, 2);
45  hash.Update(in, inLen);
46  hash.Final(outBuf+i);
47  }
48 
49  while (iterations-- > 1)
50  {
51  memcpy(buf, outBuf, bufSize);
52  for (i=0; i<bufSize; i+=H::DIGESTSIZE)
53  {
54  b[0] = (byte) (i >> 8);
55  b[1] = (byte) i;
56  hash.Update(b, 2);
57  hash.Update(buf, bufSize);
58  hash.Final(outBuf+i);
59  }
60  }
61 
62  memcpy(out, outBuf, outLen);
63 }
64 
65 template <class BC, class H, class Info>
66 static void GenerateKeyIV(const byte *passphrase, size_t passphraseLength, const byte *salt, size_t saltLength, unsigned int iterations, byte *key, byte *IV)
67 {
68  SecByteBlock temp(passphraseLength+saltLength);
69  memcpy(temp, passphrase, passphraseLength);
70  memcpy(temp+passphraseLength, salt, saltLength);
71  SecByteBlock keyIV(Info::KEYLENGTH+Info::BLOCKSIZE);
72  Mash<H>(temp, passphraseLength + saltLength, keyIV, Info::KEYLENGTH+Info::BLOCKSIZE, iterations);
73  memcpy(key, keyIV, Info::KEYLENGTH);
74  memcpy(IV, keyIV+Info::KEYLENGTH, Info::BLOCKSIZE);
75 }
76 
77 // ********************************************************
78 
79 template <class BC, class H, class Info>
81  : ProxyFilter(NULLPTR, 0, 0, attachment), m_passphrase((const byte *)passphrase, strlen(passphrase))
82 {
83  CRYPTOPP_COMPILE_ASSERT(SALTLENGTH <= DIGESTSIZE);
84  CRYPTOPP_COMPILE_ASSERT(BLOCKSIZE <= DIGESTSIZE);
85 }
86 
87 template <class BC, class H, class Info>
88 DataEncryptor<BC,H,Info>::DataEncryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment)
89  : ProxyFilter(NULLPTR, 0, 0, attachment), m_passphrase(passphrase, passphraseLength)
90 {
91  CRYPTOPP_COMPILE_ASSERT(SALTLENGTH <= DIGESTSIZE);
92  CRYPTOPP_COMPILE_ASSERT(BLOCKSIZE <= DIGESTSIZE);
93 }
94 
95 template <class BC, class H, class Info>
96 void DataEncryptor<BC,H,Info>::FirstPut(const byte *)
97 {
98  SecByteBlock salt(DIGESTSIZE), keyCheck(DIGESTSIZE);
99  H hash;
100 
101  // use hash(passphrase | time | clock) as salt
102  hash.Update(m_passphrase, m_passphrase.size());
103  time_t t=time(NULLPTR);
104  hash.Update((byte *)&t, sizeof(t));
105  clock_t c=clock();
106  hash.Update((byte *)&c, sizeof(c));
107  hash.Final(salt);
108 
109  // use hash(passphrase | salt) as key check
110  hash.Update(m_passphrase, m_passphrase.size());
111  hash.Update(salt, SALTLENGTH);
112  hash.Final(keyCheck);
113 
114  AttachedTransformation()->Put(salt, SALTLENGTH);
115 
116  // mash passphrase and salt together into key and IV
117  SecByteBlock key(KEYLENGTH);
118  SecByteBlock IV(BLOCKSIZE);
119  GenerateKeyIV<BC,H,Info>(m_passphrase, m_passphrase.size(), salt, SALTLENGTH, ITERATIONS, key, IV);
120 
121  m_cipher.SetKeyWithIV(key, key.size(), IV);
122  SetFilter(new StreamTransformationFilter(m_cipher));
123 
124  m_filter->Put(keyCheck, BLOCKSIZE);
125 }
126 
127 template <class BC, class H, class Info>
128 void DataEncryptor<BC,H,Info>::LastPut(const byte *inString, size_t length)
129 {
130  CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);
131  m_filter->MessageEnd();
132 }
133 
134 // ********************************************************
135 
136 template <class BC, class H, class Info>
137 DataDecryptor<BC,H,Info>::DataDecryptor(const char *p, BufferedTransformation *attachment, bool throwException)
138  : ProxyFilter(NULLPTR, SALTLENGTH+BLOCKSIZE, 0, attachment)
139  , m_state(WAITING_FOR_KEYCHECK)
140  , m_passphrase((const byte *)p, strlen(p))
141  , m_throwException(throwException)
142 {
143  CRYPTOPP_COMPILE_ASSERT(SALTLENGTH <= DIGESTSIZE);
144  CRYPTOPP_COMPILE_ASSERT(BLOCKSIZE <= DIGESTSIZE);
145 }
146 
147 template <class BC, class H, class Info>
148 DataDecryptor<BC,H,Info>::DataDecryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment, bool throwException)
149  : ProxyFilter(NULLPTR, SALTLENGTH+BLOCKSIZE, 0, attachment)
150  , m_state(WAITING_FOR_KEYCHECK)
151  , m_passphrase(passphrase, passphraseLength)
152  , m_throwException(throwException)
153 {
154  CRYPTOPP_COMPILE_ASSERT(SALTLENGTH <= DIGESTSIZE);
155  CRYPTOPP_COMPILE_ASSERT(BLOCKSIZE <= DIGESTSIZE);
156 }
157 
158 template <class BC, class H, class Info>
159 void DataDecryptor<BC,H,Info>::FirstPut(const byte *inString)
160 {
161  CheckKey(inString, inString+SALTLENGTH);
162 }
163 
164 template <class BC, class H, class Info>
165 void DataDecryptor<BC,H,Info>::LastPut(const byte *inString, size_t length)
166 {
167  CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);
168  if (m_filter.get() == NULLPTR)
169  {
170  m_state = KEY_BAD;
171  if (m_throwException)
172  throw KeyBadErr();
173  }
174  else
175  {
176  m_filter->MessageEnd();
177  m_state = WAITING_FOR_KEYCHECK;
178  }
179 }
180 
181 template <class BC, class H, class Info>
182 void DataDecryptor<BC,H,Info>::CheckKey(const byte *salt, const byte *keyCheck)
183 {
184  SecByteBlock check(STDMAX((unsigned int)2*BLOCKSIZE, (unsigned int)DIGESTSIZE));
185 
186  H hash;
187  hash.Update(m_passphrase, m_passphrase.size());
188  hash.Update(salt, SALTLENGTH);
189  hash.Final(check);
190 
191  SecByteBlock key(KEYLENGTH);
192  SecByteBlock IV(BLOCKSIZE);
193  GenerateKeyIV<BC,H,Info>(m_passphrase, m_passphrase.size(), salt, SALTLENGTH, ITERATIONS, key, IV);
194 
195  m_cipher.SetKeyWithIV(key, key.size(), IV);
197 
198  decryptor->Put(keyCheck, BLOCKSIZE);
199  decryptor->ForceNextPut();
200  decryptor->Get(check+BLOCKSIZE, BLOCKSIZE);
201 
202  SetFilter(decryptor.release());
203 
204  if (!VerifyBufsEqual(check, check+BLOCKSIZE, BLOCKSIZE))
205  {
206  m_state = KEY_BAD;
207  if (m_throwException)
208  throw KeyBadErr();
209  }
210  else
211  m_state = KEY_GOOD;
212 }
213 
214 // ********************************************************
215 
216 template <class H, class MAC>
217 static MAC* NewDataEncryptorMAC(const byte *passphrase, size_t passphraseLength)
218 {
219  size_t macKeyLength = MAC::StaticGetValidKeyLength(16);
220  SecByteBlock macKey(macKeyLength);
221  // since the MAC is encrypted there is no reason to mash the passphrase for many iterations
222  Mash<H>(passphrase, passphraseLength, macKey, macKeyLength, 1);
223  return new MAC(macKey, macKeyLength);
224 }
225 
226 template <class BC, class H, class MAC, class Info>
228  : ProxyFilter(NULLPTR, 0, 0, attachment)
229  , m_mac(NewDataEncryptorMAC<H,MAC>((const byte *)passphrase, strlen(passphrase)))
230 {
231  SetFilter(new HashFilter(*m_mac, new DataEncryptor<BC,H,Info>(passphrase), true));
232 }
233 
234 template <class BC, class H, class MAC, class Info>
235 DataEncryptorWithMAC<BC,H,MAC,Info>::DataEncryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment)
236  : ProxyFilter(NULLPTR, 0, 0, attachment)
237  , m_mac(NewDataEncryptorMAC<H,MAC>(passphrase, passphraseLength))
238 {
239  SetFilter(new HashFilter(*m_mac, new DataEncryptor<BC,H,Info>(passphrase, passphraseLength), true));
240 }
241 
242 template <class BC, class H, class MAC, class Info>
243 void DataEncryptorWithMAC<BC,H,MAC,Info>::LastPut(const byte *inString, size_t length)
244 {
245  CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);
246  m_filter->MessageEnd();
247 }
248 
249 // ********************************************************
250 
251 template <class BC, class H, class MAC, class Info>
252 DataDecryptorWithMAC<BC,H,MAC,Info>::DataDecryptorWithMAC(const char *passphrase, BufferedTransformation *attachment, bool throwException)
253  : ProxyFilter(NULLPTR, 0, 0, attachment)
254  , m_mac(NewDataEncryptorMAC<H,MAC>((const byte *)passphrase, strlen(passphrase)))
255  , m_throwException(throwException)
256 {
257  SetFilter(new DataDecryptor<BC,H,Info>(passphrase, m_hashVerifier=new HashVerificationFilter(*m_mac, NULLPTR, HashVerificationFilter::PUT_MESSAGE), throwException));
258 }
259 
260 template <class BC, class H, class MAC, class Info>
261 DataDecryptorWithMAC<BC,H,MAC,Info>::DataDecryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment, bool throwException)
262  : ProxyFilter(NULLPTR, 0, 0, attachment)
263  , m_mac(NewDataEncryptorMAC<H,MAC>(passphrase, passphraseLength))
264  , m_throwException(throwException)
265 {
266  SetFilter(new DataDecryptor<BC,H,Info>(passphrase, passphraseLength, m_hashVerifier=new HashVerificationFilter(*m_mac, NULLPTR, HashVerificationFilter::PUT_MESSAGE), throwException));
267 }
268 
269 template <class BC, class H, class MAC, class Info>
270 typename DataDecryptor<BC,H,Info>::State DataDecryptorWithMAC<BC,H,MAC,Info>::CurrentState() const
271 {
272  return static_cast<const DataDecryptor<BC,H,Info> *>(m_filter.get())->CurrentState();
273 }
274 
275 template <class BC, class H, class MAC, class Info>
277 {
278  return m_hashVerifier->GetLastResult();
279 }
280 
281 template <class BC, class H, class MAC, class Info>
282 void DataDecryptorWithMAC<BC,H,MAC,Info>::LastPut(const byte *inString, size_t length)
283 {
284  CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);
285  m_filter->MessageEnd();
286  if (m_throwException && !CheckLastMAC())
287  throw MACBadErr();
288 }
289 
292 
301 
302 NAMESPACE_END
An invalid argument was detected.
Definition: cryptlib.h:194
Exception thrown when a bad key is encountered in DefaultDecryptorWithMAC and LegacyDecryptorWithMAC...
Definition: default.h:44
Base class for Filter classes that are proxies for a chain of other filters.
Definition: filters.h:970
unsigned int BytePrecision(const T &value)
Returns the number of 8-bit bytes or octets required for a value.
Definition: misc.h:677
Password-based Encryptor.
Definition: default.h:83
Abstract base classes that provide a uniform interface to this library.
Password-based Decryptor.
Definition: default.h:122
Classes for automatic resource management.
Classes for DefaultEncryptor, DefaultDecryptor, DefaultEncryptorWithMAC and DefaultDecryptorWithMAC.
Library configuration file.
SecBlock<byte> typedef.
Definition: secblock.h:810
Interface for buffered transformations.
Definition: cryptlib.h:1345
Pointer that overloads operator ->
Definition: smartptr.h:39
DataEncryptor(const char *passphrase, BufferedTransformation *attachment=NULL)
Construct a DataEncryptor.
Definition: default.cpp:80
Classes for an unlimited queue to store bytes.
Filter wrapper for HashTransformation.
Definition: filters.h:565
Filter wrapper for HashTransformation.
Definition: filters.h:535
Password-based encryptor with MAC.
Definition: default.h:180
size_t Put(byte inByte, bool blocking=true)
Input a byte for processing.
Definition: cryptlib.h:1366
#define CRYPTOPP_COMPILE_ASSERT(expr)
Compile time assertion.
Definition: misc.h:159
DataEncryptorWithMAC(const char *passphrase, BufferedTransformation *attachment=NULL)
Constructs a DataEncryptorWithMAC.
Definition: default.cpp:227
BufferedTransformation * AttachedTransformation()
Retrieve attached transformation.
Definition: filters.cpp:36
Indicates the message should be passed to an attached transformation.
Definition: filters.h:588
Algorithm information for password-based encryptors and decryptors.
Definition: default.h:61
Implementation of BufferedTransformation&#39;s attachment interface.
const char * IV()
ConstByteArrayParameter, also accepts const byte * for backwards compatibility.
Definition: argnames.h:21
Filter wrapper for StreamTransformation.
Definition: filters.h:504
DataDecryptor(const char *passphrase, BufferedTransformation *attachment=NULL, bool throwException=true)
Constructs a DataDecryptor.
Definition: default.cpp:137
DataDecryptorWithMAC(const char *passphrase, BufferedTransformation *attachment=NULL, bool throwException=true)
Constructs a DataDecryptor.
Definition: default.cpp:252
void ForceNextPut()
Flushes data buffered by this object.
Definition: filters.cpp:441
Password-based decryptor with MAC.
Definition: default.h:220
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
T1 RoundUpToMultipleOf(const T1 &n, const T2 &m)
Rounds a value up to a multiple of a second value.
Definition: misc.h:977
const T & STDMAX(const T &a, const T &b)
Replacement function for std::max.
Definition: misc.h:525
virtual size_t Get(byte &outByte)
Retrieve a 8-bit byte.
Definition: cryptlib.cpp:489
Crypto++ library namespace.
void SetFilter(Filter *filter)
Sets the OutputProxy filter.
Definition: filters.cpp:496
Exception thrown when an incorrect MAC is encountered in DefaultDecryptorWithMAC and LegacyDecryptorW...
Definition: default.h:52
size_type size() const
Provides the count of elements in the SecBlock.
Definition: secblock.h:570