rlm@1
|
1 // Crypto/WzAes.cpp
|
rlm@1
|
2 /*
|
rlm@1
|
3 This code implements Brian Gladman's scheme
|
rlm@1
|
4 specified in password Based File Encryption Utility.
|
rlm@1
|
5
|
rlm@1
|
6 Note: you must include MyAes.cpp to project to initialize AES tables
|
rlm@1
|
7 */
|
rlm@1
|
8
|
rlm@1
|
9 #include "StdAfx.h"
|
rlm@1
|
10
|
rlm@1
|
11 #include "../Common/StreamObjects.h"
|
rlm@1
|
12 #include "../Common/StreamUtils.h"
|
rlm@1
|
13
|
rlm@1
|
14 #include "Pbkdf2HmacSha1.h"
|
rlm@1
|
15 #include "RandGen.h"
|
rlm@1
|
16 #include "WzAes.h"
|
rlm@1
|
17
|
rlm@1
|
18 // define it if you don't want to use speed-optimized version of Pbkdf2HmacSha1
|
rlm@1
|
19 // #define _NO_WZAES_OPTIMIZATIONS
|
rlm@1
|
20
|
rlm@1
|
21 namespace NCrypto {
|
rlm@1
|
22 namespace NWzAes {
|
rlm@1
|
23
|
rlm@1
|
24 const unsigned int kAesKeySizeMax = 32;
|
rlm@1
|
25
|
rlm@1
|
26 static const UInt32 kNumKeyGenIterations = 1000;
|
rlm@1
|
27
|
rlm@1
|
28 STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)
|
rlm@1
|
29 {
|
rlm@1
|
30 if(size > kPasswordSizeMax)
|
rlm@1
|
31 return E_INVALIDARG;
|
rlm@1
|
32 _key.Password.SetCapacity(size);
|
rlm@1
|
33 memcpy(_key.Password, data, size);
|
rlm@1
|
34 return S_OK;
|
rlm@1
|
35 }
|
rlm@1
|
36
|
rlm@1
|
37 #define SetUi32(p, d) { UInt32 x = (d); (p)[0] = (Byte)x; (p)[1] = (Byte)(x >> 8); \
|
rlm@1
|
38 (p)[2] = (Byte)(x >> 16); (p)[3] = (Byte)(x >> 24); }
|
rlm@1
|
39
|
rlm@1
|
40 void CBaseCoder::EncryptData(Byte *data, UInt32 size)
|
rlm@1
|
41 {
|
rlm@1
|
42 unsigned int pos = _blockPos;
|
rlm@1
|
43 for (; size > 0; size--)
|
rlm@1
|
44 {
|
rlm@1
|
45 if (pos == AES_BLOCK_SIZE)
|
rlm@1
|
46 {
|
rlm@1
|
47 if (++_counter[0] == 0)
|
rlm@1
|
48 _counter[1]++;
|
rlm@1
|
49 UInt32 temp[4];
|
rlm@1
|
50 Aes_Encode32(&Aes, temp, _counter);
|
rlm@1
|
51 SetUi32(_buffer, temp[0]);
|
rlm@1
|
52 SetUi32(_buffer + 4, temp[1]);
|
rlm@1
|
53 SetUi32(_buffer + 8, temp[2]);
|
rlm@1
|
54 SetUi32(_buffer + 12, temp[3]);
|
rlm@1
|
55 pos = 0;
|
rlm@1
|
56 }
|
rlm@1
|
57 *data++ ^= _buffer[pos++];
|
rlm@1
|
58 }
|
rlm@1
|
59 _blockPos = pos;
|
rlm@1
|
60 }
|
rlm@1
|
61
|
rlm@1
|
62 #ifndef _NO_WZAES_OPTIMIZATIONS
|
rlm@1
|
63
|
rlm@1
|
64 static void BytesToBeUInt32s(const Byte *src, UInt32 *dest, int destSize)
|
rlm@1
|
65 {
|
rlm@1
|
66 for (int i = 0 ; i < destSize; i++)
|
rlm@1
|
67 dest[i] =
|
rlm@1
|
68 ((UInt32)(src[i * 4 + 0]) << 24) |
|
rlm@1
|
69 ((UInt32)(src[i * 4 + 1]) << 16) |
|
rlm@1
|
70 ((UInt32)(src[i * 4 + 2]) << 8) |
|
rlm@1
|
71 ((UInt32)(src[i * 4 + 3]));
|
rlm@1
|
72 }
|
rlm@1
|
73
|
rlm@1
|
74 #endif
|
rlm@1
|
75
|
rlm@1
|
76 STDMETHODIMP CBaseCoder::Init()
|
rlm@1
|
77 {
|
rlm@1
|
78 UInt32 keySize = _key.GetKeySize();
|
rlm@1
|
79 UInt32 keysTotalSize = 2 * keySize + kPwdVerifCodeSize;
|
rlm@1
|
80 Byte buf[2 * kAesKeySizeMax + kPwdVerifCodeSize];
|
rlm@1
|
81
|
rlm@1
|
82 // for (int ii = 0; ii < 1000; ii++)
|
rlm@1
|
83 {
|
rlm@1
|
84 #ifdef _NO_WZAES_OPTIMIZATIONS
|
rlm@1
|
85
|
rlm@1
|
86 NSha1::Pbkdf2Hmac(
|
rlm@1
|
87 _key.Password, _key.Password.GetCapacity(),
|
rlm@1
|
88 _key.Salt, _key.GetSaltSize(),
|
rlm@1
|
89 kNumKeyGenIterations,
|
rlm@1
|
90 buf, keysTotalSize);
|
rlm@1
|
91
|
rlm@1
|
92 #else
|
rlm@1
|
93
|
rlm@1
|
94 UInt32 buf32[(2 * kAesKeySizeMax + kPwdVerifCodeSize + 3) / 4];
|
rlm@1
|
95 UInt32 key32SizeTotal = (keysTotalSize + 3) / 4;
|
rlm@1
|
96 UInt32 salt[kSaltSizeMax * 4];
|
rlm@1
|
97 UInt32 saltSizeInWords = _key.GetSaltSize() / 4;
|
rlm@1
|
98 BytesToBeUInt32s(_key.Salt, salt, saltSizeInWords);
|
rlm@1
|
99 NSha1::Pbkdf2Hmac32(
|
rlm@1
|
100 _key.Password, _key.Password.GetCapacity(),
|
rlm@1
|
101 salt, saltSizeInWords,
|
rlm@1
|
102 kNumKeyGenIterations,
|
rlm@1
|
103 buf32, key32SizeTotal);
|
rlm@1
|
104 for (UInt32 j = 0; j < keysTotalSize; j++)
|
rlm@1
|
105 buf[j] = (Byte)(buf32[j / 4] >> (24 - 8 * (j & 3)));
|
rlm@1
|
106
|
rlm@1
|
107 #endif
|
rlm@1
|
108 }
|
rlm@1
|
109
|
rlm@1
|
110 _hmac.SetKey(buf + keySize, keySize);
|
rlm@1
|
111 memcpy(_key.PwdVerifComputed, buf + 2 * keySize, kPwdVerifCodeSize);
|
rlm@1
|
112
|
rlm@1
|
113 _blockPos = AES_BLOCK_SIZE;
|
rlm@1
|
114 for (int i = 0; i < 4; i++)
|
rlm@1
|
115 _counter[i] = 0;
|
rlm@1
|
116
|
rlm@1
|
117 Aes_SetKeyEncode(&Aes, buf, keySize);
|
rlm@1
|
118 return S_OK;
|
rlm@1
|
119 }
|
rlm@1
|
120
|
rlm@1
|
121 /*
|
rlm@1
|
122 STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
|
rlm@1
|
123 {
|
rlm@1
|
124 Byte keySizeMode = 3;
|
rlm@1
|
125 return outStream->Write(&keySizeMode, 1, NULL);
|
rlm@1
|
126 }
|
rlm@1
|
127 */
|
rlm@1
|
128
|
rlm@1
|
129 HRESULT CEncoder::WriteHeader(ISequentialOutStream *outStream)
|
rlm@1
|
130 {
|
rlm@1
|
131 UInt32 saltSize = _key.GetSaltSize();
|
rlm@1
|
132 g_RandomGenerator.Generate(_key.Salt, saltSize);
|
rlm@1
|
133 Init();
|
rlm@1
|
134 RINOK(WriteStream(outStream, _key.Salt, saltSize));
|
rlm@1
|
135 return WriteStream(outStream, _key.PwdVerifComputed, kPwdVerifCodeSize);
|
rlm@1
|
136 }
|
rlm@1
|
137
|
rlm@1
|
138 HRESULT CEncoder::WriteFooter(ISequentialOutStream *outStream)
|
rlm@1
|
139 {
|
rlm@1
|
140 Byte mac[kMacSize];
|
rlm@1
|
141 _hmac.Final(mac, kMacSize);
|
rlm@1
|
142 return WriteStream(outStream, mac, kMacSize);
|
rlm@1
|
143 }
|
rlm@1
|
144
|
rlm@1
|
145 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
|
rlm@1
|
146 {
|
rlm@1
|
147 if (size != 1)
|
rlm@1
|
148 return E_INVALIDARG;
|
rlm@1
|
149 _key.Init();
|
rlm@1
|
150 Byte keySizeMode = data[0];
|
rlm@1
|
151 if (keySizeMode < 1 || keySizeMode > 3)
|
rlm@1
|
152 return E_INVALIDARG;
|
rlm@1
|
153 _key.KeySizeMode = keySizeMode;
|
rlm@1
|
154 return S_OK;
|
rlm@1
|
155 }
|
rlm@1
|
156
|
rlm@1
|
157 HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream)
|
rlm@1
|
158 {
|
rlm@1
|
159 UInt32 saltSize = _key.GetSaltSize();
|
rlm@1
|
160 UInt32 extraSize = saltSize + kPwdVerifCodeSize;
|
rlm@1
|
161 Byte temp[kSaltSizeMax + kPwdVerifCodeSize];
|
rlm@1
|
162 RINOK(ReadStream_FAIL(inStream, temp, extraSize));
|
rlm@1
|
163 UInt32 i;
|
rlm@1
|
164 for (i = 0; i < saltSize; i++)
|
rlm@1
|
165 _key.Salt[i] = temp[i];
|
rlm@1
|
166 for (i = 0; i < kPwdVerifCodeSize; i++)
|
rlm@1
|
167 _pwdVerifFromArchive[i] = temp[saltSize + i];
|
rlm@1
|
168 return S_OK;
|
rlm@1
|
169 }
|
rlm@1
|
170
|
rlm@1
|
171 static bool CompareArrays(const Byte *p1, const Byte *p2, UInt32 size)
|
rlm@1
|
172 {
|
rlm@1
|
173 for (UInt32 i = 0; i < size; i++)
|
rlm@1
|
174 if (p1[i] != p2[i])
|
rlm@1
|
175 return false;
|
rlm@1
|
176 return true;
|
rlm@1
|
177 }
|
rlm@1
|
178
|
rlm@1
|
179 bool CDecoder::CheckPasswordVerifyCode()
|
rlm@1
|
180 {
|
rlm@1
|
181 return CompareArrays(_key.PwdVerifComputed, _pwdVerifFromArchive, kPwdVerifCodeSize);
|
rlm@1
|
182 }
|
rlm@1
|
183
|
rlm@1
|
184 HRESULT CDecoder::CheckMac(ISequentialInStream *inStream, bool &isOK)
|
rlm@1
|
185 {
|
rlm@1
|
186 isOK = false;
|
rlm@1
|
187 Byte mac1[kMacSize];
|
rlm@1
|
188 RINOK(ReadStream_FAIL(inStream, mac1, kMacSize));
|
rlm@1
|
189 Byte mac2[kMacSize];
|
rlm@1
|
190 _hmac.Final(mac2, kMacSize);
|
rlm@1
|
191 isOK = CompareArrays(mac1, mac2, kMacSize);
|
rlm@1
|
192 return S_OK;
|
rlm@1
|
193 }
|
rlm@1
|
194
|
rlm@1
|
195 STDMETHODIMP_(UInt32) CEncoder::Filter(Byte *data, UInt32 size)
|
rlm@1
|
196 {
|
rlm@1
|
197 EncryptData(data, size);
|
rlm@1
|
198 _hmac.Update(data, size);
|
rlm@1
|
199 return size;
|
rlm@1
|
200 }
|
rlm@1
|
201
|
rlm@1
|
202 STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size)
|
rlm@1
|
203 {
|
rlm@1
|
204 _hmac.Update(data, size);
|
rlm@1
|
205 EncryptData(data, size);
|
rlm@1
|
206 return size;
|
rlm@1
|
207 }
|
rlm@1
|
208
|
rlm@1
|
209 }}
|