Crypto++ 8.7
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
19NAMESPACE_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
27template <class H>
28static 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 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
65template <class BC, class H, class Info>
66static 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 memcpy(temp, passphrase, passphraseLength);
72 if (salt != NULLPTR)
73 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 memcpy(key, keyIV, Info::KEYLENGTH);
79 memcpy(IV, keyIV+Info::KEYLENGTH, Info::BLOCKSIZE);
80}
81
82// ********************************************************
83
84template <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);
91
92template <class BC, class H, class Info>
93DataEncryptor<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
100template <class BC, class H, class Info>
101void 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
132template <class BC, class H, class Info>
133void 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
141template <class BC, class H, class Info>
142DataDecryptor<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
152template <class BC, class H, class Info>
153DataDecryptor<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
163template <class BC, class H, class Info>
164void DataDecryptor<BC,H,Info>::FirstPut(const byte *inString)
165{
166 CheckKey(inString, inString+SALTLENGTH);
167}
168
169template <class BC, class H, class Info>
170void 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}
186template <class BC, class H, class Info>
187void 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
221template <class H, class MAC>
222static 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
231template <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}
239template <class BC, class H, class MAC, class Info>
240DataEncryptorWithMAC<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
247template <class BC, class H, class MAC, class Info>
248void 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
256template <class BC, class H, class MAC, class Info>
257DataDecryptorWithMAC<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
265template <class BC, class H, class MAC, class Info>
266DataDecryptorWithMAC<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
274template <class BC, class H, class MAC, class Info>
275typename 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
280template <class BC, class H, class MAC, class Info>
282{
283 return m_hashVerifier->GetLastResult();
284}
285
286template <class BC, class H, class MAC, class Info>
287void 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
307NAMESPACE_END
Interface for buffered transformations.
Definition: cryptlib.h:1652
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:203
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:56
Abstract base classes that provide a uniform interface to this library.
Classes for DefaultEncryptor, DefaultDecryptor, DefaultEncryptorWithMAC and DefaultDecryptorWithMAC.
Implementation of BufferedTransformation's attachment interface.
const T & STDMAX(const T &a, const T &b)
Replacement function for std::max.
Definition: misc.h:666
unsigned int BytePrecision(const T &value)
Returns the number of 8-bit bytes or octets required for a value.
Definition: misc.h:819
T1 RoundUpToMultipleOf(const T1 &n, const T2 &m)
Rounds a value up to a multiple of a second value.
Definition: misc.h:1175
#define CRYPTOPP_COMPILE_ASSERT(expr)
Compile time assertion.
Definition: misc.h:151
#define EnumToInt(v)
Integer value.
Definition: misc.h:502
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