Crypto++  8.8
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 *deterministically* 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 length 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  std::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  std::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  // UBsan. User supplied params, may be NULL
69  SecByteBlock temp(passphraseLength+saltLength);
70  if (passphrase != NULLPTR)
71  std::memcpy(temp, passphrase, passphraseLength);
72  if (salt != NULLPTR)
73  std::memcpy(temp+passphraseLength, salt, saltLength);
74 
75  // OK. Derived params, cannot be NULL
76  SecByteBlock keyIV(EnumToInt(Info::KEYLENGTH)+EnumToInt(+Info::BLOCKSIZE));
77  Mash<H>(temp, passphraseLength + saltLength, keyIV, EnumToInt(Info::KEYLENGTH)+EnumToInt(+Info::BLOCKSIZE), iterations);
78  std::memcpy(key, keyIV, Info::KEYLENGTH);
79  std::memcpy(IV, keyIV+Info::KEYLENGTH, Info::BLOCKSIZE);
80 }
81 
82 // ********************************************************
83 
84 template <class BC, class H, class Info>
86  : ProxyFilter(NULLPTR, 0, 0, attachment), m_passphrase((const byte *)passphrase, strlen(passphrase))
87 {
88  CRYPTOPP_COMPILE_ASSERT((int)SALTLENGTH <= DIGESTSIZE);
89  CRYPTOPP_COMPILE_ASSERT((int)BLOCKSIZE <= (int)DIGESTSIZE);
90 }
91 
92 template <class BC, class H, class Info>
93 DataEncryptor<BC,H,Info>::DataEncryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment)
94  : ProxyFilter(NULLPTR, 0, 0, attachment), m_passphrase(passphrase, passphraseLength)
95 {
96  CRYPTOPP_COMPILE_ASSERT((int)SALTLENGTH <= (int)DIGESTSIZE);
97  CRYPTOPP_COMPILE_ASSERT((int)BLOCKSIZE <= (int)DIGESTSIZE);
98 }
99 
100 template <class BC, class H, class Info>
101 void DataEncryptor<BC,H,Info>::FirstPut(const byte *)
102 {
103  SecByteBlock salt(DIGESTSIZE), keyCheck(DIGESTSIZE);
104  H hash;
105 
106  // use hash(passphrase | time | clock) as salt
107  hash.Update(m_passphrase, m_passphrase.size());
108  time_t t=time(NULLPTR);
109  hash.Update((byte *)&t, sizeof(t));
110  clock_t c=clock();
111  hash.Update((byte *)&c, sizeof(c));
112  hash.Final(salt);
113 
114  // use hash(passphrase | salt) as key check
115  hash.Update(m_passphrase, m_passphrase.size());
116  hash.Update(salt, SALTLENGTH);
117  hash.Final(keyCheck);
118 
119  AttachedTransformation()->Put(salt, SALTLENGTH);
120 
121  // mash passphrase and salt together into key and IV
122  SecByteBlock key(KEYLENGTH);
123  SecByteBlock IV(BLOCKSIZE);
124  GenerateKeyIV<BC,H,Info>(m_passphrase, m_passphrase.size(), salt, SALTLENGTH, ITERATIONS, key, IV);
125 
126  m_cipher.SetKeyWithIV(key, key.size(), IV);
127  SetFilter(new StreamTransformationFilter(m_cipher));
128 
129  m_filter->Put(keyCheck, BLOCKSIZE);
130 }
131 
132 template <class BC, class H, class Info>
133 void DataEncryptor<BC,H,Info>::LastPut(const byte *inString, size_t length)
134 {
135  CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);
136  m_filter->MessageEnd();
137 }
138 
139 // ********************************************************
140 
141 template <class BC, class H, class Info>
142 DataDecryptor<BC,H,Info>::DataDecryptor(const char *p, BufferedTransformation *attachment, bool throwException)
143  : ProxyFilter(NULLPTR, EnumToInt(SALTLENGTH)+EnumToInt(BLOCKSIZE), 0, attachment)
144  , m_state(WAITING_FOR_KEYCHECK)
145  , m_passphrase((const byte *)p, strlen(p))
146  , m_throwException(throwException)
147 {
148  CRYPTOPP_COMPILE_ASSERT((int)SALTLENGTH <= (int)DIGESTSIZE);
149  CRYPTOPP_COMPILE_ASSERT((int)BLOCKSIZE <= (int)DIGESTSIZE);
150 }
151 
152 template <class BC, class H, class Info>
153 DataDecryptor<BC,H,Info>::DataDecryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment, bool throwException)
154  : ProxyFilter(NULLPTR, EnumToInt(SALTLENGTH)+EnumToInt(BLOCKSIZE), 0, attachment)
155  , m_state(WAITING_FOR_KEYCHECK)
156  , m_passphrase(passphrase, passphraseLength)
157  , m_throwException(throwException)
158 {
159  CRYPTOPP_COMPILE_ASSERT((int)SALTLENGTH <= (int)DIGESTSIZE);
160  CRYPTOPP_COMPILE_ASSERT((int)BLOCKSIZE <= (int)DIGESTSIZE);
161 }
162 
163 template <class BC, class H, class Info>
164 void DataDecryptor<BC,H,Info>::FirstPut(const byte *inString)
165 {
166  CheckKey(inString, inString+SALTLENGTH);
167 }
168 
169 template <class BC, class H, class Info>
170 void DataDecryptor<BC,H,Info>::LastPut(const byte *inString, size_t length)
171 {
172  CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);
173  if (m_filter.get() == NULLPTR)
174  {
175  m_state = KEY_BAD;
176  if (m_throwException)
177  throw KeyBadErr();
178  }
179  else
180  {
181  m_filter->MessageEnd();
182  m_state = WAITING_FOR_KEYCHECK;
183  }
184 }
185 
186 template <class BC, class H, class Info>
187 void DataDecryptor<BC,H,Info>::CheckKey(const byte *salt, const byte *keyCheck)
188 {
189  SecByteBlock check(STDMAX((unsigned int)2*BLOCKSIZE, (unsigned int)DIGESTSIZE));
190 
191  H hash;
192  hash.Update(m_passphrase, m_passphrase.size());
193  hash.Update(salt, SALTLENGTH);
194  hash.Final(check);
195 
196  SecByteBlock key(KEYLENGTH);
197  SecByteBlock IV(BLOCKSIZE);
198  GenerateKeyIV<BC,H,Info>(m_passphrase, m_passphrase.size(), salt, SALTLENGTH, ITERATIONS, key, IV);
199 
200  m_cipher.SetKeyWithIV(key, key.size(), IV);
202 
203  decryptor->Put(keyCheck, BLOCKSIZE);
204  decryptor->ForceNextPut();
205  decryptor->Get(check+EnumToInt(BLOCKSIZE), BLOCKSIZE);
206 
207  SetFilter(decryptor.release());
208 
209  if (!VerifyBufsEqual(check, check+EnumToInt(BLOCKSIZE), BLOCKSIZE))
210  {
211  m_state = KEY_BAD;
212  if (m_throwException)
213  throw KeyBadErr();
214  }
215  else
216  m_state = KEY_GOOD;
217 }
218 
219 // ********************************************************
220 
221 template <class H, class MAC>
222 static MAC* NewDataEncryptorMAC(const byte *passphrase, size_t passphraseLength)
223 {
224  size_t macKeyLength = MAC::StaticGetValidKeyLength(16);
225  SecByteBlock macKey(macKeyLength);
226  // since the MAC is encrypted there is no reason to mash the passphrase for many iterations
227  Mash<H>(passphrase, passphraseLength, macKey, macKeyLength, 1);
228  return new MAC(macKey, macKeyLength);
229 }
230 
231 template <class BC, class H, class MAC, class Info>
233  : ProxyFilter(NULLPTR, 0, 0, attachment)
234  , m_mac(NewDataEncryptorMAC<H,MAC>((const byte *)passphrase, strlen(passphrase)))
235 {
236  SetFilter(new HashFilter(*m_mac, new DataEncryptor<BC,H,Info>(passphrase), true));
237 }
238 
239 template <class BC, class H, class MAC, class Info>
240 DataEncryptorWithMAC<BC,H,MAC,Info>::DataEncryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment)
241  : ProxyFilter(NULLPTR, 0, 0, attachment)
242  , m_mac(NewDataEncryptorMAC<H,MAC>(passphrase, passphraseLength))
243 {
244  SetFilter(new HashFilter(*m_mac, new DataEncryptor<BC,H,Info>(passphrase, passphraseLength), true));
245 }
246 
247 template <class BC, class H, class MAC, class Info>
248 void DataEncryptorWithMAC<BC,H,MAC,Info>::LastPut(const byte *inString, size_t length)
249 {
250  CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);
251  m_filter->MessageEnd();
252 }
253 
254 // ********************************************************
255 
256 template <class BC, class H, class MAC, class Info>
257 DataDecryptorWithMAC<BC,H,MAC,Info>::DataDecryptorWithMAC(const char *passphrase, BufferedTransformation *attachment, bool throwException)
258  : ProxyFilter(NULLPTR, 0, 0, attachment)
259  , m_mac(NewDataEncryptorMAC<H,MAC>((const byte *)passphrase, strlen(passphrase)))
260  , m_throwException(throwException)
261 {
262  SetFilter(new DataDecryptor<BC,H,Info>(passphrase, m_hashVerifier=new HashVerificationFilter(*m_mac, NULLPTR, HashVerificationFilter::PUT_MESSAGE), throwException));
263 }
264 
265 template <class BC, class H, class MAC, class Info>
266 DataDecryptorWithMAC<BC,H,MAC,Info>::DataDecryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment, bool throwException)
267  : ProxyFilter(NULLPTR, 0, 0, attachment)
268  , m_mac(NewDataEncryptorMAC<H,MAC>(passphrase, passphraseLength))
269  , m_throwException(throwException)
270 {
271  SetFilter(new DataDecryptor<BC,H,Info>(passphrase, passphraseLength, m_hashVerifier=new HashVerificationFilter(*m_mac, NULLPTR, HashVerificationFilter::PUT_MESSAGE), throwException));
272 }
273 
274 template <class BC, class H, class MAC, class Info>
275 typename DataDecryptor<BC,H,Info>::State DataDecryptorWithMAC<BC,H,MAC,Info>::CurrentState() const
276 {
277  return static_cast<const DataDecryptor<BC,H,Info> *>(m_filter.get())->CurrentState();
278 }
279 
280 template <class BC, class H, class MAC, class Info>
282 {
283  return m_hashVerifier->GetLastResult();
284 }
285 
286 template <class BC, class H, class MAC, class Info>
287 void DataDecryptorWithMAC<BC,H,MAC,Info>::LastPut(const byte *inString, size_t length)
288 {
289  CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);
290  m_filter->MessageEnd();
291  if (m_throwException && !CheckLastMAC())
292  throw MACBadErr();
293 }
294 
297 
306 
307 NAMESPACE_END
Interface for buffered transformations.
Definition: cryptlib.h:1657
Password-based Decryptor.
Definition: default.h:117
DataDecryptor(const char *passphrase, BufferedTransformation *attachment=NULL, bool throwException=true)
Constructs a DataDecryptor.
Definition: default.cpp:142
Password-based decryptor with MAC.
Definition: default.h:219
DataDecryptorWithMAC(const char *passphrase, BufferedTransformation *attachment=NULL, bool throwException=true)
Constructs a DataDecryptor.
Definition: default.cpp:257
Password-based Encryptor.
Definition: default.h:79
DataEncryptor(const char *passphrase, BufferedTransformation *attachment=NULL)
Construct a DataEncryptor.
Definition: default.cpp:85
Password-based encryptor with MAC.
Definition: default.h:174
DataEncryptorWithMAC(const char *passphrase, BufferedTransformation *attachment=NULL)
Constructs a DataEncryptorWithMAC.
Definition: default.cpp:232
Filter wrapper for HashTransformation.
Definition: filters.h:582
Filter wrapper for HashTransformation.
Definition: filters.h:611
@ PUT_MESSAGE
The message should be passed to an attached transformation.
Definition: filters.h:632
An invalid argument was detected.
Definition: cryptlib.h:208
Exception thrown when a bad key is encountered in DefaultDecryptorWithMAC and LegacyDecryptorWithMAC.
Definition: default.h:43
Exception thrown when an incorrect MAC is encountered in DefaultDecryptorWithMAC and LegacyDecryptorW...
Definition: default.h:50
Base class for Filter classes that are proxies for a chain of other filters.
Definition: filters.h:1039
void SetFilter(Filter *filter)
Sets the OutputProxy filter.
SecBlock<byte> typedef.
Definition: secblock.h:1226
Filter wrapper for StreamTransformation.
Definition: filters.h:532
Pointer that overloads operator ->
Definition: smartptr.h:38
Library configuration file.
unsigned char byte
8-bit unsigned datatype
Definition: config_int.h:66
Abstract base classes that provide a uniform interface to this library.
Classes for DefaultEncryptor, DefaultDecryptor, DefaultEncryptorWithMAC and DefaultDecryptorWithMAC.
Implementation of BufferedTransformation's attachment interface.
unsigned int BytePrecision(const T &value)
Returns the number of 8-bit bytes or octets required for a value.
Definition: misc.h:1024
T1 RoundUpToMultipleOf(const T1 &n, const T2 &m)
Rounds a value up to a multiple of a second value.
Definition: misc.h:1384
#define CRYPTOPP_COMPILE_ASSERT(expr)
Compile time assertion.
Definition: misc.h:153
#define EnumToInt(v)
Integer value.
Definition: misc.h:504
const T & STDMAX(const T &a, const T &b)
Replacement function for std::max.
Definition: misc.h:668
CRYPTOPP_DLL bool VerifyBufsEqual(const byte *buf1, const byte *buf2, size_t count)
Performs a near constant-time comparison of two equally sized buffers.
Crypto++ library namespace.
const char * IV()
ConstByteArrayParameter, also accepts const byte * for backwards compatibility.
Definition: argnames.h:21
Precompiled header file.
Classes for an unlimited queue to store bytes.
Classes for automatic resource management.
Algorithm information for password-based encryptors and decryptors.
Definition: default.h:58