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
9NAMESPACE_BEGIN(CryptoPP)
10
11static const unsigned int MASH_ITERATIONS = 200;
12static const unsigned int SALTLENGTH = 8;
13static const unsigned int BLOCKSIZE = Default_BlockCipher::Encryption::BLOCKSIZE;
14static 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
22static 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
59static 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
72DefaultEncryptor::DefaultEncryptor(const char *passphrase, BufferedTransformation *attachment)
73	: ProxyFilter(NULL, 0, 0, attachment), m_passphrase((const byte *)passphrase, strlen(passphrase))
74{
75}
76
77DefaultEncryptor::DefaultEncryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment)
78	: ProxyFilter(NULL, 0, 0, attachment), m_passphrase(passphrase, passphraseLength)
79{
80}
81
82
83void 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
118void DefaultEncryptor::LastPut(const byte *inString, size_t length)
119{
120	m_filter->MessageEnd();
121}
122
123// ********************************************************
124
125DefaultDecryptor::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
133DefaultDecryptor::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
141void DefaultDecryptor::FirstPut(const byte *inString)
142{
143	CheckKey(inString, inString+SALTLENGTH);
144}
145
146void 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
161void 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
195static 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
204DefaultEncryptorWithMAC::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
211DefaultEncryptorWithMAC::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
218void DefaultEncryptorWithMAC::LastPut(const byte *inString, size_t length)
219{
220	m_filter->MessageEnd();
221}
222
223// ********************************************************
224
225DefaultDecryptorWithMAC::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
233DefaultDecryptorWithMAC::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
241DefaultDecryptor::State DefaultDecryptorWithMAC::CurrentState() const
242{
243	return static_cast<const DefaultDecryptor *>(m_filter.get())->CurrentState();
244}
245
246bool DefaultDecryptorWithMAC::CheckLastMAC() const
247{
248	return m_hashVerifier->GetLastResult();
249}
250
251void DefaultDecryptorWithMAC::LastPut(const byte *inString, size_t length)
252{
253	m_filter->MessageEnd();
254	if (m_throwException && !CheckLastMAC())
255		throw MACBadErr();
256}
257
258NAMESPACE_END
259