1*f6dc9357SAndroid Build Coastguard Worker // Crypto/WzAes.cpp
2*f6dc9357SAndroid Build Coastguard Worker /*
3*f6dc9357SAndroid Build Coastguard Worker This code implements Brian Gladman's scheme
4*f6dc9357SAndroid Build Coastguard Worker specified in "A Password Based File Encryption Utility".
5*f6dc9357SAndroid Build Coastguard Worker
6*f6dc9357SAndroid Build Coastguard Worker Note: you must include MyAes.cpp to project to initialize AES tables
7*f6dc9357SAndroid Build Coastguard Worker */
8*f6dc9357SAndroid Build Coastguard Worker
9*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
10*f6dc9357SAndroid Build Coastguard Worker
11*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/CpuArch.h"
12*f6dc9357SAndroid Build Coastguard Worker
13*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
14*f6dc9357SAndroid Build Coastguard Worker
15*f6dc9357SAndroid Build Coastguard Worker #include "Pbkdf2HmacSha1.h"
16*f6dc9357SAndroid Build Coastguard Worker #include "RandGen.h"
17*f6dc9357SAndroid Build Coastguard Worker #include "WzAes.h"
18*f6dc9357SAndroid Build Coastguard Worker
19*f6dc9357SAndroid Build Coastguard Worker namespace NCrypto {
20*f6dc9357SAndroid Build Coastguard Worker namespace NWzAes {
21*f6dc9357SAndroid Build Coastguard Worker
22*f6dc9357SAndroid Build Coastguard Worker const unsigned kAesKeySizeMax = 32;
23*f6dc9357SAndroid Build Coastguard Worker
24*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kNumKeyGenIterations = 1000;
25*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CBaseCoder::CryptoSetPassword (const Byte * data,UInt32 size))26*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size))
27*f6dc9357SAndroid Build Coastguard Worker {
28*f6dc9357SAndroid Build Coastguard Worker if (size > kPasswordSizeMax)
29*f6dc9357SAndroid Build Coastguard Worker return E_INVALIDARG;
30*f6dc9357SAndroid Build Coastguard Worker _key.Password.Wipe();
31*f6dc9357SAndroid Build Coastguard Worker _key.Password.CopyFrom(data, (size_t)size);
32*f6dc9357SAndroid Build Coastguard Worker return S_OK;
33*f6dc9357SAndroid Build Coastguard Worker }
34*f6dc9357SAndroid Build Coastguard Worker
Init2()35*f6dc9357SAndroid Build Coastguard Worker void CBaseCoder::Init2()
36*f6dc9357SAndroid Build Coastguard Worker {
37*f6dc9357SAndroid Build Coastguard Worker _hmacOverCalc = 0;
38*f6dc9357SAndroid Build Coastguard Worker const unsigned dkSizeMax32 = (2 * kAesKeySizeMax + kPwdVerifSize + 3) / 4;
39*f6dc9357SAndroid Build Coastguard Worker Byte dk[dkSizeMax32 * 4];
40*f6dc9357SAndroid Build Coastguard Worker
41*f6dc9357SAndroid Build Coastguard Worker const unsigned keySize = _key.GetKeySize();
42*f6dc9357SAndroid Build Coastguard Worker const unsigned dkSize = 2 * keySize + ((kPwdVerifSize + 3) & ~(unsigned)3);
43*f6dc9357SAndroid Build Coastguard Worker
44*f6dc9357SAndroid Build Coastguard Worker // for (unsigned ii = 0; ii < 1000; ii++)
45*f6dc9357SAndroid Build Coastguard Worker {
46*f6dc9357SAndroid Build Coastguard Worker NSha1::Pbkdf2Hmac(
47*f6dc9357SAndroid Build Coastguard Worker _key.Password, _key.Password.Size(),
48*f6dc9357SAndroid Build Coastguard Worker _key.Salt, _key.GetSaltSize(),
49*f6dc9357SAndroid Build Coastguard Worker kNumKeyGenIterations,
50*f6dc9357SAndroid Build Coastguard Worker dk, dkSize);
51*f6dc9357SAndroid Build Coastguard Worker }
52*f6dc9357SAndroid Build Coastguard Worker
53*f6dc9357SAndroid Build Coastguard Worker Hmac()->SetKey(dk + keySize, keySize);
54*f6dc9357SAndroid Build Coastguard Worker memcpy(_key.PwdVerifComputed, dk + 2 * keySize, kPwdVerifSize);
55*f6dc9357SAndroid Build Coastguard Worker
56*f6dc9357SAndroid Build Coastguard Worker // Aes_SetKey_Enc(_aes.Aes() + 8, dk, keySize);
57*f6dc9357SAndroid Build Coastguard Worker // AesCtr2_Init(&_aes);
58*f6dc9357SAndroid Build Coastguard Worker _aesCoderSpec->SetKeySize(keySize);
59*f6dc9357SAndroid Build Coastguard Worker if (_aesCoderSpec->SetKey(dk, keySize) != S_OK) throw 2;
60*f6dc9357SAndroid Build Coastguard Worker if (_aesCoderSpec->Init() != S_OK) throw 3;
61*f6dc9357SAndroid Build Coastguard Worker }
62*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CBaseCoder::Init ())63*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CBaseCoder::Init())
64*f6dc9357SAndroid Build Coastguard Worker {
65*f6dc9357SAndroid Build Coastguard Worker return S_OK;
66*f6dc9357SAndroid Build Coastguard Worker }
67*f6dc9357SAndroid Build Coastguard Worker
WriteHeader(ISequentialOutStream * outStream)68*f6dc9357SAndroid Build Coastguard Worker HRESULT CEncoder::WriteHeader(ISequentialOutStream *outStream)
69*f6dc9357SAndroid Build Coastguard Worker {
70*f6dc9357SAndroid Build Coastguard Worker unsigned saltSize = _key.GetSaltSize();
71*f6dc9357SAndroid Build Coastguard Worker MY_RAND_GEN(_key.Salt, saltSize);
72*f6dc9357SAndroid Build Coastguard Worker Init2();
73*f6dc9357SAndroid Build Coastguard Worker RINOK(WriteStream(outStream, _key.Salt, saltSize))
74*f6dc9357SAndroid Build Coastguard Worker return WriteStream(outStream, _key.PwdVerifComputed, kPwdVerifSize);
75*f6dc9357SAndroid Build Coastguard Worker }
76*f6dc9357SAndroid Build Coastguard Worker
WriteFooter(ISequentialOutStream * outStream)77*f6dc9357SAndroid Build Coastguard Worker HRESULT CEncoder::WriteFooter(ISequentialOutStream *outStream)
78*f6dc9357SAndroid Build Coastguard Worker {
79*f6dc9357SAndroid Build Coastguard Worker MY_ALIGN (16)
80*f6dc9357SAndroid Build Coastguard Worker UInt32 mac[NSha1::kNumDigestWords];
81*f6dc9357SAndroid Build Coastguard Worker Hmac()->Final((Byte *)mac);
82*f6dc9357SAndroid Build Coastguard Worker return WriteStream(outStream, mac, kMacSize);
83*f6dc9357SAndroid Build Coastguard Worker }
84*f6dc9357SAndroid Build Coastguard Worker
85*f6dc9357SAndroid Build Coastguard Worker /*
86*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size))
87*f6dc9357SAndroid Build Coastguard Worker {
88*f6dc9357SAndroid Build Coastguard Worker if (size != 1)
89*f6dc9357SAndroid Build Coastguard Worker return E_INVALIDARG;
90*f6dc9357SAndroid Build Coastguard Worker _key.Init();
91*f6dc9357SAndroid Build Coastguard Worker return SetKeyMode(data[0]) ? S_OK : E_INVALIDARG;
92*f6dc9357SAndroid Build Coastguard Worker }
93*f6dc9357SAndroid Build Coastguard Worker */
94*f6dc9357SAndroid Build Coastguard Worker
ReadHeader(ISequentialInStream * inStream)95*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream)
96*f6dc9357SAndroid Build Coastguard Worker {
97*f6dc9357SAndroid Build Coastguard Worker const unsigned saltSize = _key.GetSaltSize();
98*f6dc9357SAndroid Build Coastguard Worker const unsigned extraSize = saltSize + kPwdVerifSize;
99*f6dc9357SAndroid Build Coastguard Worker Byte temp[kSaltSizeMax + kPwdVerifSize];
100*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FAIL(inStream, temp, extraSize))
101*f6dc9357SAndroid Build Coastguard Worker unsigned i;
102*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < saltSize; i++)
103*f6dc9357SAndroid Build Coastguard Worker _key.Salt[i] = temp[i];
104*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < kPwdVerifSize; i++)
105*f6dc9357SAndroid Build Coastguard Worker _pwdVerifFromArchive[i] = temp[saltSize + i];
106*f6dc9357SAndroid Build Coastguard Worker return S_OK;
107*f6dc9357SAndroid Build Coastguard Worker }
108*f6dc9357SAndroid Build Coastguard Worker
CompareArrays(const Byte * p1,const Byte * p2,unsigned size)109*f6dc9357SAndroid Build Coastguard Worker static inline bool CompareArrays(const Byte *p1, const Byte *p2, unsigned size)
110*f6dc9357SAndroid Build Coastguard Worker {
111*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < size; i++)
112*f6dc9357SAndroid Build Coastguard Worker if (p1[i] != p2[i])
113*f6dc9357SAndroid Build Coastguard Worker return false;
114*f6dc9357SAndroid Build Coastguard Worker return true;
115*f6dc9357SAndroid Build Coastguard Worker }
116*f6dc9357SAndroid Build Coastguard Worker
Init_and_CheckPassword()117*f6dc9357SAndroid Build Coastguard Worker bool CDecoder::Init_and_CheckPassword()
118*f6dc9357SAndroid Build Coastguard Worker {
119*f6dc9357SAndroid Build Coastguard Worker Init2();
120*f6dc9357SAndroid Build Coastguard Worker return CompareArrays(_key.PwdVerifComputed, _pwdVerifFromArchive, kPwdVerifSize);
121*f6dc9357SAndroid Build Coastguard Worker }
122*f6dc9357SAndroid Build Coastguard Worker
CheckMac(ISequentialInStream * inStream,bool & isOK)123*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::CheckMac(ISequentialInStream *inStream, bool &isOK)
124*f6dc9357SAndroid Build Coastguard Worker {
125*f6dc9357SAndroid Build Coastguard Worker isOK = false;
126*f6dc9357SAndroid Build Coastguard Worker MY_ALIGN (16)
127*f6dc9357SAndroid Build Coastguard Worker Byte mac1[kMacSize];
128*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FAIL(inStream, mac1, kMacSize))
129*f6dc9357SAndroid Build Coastguard Worker MY_ALIGN (16)
130*f6dc9357SAndroid Build Coastguard Worker UInt32 mac2[NSha1::kNumDigestWords];
131*f6dc9357SAndroid Build Coastguard Worker Hmac()->Final((Byte *)mac2);
132*f6dc9357SAndroid Build Coastguard Worker isOK = CompareArrays(mac1, (const Byte *)mac2, kMacSize);
133*f6dc9357SAndroid Build Coastguard Worker if (_hmacOverCalc)
134*f6dc9357SAndroid Build Coastguard Worker isOK = false;
135*f6dc9357SAndroid Build Coastguard Worker return S_OK;
136*f6dc9357SAndroid Build Coastguard Worker }
137*f6dc9357SAndroid Build Coastguard Worker
138*f6dc9357SAndroid Build Coastguard Worker /*
139*f6dc9357SAndroid Build Coastguard Worker
140*f6dc9357SAndroid Build Coastguard Worker CAesCtr2::CAesCtr2():
141*f6dc9357SAndroid Build Coastguard Worker aes((4 + AES_NUM_IVMRK_WORDS) * 4)
142*f6dc9357SAndroid Build Coastguard Worker {
143*f6dc9357SAndroid Build Coastguard Worker // offset = ((0 - (unsigned)(ptrdiff_t)aes) & 0xF) / sizeof(UInt32);
144*f6dc9357SAndroid Build Coastguard Worker // first 16 bytes are buffer for last block data.
145*f6dc9357SAndroid Build Coastguard Worker // so the ivAES is aligned for (Align + 16).
146*f6dc9357SAndroid Build Coastguard Worker }
147*f6dc9357SAndroid Build Coastguard Worker
148*f6dc9357SAndroid Build Coastguard Worker void AesCtr2_Init(CAesCtr2 *p)
149*f6dc9357SAndroid Build Coastguard Worker {
150*f6dc9357SAndroid Build Coastguard Worker UInt32 *ctr = p->Aes() + 4;
151*f6dc9357SAndroid Build Coastguard Worker unsigned i;
152*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < 4; i++)
153*f6dc9357SAndroid Build Coastguard Worker ctr[i] = 0;
154*f6dc9357SAndroid Build Coastguard Worker p->pos = AES_BLOCK_SIZE;
155*f6dc9357SAndroid Build Coastguard Worker }
156*f6dc9357SAndroid Build Coastguard Worker
157*f6dc9357SAndroid Build Coastguard Worker // (size != 16 * N) is allowed only for last call
158*f6dc9357SAndroid Build Coastguard Worker
159*f6dc9357SAndroid Build Coastguard Worker void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size)
160*f6dc9357SAndroid Build Coastguard Worker {
161*f6dc9357SAndroid Build Coastguard Worker unsigned pos = p->pos;
162*f6dc9357SAndroid Build Coastguard Worker UInt32 *buf32 = p->Aes();
163*f6dc9357SAndroid Build Coastguard Worker if (size == 0)
164*f6dc9357SAndroid Build Coastguard Worker return;
165*f6dc9357SAndroid Build Coastguard Worker
166*f6dc9357SAndroid Build Coastguard Worker if (pos != AES_BLOCK_SIZE)
167*f6dc9357SAndroid Build Coastguard Worker {
168*f6dc9357SAndroid Build Coastguard Worker const Byte *buf = (const Byte *)buf32;
169*f6dc9357SAndroid Build Coastguard Worker do
170*f6dc9357SAndroid Build Coastguard Worker *data++ ^= buf[pos++];
171*f6dc9357SAndroid Build Coastguard Worker while (--size != 0 && pos != AES_BLOCK_SIZE);
172*f6dc9357SAndroid Build Coastguard Worker }
173*f6dc9357SAndroid Build Coastguard Worker
174*f6dc9357SAndroid Build Coastguard Worker // (size == 0 || pos == AES_BLOCK_SIZE)
175*f6dc9357SAndroid Build Coastguard Worker
176*f6dc9357SAndroid Build Coastguard Worker if (size >= 16)
177*f6dc9357SAndroid Build Coastguard Worker {
178*f6dc9357SAndroid Build Coastguard Worker SizeT size2 = size >> 4;
179*f6dc9357SAndroid Build Coastguard Worker g_AesCtr_Code(buf32 + 4, data, size2);
180*f6dc9357SAndroid Build Coastguard Worker size2 <<= 4;
181*f6dc9357SAndroid Build Coastguard Worker data += size2;
182*f6dc9357SAndroid Build Coastguard Worker size -= size2;
183*f6dc9357SAndroid Build Coastguard Worker // (pos == AES_BLOCK_SIZE)
184*f6dc9357SAndroid Build Coastguard Worker }
185*f6dc9357SAndroid Build Coastguard Worker
186*f6dc9357SAndroid Build Coastguard Worker // (size < 16)
187*f6dc9357SAndroid Build Coastguard Worker
188*f6dc9357SAndroid Build Coastguard Worker if (size != 0)
189*f6dc9357SAndroid Build Coastguard Worker {
190*f6dc9357SAndroid Build Coastguard Worker unsigned j;
191*f6dc9357SAndroid Build Coastguard Worker const Byte *buf;
192*f6dc9357SAndroid Build Coastguard Worker for (j = 0; j < 4; j++)
193*f6dc9357SAndroid Build Coastguard Worker buf32[j] = 0;
194*f6dc9357SAndroid Build Coastguard Worker g_AesCtr_Code(buf32 + 4, (Byte *)buf32, 1);
195*f6dc9357SAndroid Build Coastguard Worker buf = (const Byte *)buf32;
196*f6dc9357SAndroid Build Coastguard Worker pos = 0;
197*f6dc9357SAndroid Build Coastguard Worker do
198*f6dc9357SAndroid Build Coastguard Worker *data++ ^= buf[pos++];
199*f6dc9357SAndroid Build Coastguard Worker while (--size != 0);
200*f6dc9357SAndroid Build Coastguard Worker }
201*f6dc9357SAndroid Build Coastguard Worker
202*f6dc9357SAndroid Build Coastguard Worker p->pos = pos;
203*f6dc9357SAndroid Build Coastguard Worker }
204*f6dc9357SAndroid Build Coastguard Worker */
205*f6dc9357SAndroid Build Coastguard Worker
206*f6dc9357SAndroid Build Coastguard Worker /* (size != 16 * N) is allowed only for last Filter() call */
207*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF2(UInt32,CEncoder::Filter (Byte * data,UInt32 size))208*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF2(UInt32, CEncoder::Filter(Byte *data, UInt32 size))
209*f6dc9357SAndroid Build Coastguard Worker {
210*f6dc9357SAndroid Build Coastguard Worker // AesCtr2_Code(&_aes, data, size);
211*f6dc9357SAndroid Build Coastguard Worker size = _aesCoder->Filter(data, size);
212*f6dc9357SAndroid Build Coastguard Worker Hmac()->Update(data, size);
213*f6dc9357SAndroid Build Coastguard Worker return size;
214*f6dc9357SAndroid Build Coastguard Worker }
215*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF2(UInt32,CDecoder::Filter (Byte * data,UInt32 size))216*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size))
217*f6dc9357SAndroid Build Coastguard Worker {
218*f6dc9357SAndroid Build Coastguard Worker if (size >= 16)
219*f6dc9357SAndroid Build Coastguard Worker size &= ~(UInt32)15;
220*f6dc9357SAndroid Build Coastguard Worker if (_hmacOverCalc < size)
221*f6dc9357SAndroid Build Coastguard Worker {
222*f6dc9357SAndroid Build Coastguard Worker Hmac()->Update(data + _hmacOverCalc, size - _hmacOverCalc);
223*f6dc9357SAndroid Build Coastguard Worker _hmacOverCalc = size;
224*f6dc9357SAndroid Build Coastguard Worker }
225*f6dc9357SAndroid Build Coastguard Worker // AesCtr2_Code(&_aes, data, size);
226*f6dc9357SAndroid Build Coastguard Worker size = _aesCoder->Filter(data, size);
227*f6dc9357SAndroid Build Coastguard Worker _hmacOverCalc -= size;
228*f6dc9357SAndroid Build Coastguard Worker return size;
229*f6dc9357SAndroid Build Coastguard Worker }
230*f6dc9357SAndroid Build Coastguard Worker
231*f6dc9357SAndroid Build Coastguard Worker }}
232