rlm@1
|
1 // 7zAes.cpp
|
rlm@1
|
2
|
rlm@1
|
3 #include "StdAfx.h"
|
rlm@1
|
4
|
rlm@1
|
5 extern "C"
|
rlm@1
|
6 {
|
rlm@1
|
7 #include "../../../C/Sha256.h"
|
rlm@1
|
8 }
|
rlm@1
|
9
|
rlm@1
|
10 #include "Windows/Synchronization.h"
|
rlm@1
|
11 #include "../Common/StreamObjects.h"
|
rlm@1
|
12 #include "../Common/StreamUtils.h"
|
rlm@1
|
13 #include "7zAes.h"
|
rlm@1
|
14 #include "MyAes.h"
|
rlm@1
|
15
|
rlm@1
|
16 #ifndef EXTRACT_ONLY
|
rlm@1
|
17 #include "RandGen.h"
|
rlm@1
|
18 #endif
|
rlm@1
|
19
|
rlm@1
|
20 using namespace NWindows;
|
rlm@1
|
21
|
rlm@1
|
22 namespace NCrypto {
|
rlm@1
|
23 namespace NSevenZ {
|
rlm@1
|
24
|
rlm@1
|
25 bool CKeyInfo::IsEqualTo(const CKeyInfo &a) const
|
rlm@1
|
26 {
|
rlm@1
|
27 if (SaltSize != a.SaltSize || NumCyclesPower != a.NumCyclesPower)
|
rlm@1
|
28 return false;
|
rlm@1
|
29 for (UInt32 i = 0; i < SaltSize; i++)
|
rlm@1
|
30 if (Salt[i] != a.Salt[i])
|
rlm@1
|
31 return false;
|
rlm@1
|
32 return (Password == a.Password);
|
rlm@1
|
33 }
|
rlm@1
|
34
|
rlm@1
|
35 void CKeyInfo::CalculateDigest()
|
rlm@1
|
36 {
|
rlm@1
|
37 if (NumCyclesPower == 0x3F)
|
rlm@1
|
38 {
|
rlm@1
|
39 UInt32 pos;
|
rlm@1
|
40 for (pos = 0; pos < SaltSize; pos++)
|
rlm@1
|
41 Key[pos] = Salt[pos];
|
rlm@1
|
42 for (UInt32 i = 0; i < Password.GetCapacity() && pos < kKeySize; i++)
|
rlm@1
|
43 Key[pos++] = Password[i];
|
rlm@1
|
44 for (; pos < kKeySize; pos++)
|
rlm@1
|
45 Key[pos] = 0;
|
rlm@1
|
46 }
|
rlm@1
|
47 else
|
rlm@1
|
48 {
|
rlm@1
|
49 CSha256 sha;
|
rlm@1
|
50 Sha256_Init(&sha);
|
rlm@1
|
51 const UInt64 numRounds = UInt64(1) << (NumCyclesPower);
|
rlm@1
|
52 Byte temp[8] = { 0,0,0,0,0,0,0,0 };
|
rlm@1
|
53 for (UInt64 round = 0; round < numRounds; round++)
|
rlm@1
|
54 {
|
rlm@1
|
55 Sha256_Update(&sha, Salt, (size_t)SaltSize);
|
rlm@1
|
56 Sha256_Update(&sha, Password, Password.GetCapacity());
|
rlm@1
|
57 Sha256_Update(&sha, temp, 8);
|
rlm@1
|
58 for (int i = 0; i < 8; i++)
|
rlm@1
|
59 if (++(temp[i]) != 0)
|
rlm@1
|
60 break;
|
rlm@1
|
61 }
|
rlm@1
|
62 Sha256_Final(&sha, Key);
|
rlm@1
|
63 }
|
rlm@1
|
64 }
|
rlm@1
|
65
|
rlm@1
|
66 bool CKeyInfoCache::Find(CKeyInfo &key)
|
rlm@1
|
67 {
|
rlm@1
|
68 for (int i = 0; i < Keys.Size(); i++)
|
rlm@1
|
69 {
|
rlm@1
|
70 const CKeyInfo &cached = Keys[i];
|
rlm@1
|
71 if (key.IsEqualTo(cached))
|
rlm@1
|
72 {
|
rlm@1
|
73 for (int j = 0; j < kKeySize; j++)
|
rlm@1
|
74 key.Key[j] = cached.Key[j];
|
rlm@1
|
75 if (i != 0)
|
rlm@1
|
76 {
|
rlm@1
|
77 Keys.Insert(0, cached);
|
rlm@1
|
78 Keys.Delete(i+1);
|
rlm@1
|
79 }
|
rlm@1
|
80 return true;
|
rlm@1
|
81 }
|
rlm@1
|
82 }
|
rlm@1
|
83 return false;
|
rlm@1
|
84 }
|
rlm@1
|
85
|
rlm@1
|
86 void CKeyInfoCache::Add(CKeyInfo &key)
|
rlm@1
|
87 {
|
rlm@1
|
88 if (Find(key))
|
rlm@1
|
89 return;
|
rlm@1
|
90 if (Keys.Size() >= Size)
|
rlm@1
|
91 Keys.DeleteBack();
|
rlm@1
|
92 Keys.Insert(0, key);
|
rlm@1
|
93 }
|
rlm@1
|
94
|
rlm@1
|
95 static CKeyInfoCache g_GlobalKeyCache(32);
|
rlm@1
|
96 static NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection;
|
rlm@1
|
97
|
rlm@1
|
98 CBase::CBase():
|
rlm@1
|
99 _cachedKeys(16),
|
rlm@1
|
100 _ivSize(0)
|
rlm@1
|
101 {
|
rlm@1
|
102 for (int i = 0; i < sizeof(_iv); i++)
|
rlm@1
|
103 _iv[i] = 0;
|
rlm@1
|
104 }
|
rlm@1
|
105
|
rlm@1
|
106 void CBase::CalculateDigest()
|
rlm@1
|
107 {
|
rlm@1
|
108 NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection);
|
rlm@1
|
109 if (_cachedKeys.Find(_key))
|
rlm@1
|
110 g_GlobalKeyCache.Add(_key);
|
rlm@1
|
111 else
|
rlm@1
|
112 {
|
rlm@1
|
113 if (!g_GlobalKeyCache.Find(_key))
|
rlm@1
|
114 {
|
rlm@1
|
115 _key.CalculateDigest();
|
rlm@1
|
116 g_GlobalKeyCache.Add(_key);
|
rlm@1
|
117 }
|
rlm@1
|
118 _cachedKeys.Add(_key);
|
rlm@1
|
119 }
|
rlm@1
|
120 }
|
rlm@1
|
121
|
rlm@1
|
122 #ifndef EXTRACT_ONLY
|
rlm@1
|
123
|
rlm@1
|
124 /*
|
rlm@1
|
125 STDMETHODIMP CEncoder::ResetSalt()
|
rlm@1
|
126 {
|
rlm@1
|
127 _key.SaltSize = 4;
|
rlm@1
|
128 g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);
|
rlm@1
|
129 return S_OK;
|
rlm@1
|
130 }
|
rlm@1
|
131 */
|
rlm@1
|
132
|
rlm@1
|
133 STDMETHODIMP CEncoder::ResetInitVector()
|
rlm@1
|
134 {
|
rlm@1
|
135 _ivSize = 8;
|
rlm@1
|
136 g_RandomGenerator.Generate(_iv, (unsigned)_ivSize);
|
rlm@1
|
137 return S_OK;
|
rlm@1
|
138 }
|
rlm@1
|
139
|
rlm@1
|
140 STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
|
rlm@1
|
141 {
|
rlm@1
|
142 // _key.Init();
|
rlm@1
|
143 for (UInt32 i = _ivSize; i < sizeof(_iv); i++)
|
rlm@1
|
144 _iv[i] = 0;
|
rlm@1
|
145
|
rlm@1
|
146 UInt32 ivSize = _ivSize;
|
rlm@1
|
147
|
rlm@1
|
148 // _key.NumCyclesPower = 0x3F;
|
rlm@1
|
149 _key.NumCyclesPower = 19;
|
rlm@1
|
150
|
rlm@1
|
151 Byte firstByte = (Byte)(_key.NumCyclesPower |
|
rlm@1
|
152 (((_key.SaltSize == 0) ? 0 : 1) << 7) |
|
rlm@1
|
153 (((ivSize == 0) ? 0 : 1) << 6));
|
rlm@1
|
154 RINOK(outStream->Write(&firstByte, 1, NULL));
|
rlm@1
|
155 if (_key.SaltSize == 0 && ivSize == 0)
|
rlm@1
|
156 return S_OK;
|
rlm@1
|
157 Byte saltSizeSpec = (Byte)((_key.SaltSize == 0) ? 0 : (_key.SaltSize - 1));
|
rlm@1
|
158 Byte ivSizeSpec = (Byte)((ivSize == 0) ? 0 : (ivSize - 1));
|
rlm@1
|
159 Byte secondByte = (Byte)(((saltSizeSpec) << 4) | ivSizeSpec);
|
rlm@1
|
160 RINOK(outStream->Write(&secondByte, 1, NULL));
|
rlm@1
|
161 if (_key.SaltSize > 0)
|
rlm@1
|
162 {
|
rlm@1
|
163 RINOK(WriteStream(outStream, _key.Salt, _key.SaltSize));
|
rlm@1
|
164 }
|
rlm@1
|
165 if (ivSize > 0)
|
rlm@1
|
166 {
|
rlm@1
|
167 RINOK(WriteStream(outStream, _iv, ivSize));
|
rlm@1
|
168 }
|
rlm@1
|
169 return S_OK;
|
rlm@1
|
170 }
|
rlm@1
|
171
|
rlm@1
|
172 HRESULT CEncoder::CreateFilter()
|
rlm@1
|
173 {
|
rlm@1
|
174 _aesFilter = new CAesCbcEncoder;
|
rlm@1
|
175 return S_OK;
|
rlm@1
|
176 }
|
rlm@1
|
177
|
rlm@1
|
178 #endif
|
rlm@1
|
179
|
rlm@1
|
180 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
|
rlm@1
|
181 {
|
rlm@1
|
182 _key.Init();
|
rlm@1
|
183 UInt32 i;
|
rlm@1
|
184 for (i = 0; i < sizeof(_iv); i++)
|
rlm@1
|
185 _iv[i] = 0;
|
rlm@1
|
186 if (size == 0)
|
rlm@1
|
187 return S_OK;
|
rlm@1
|
188 UInt32 pos = 0;
|
rlm@1
|
189 Byte firstByte = data[pos++];
|
rlm@1
|
190
|
rlm@1
|
191 _key.NumCyclesPower = firstByte & 0x3F;
|
rlm@1
|
192 if ((firstByte & 0xC0) == 0)
|
rlm@1
|
193 return S_OK;
|
rlm@1
|
194 _key.SaltSize = (firstByte >> 7) & 1;
|
rlm@1
|
195 UInt32 ivSize = (firstByte >> 6) & 1;
|
rlm@1
|
196
|
rlm@1
|
197 if (pos >= size)
|
rlm@1
|
198 return E_INVALIDARG;
|
rlm@1
|
199 Byte secondByte = data[pos++];
|
rlm@1
|
200
|
rlm@1
|
201 _key.SaltSize += (secondByte >> 4);
|
rlm@1
|
202 ivSize += (secondByte & 0x0F);
|
rlm@1
|
203
|
rlm@1
|
204 if (pos + _key.SaltSize + ivSize > size)
|
rlm@1
|
205 return E_INVALIDARG;
|
rlm@1
|
206 for (i = 0; i < _key.SaltSize; i++)
|
rlm@1
|
207 _key.Salt[i] = data[pos++];
|
rlm@1
|
208 for (i = 0; i < ivSize; i++)
|
rlm@1
|
209 _iv[i] = data[pos++];
|
rlm@1
|
210 return S_OK;
|
rlm@1
|
211 }
|
rlm@1
|
212
|
rlm@1
|
213 STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)
|
rlm@1
|
214 {
|
rlm@1
|
215 _key.Password.SetCapacity((size_t)size);
|
rlm@1
|
216 memcpy(_key.Password, data, (size_t)size);
|
rlm@1
|
217 return S_OK;
|
rlm@1
|
218 }
|
rlm@1
|
219
|
rlm@1
|
220 STDMETHODIMP CBaseCoder::Init()
|
rlm@1
|
221 {
|
rlm@1
|
222 CalculateDigest();
|
rlm@1
|
223 if (_aesFilter == 0)
|
rlm@1
|
224 {
|
rlm@1
|
225 RINOK(CreateFilter());
|
rlm@1
|
226 }
|
rlm@1
|
227 CMyComPtr<ICryptoProperties> cp;
|
rlm@1
|
228 RINOK(_aesFilter.QueryInterface(IID_ICryptoProperties, &cp));
|
rlm@1
|
229 RINOK(cp->SetKey(_key.Key, sizeof(_key.Key)));
|
rlm@1
|
230 RINOK(cp->SetInitVector(_iv, sizeof(_iv)));
|
rlm@1
|
231 return S_OK;
|
rlm@1
|
232 }
|
rlm@1
|
233
|
rlm@1
|
234 STDMETHODIMP_(UInt32) CBaseCoder::Filter(Byte *data, UInt32 size)
|
rlm@1
|
235 {
|
rlm@1
|
236 return _aesFilter->Filter(data, size);
|
rlm@1
|
237 }
|
rlm@1
|
238
|
rlm@1
|
239 HRESULT CDecoder::CreateFilter()
|
rlm@1
|
240 {
|
rlm@1
|
241 _aesFilter = new CAesCbcDecoder;
|
rlm@1
|
242 return S_OK;
|
rlm@1
|
243 }
|
rlm@1
|
244
|
rlm@1
|
245 }}
|