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