Crypto++ 8.9 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>
85 DataEncryptor<BC,H,Info>::DataEncryptor(const char *passphrase, BufferedTransformation *attachment)
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);
201 member_ptr<StreamTransformationFilter> decryptor(new StreamTransformationFilter(m_cipher));
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>
232 DataEncryptorWithMAC<BC,H,MAC,Info>::DataEncryptorWithMAC(const char *passphrase, BufferedTransformation *attachment)
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>
281 bool DataDecryptorWithMAC<BC,H,MAC,Info>::CheckLastMAC() const
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
295 template struct DataParametersInfo<LegacyBlockCipher::BLOCKSIZE, LegacyBlockCipher::DEFAULT_KEYLENGTH, LegacyHashModule::DIGESTSIZE, 8, 200>;
296 template struct DataParametersInfo<DefaultBlockCipher::BLOCKSIZE, DefaultBlockCipher::DEFAULT_KEYLENGTH, DefaultHashModule::DIGESTSIZE, 8, 2500>;
297
298 template class DataEncryptor<LegacyBlockCipher,LegacyHashModule,LegacyParametersInfo>;
299 template class DataDecryptor<LegacyBlockCipher,LegacyHashModule,LegacyParametersInfo>;
300 template class DataEncryptor<DefaultBlockCipher,DefaultHashModule,DefaultParametersInfo>;
301 template class DataDecryptor<DefaultBlockCipher,DefaultHashModule,DefaultParametersInfo>;
302 template class DataEncryptorWithMAC<LegacyBlockCipher,LegacyHashModule,LegacyMAC,LegacyParametersInfo>;
303 template class DataDecryptorWithMAC<LegacyBlockCipher,LegacyHashModule,LegacyMAC,LegacyParametersInfo>;
304 template class DataEncryptorWithMAC<DefaultBlockCipher,DefaultHashModule,DefaultMAC,DefaultParametersInfo>;
305 template class DataDecryptorWithMAC<DefaultBlockCipher,DefaultHashModule,DefaultMAC,DefaultParametersInfo>;
306
307 NAMESPACE_END
BufferedTransformation
Interface for buffered transformations.
Definition: cryptlib.h:1657
DataDecryptor
Password-based Decryptor.
Definition: default.h:117
DataDecryptor::DataDecryptor
DataDecryptor(const char *passphrase, BufferedTransformation *attachment=NULL, bool throwException=true)
Constructs a DataDecryptor.
Definition: default.cpp:142
DataDecryptorWithMAC
Password-based decryptor with MAC.
Definition: default.h:219
DataDecryptorWithMAC::DataDecryptorWithMAC
DataDecryptorWithMAC(const char *passphrase, BufferedTransformation *attachment=NULL, bool throwException=true)
Constructs a DataDecryptor.
Definition: default.cpp:257
DataEncryptor
Password-based Encryptor.
Definition: default.h:79
DataEncryptor::DataEncryptor
DataEncryptor(const char *passphrase, BufferedTransformation *attachment=NULL)
Construct a DataEncryptor.
Definition: default.cpp:85
DataEncryptorWithMAC
Password-based encryptor with MAC.
Definition: default.h:174
DataEncryptorWithMAC::DataEncryptorWithMAC
DataEncryptorWithMAC(const char *passphrase, BufferedTransformation *attachment=NULL)
Constructs a DataEncryptorWithMAC.
Definition: default.cpp:232
HashFilter
Filter wrapper for HashTransformation.
Definition: filters.h:582
HashVerificationFilter
Filter wrapper for HashTransformation.
Definition: filters.h:611
HashVerificationFilter::PUT_MESSAGE
@ PUT_MESSAGE
The message should be passed to an attached transformation.
Definition: filters.h:632
InvalidArgument
An invalid argument was detected.
Definition: cryptlib.h:208
KeyBadErr
Exception thrown when a bad key is encountered in DefaultDecryptorWithMAC and LegacyDecryptorWithMAC.
Definition: default.h:43
MACBadErr
Exception thrown when an incorrect MAC is encountered in DefaultDecryptorWithMAC and LegacyDecryptorW...
Definition: default.h:50
ProxyFilter
Base class for Filter classes that are proxies for a chain of other filters.
Definition: filters.h:1039
ProxyFilter::SetFilter
void SetFilter(Filter *filter)
Sets the OutputProxy filter.
SecByteBlock
SecBlock<byte> typedef.
Definition: secblock.h:1226
StreamTransformationFilter
Filter wrapper for StreamTransformation.
Definition: filters.h:532
member_ptr
Pointer that overloads operator ->
Definition: smartptr.h:38
config.h
Library configuration file.
byte
unsigned char byte
8-bit unsigned datatype
Definition: config_int.h:66
cryptlib.h
Abstract base classes that provide a uniform interface to this library.
default.h
Classes for DefaultEncryptor, DefaultDecryptor, DefaultEncryptorWithMAC and DefaultDecryptorWithMAC.
filters.h
Implementation of BufferedTransformation's attachment interface.
BytePrecision
unsigned int BytePrecision(const T &value)
Returns the number of 8-bit bytes or octets required for a value.
Definition: misc.h:1024
RoundUpToMultipleOf
T1 RoundUpToMultipleOf(const T1 &n, const T2 &m)
Rounds a value up to a multiple of a second value.
Definition: misc.h:1384
CRYPTOPP_COMPILE_ASSERT
#define CRYPTOPP_COMPILE_ASSERT(expr)
Compile time assertion.
Definition: misc.h:153
EnumToInt
#define EnumToInt(v)
Integer value.
Definition: misc.h:504
STDMAX
const T & STDMAX(const T &a, const T &b)
Replacement function for std::max.
Definition: misc.h:668
VerifyBufsEqual
CRYPTOPP_DLL bool VerifyBufsEqual(const byte *buf1, const byte *buf2, size_t count)
Performs a near constant-time comparison of two equally sized buffers.
CryptoPP
Crypto++ library namespace.
Name::IV
const char * IV()
ConstByteArrayParameter, also accepts const byte * for backwards compatibility.
Definition: argnames.h:21
pch.h
Precompiled header file.
queue.h
Classes for an unlimited queue to store bytes.
smartptr.h
Classes for automatic resource management.
DataParametersInfo
Algorithm information for password-based encryptors and decryptors.
Definition: default.h:58