• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 7zAes.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../C/CpuArch.h"
6 #include "../../../C/Sha256.h"
7 
8 #include "../../Common/ComTry.h"
9 #include "../../Common/MyBuffer2.h"
10 
11 #ifndef _7ZIP_ST
12 #include "../../Windows/Synchronization.h"
13 #endif
14 
15 #include "../Common/StreamUtils.h"
16 
17 #include "7zAes.h"
18 #include "MyAes.h"
19 
20 #ifndef EXTRACT_ONLY
21 #include "RandGen.h"
22 #endif
23 
24 namespace NCrypto {
25 namespace N7z {
26 
27 static const unsigned k_NumCyclesPower_Supported_MAX = 24;
28 
IsEqualTo(const CKeyInfo & a) const29 bool CKeyInfo::IsEqualTo(const CKeyInfo &a) const
30 {
31   if (SaltSize != a.SaltSize || NumCyclesPower != a.NumCyclesPower)
32     return false;
33   for (unsigned i = 0; i < SaltSize; i++)
34     if (Salt[i] != a.Salt[i])
35       return false;
36   return (Password == a.Password);
37 }
38 
CalcKey()39 void CKeyInfo::CalcKey()
40 {
41   if (NumCyclesPower == 0x3F)
42   {
43     unsigned pos;
44     for (pos = 0; pos < SaltSize; pos++)
45       Key[pos] = Salt[pos];
46     for (unsigned i = 0; i < Password.Size() && pos < kKeySize; i++)
47       Key[pos++] = Password[i];
48     for (; pos < kKeySize; pos++)
49       Key[pos] = 0;
50   }
51   else
52   {
53     const unsigned kUnrPow = 6;
54     const UInt32 numUnroll = (UInt32)1 << (NumCyclesPower <= kUnrPow ? (unsigned)NumCyclesPower : kUnrPow);
55 
56     const size_t bufSize = 8 + SaltSize + Password.Size();
57     const size_t unrollSize = bufSize * numUnroll;
58 
59     // MY_ALIGN (16)
60     // CSha256 sha;
61     CAlignedBuffer sha(sizeof(CSha256) + unrollSize + bufSize * 2);
62     Byte *buf = sha + sizeof(CSha256);
63 
64     memcpy(buf, Salt, SaltSize);
65     memcpy(buf + SaltSize, Password, Password.Size());
66     memset(buf + bufSize - 8, 0, 8);
67 
68     Sha256_Init((CSha256 *)(void *)(Byte *)sha);
69 
70     {
71       {
72         Byte *dest = buf;
73         for (UInt32 i = 1; i < numUnroll; i++)
74         {
75           dest += bufSize;
76           memcpy(dest, buf, bufSize);
77         }
78       }
79 
80       const UInt32 numRounds = (UInt32)1 << NumCyclesPower;
81       UInt32 r = 0;
82       do
83       {
84         Byte *dest = buf + bufSize - 8;
85         UInt32 i = r;
86         r += numUnroll;
87         do
88         {
89           SetUi32(dest, i); i++; dest += bufSize;
90           // SetUi32(dest, i); i++; dest += bufSize;
91         }
92         while (i < r);
93         Sha256_Update((CSha256 *)(void *)(Byte *)sha, buf, unrollSize);
94       }
95       while (r < numRounds);
96     }
97     /*
98     UInt64 numRounds = (UInt64)1 << NumCyclesPower;
99 
100     do
101     {
102       Sha256_Update((CSha256 *)(Byte *)sha, buf, bufSize);
103       for (unsigned i = 0; i < 8; i++)
104         if (++(ctr[i]) != 0)
105           break;
106     }
107     while (--numRounds != 0);
108     */
109 
110     Sha256_Final((CSha256 *)(void *)(Byte *)sha, Key);
111     memset(sha, 0, sha.Size());
112   }
113 }
114 
GetKey(CKeyInfo & key)115 bool CKeyInfoCache::GetKey(CKeyInfo &key)
116 {
117   FOR_VECTOR (i, Keys)
118   {
119     const CKeyInfo &cached = Keys[i];
120     if (key.IsEqualTo(cached))
121     {
122       for (unsigned j = 0; j < kKeySize; j++)
123         key.Key[j] = cached.Key[j];
124       if (i != 0)
125         Keys.MoveToFront(i);
126       return true;
127     }
128   }
129   return false;
130 }
131 
FindAndAdd(const CKeyInfo & key)132 void CKeyInfoCache::FindAndAdd(const CKeyInfo &key)
133 {
134   FOR_VECTOR (i, Keys)
135   {
136     const CKeyInfo &cached = Keys[i];
137     if (key.IsEqualTo(cached))
138     {
139       if (i != 0)
140         Keys.MoveToFront(i);
141       return;
142     }
143   }
144   Add(key);
145 }
146 
Add(const CKeyInfo & key)147 void CKeyInfoCache::Add(const CKeyInfo &key)
148 {
149   if (Keys.Size() >= Size)
150     Keys.DeleteBack();
151   Keys.Insert(0, key);
152 }
153 
154 static CKeyInfoCache g_GlobalKeyCache(32);
155 
156 #ifndef _7ZIP_ST
157   static NWindows::NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection;
158   #define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection);
159 #else
160   #define MT_LOCK
161 #endif
162 
CBase()163 CBase::CBase():
164   _cachedKeys(16),
165   _ivSize(0)
166 {
167   for (unsigned i = 0; i < sizeof(_iv); i++)
168     _iv[i] = 0;
169 }
170 
PrepareKey()171 void CBase::PrepareKey()
172 {
173   // BCJ2 threads use same password. So we use long lock.
174   MT_LOCK
175 
176   bool finded = false;
177   if (!_cachedKeys.GetKey(_key))
178   {
179     finded = g_GlobalKeyCache.GetKey(_key);
180     if (!finded)
181       _key.CalcKey();
182     _cachedKeys.Add(_key);
183   }
184   if (!finded)
185     g_GlobalKeyCache.FindAndAdd(_key);
186 }
187 
188 #ifndef EXTRACT_ONLY
189 
190 /*
191 STDMETHODIMP CEncoder::ResetSalt()
192 {
193   _key.SaltSize = 4;
194   g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);
195   return S_OK;
196 }
197 */
198 
ResetInitVector()199 STDMETHODIMP CEncoder::ResetInitVector()
200 {
201   for (unsigned i = 0; i < sizeof(_iv); i++)
202     _iv[i] = 0;
203   _ivSize = 16;
204   MY_RAND_GEN(_iv, _ivSize);
205   return S_OK;
206 }
207 
WriteCoderProperties(ISequentialOutStream * outStream)208 STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
209 {
210   Byte props[2 + sizeof(_key.Salt) + sizeof(_iv)];
211   unsigned propsSize = 1;
212 
213   props[0] = (Byte)(_key.NumCyclesPower
214       | (_key.SaltSize == 0 ? 0 : (1 << 7))
215       | (_ivSize       == 0 ? 0 : (1 << 6)));
216 
217   if (_key.SaltSize != 0 || _ivSize != 0)
218   {
219     props[1] = (Byte)(
220         ((_key.SaltSize == 0 ? 0 : _key.SaltSize - 1) << 4)
221         | (_ivSize      == 0 ? 0 : _ivSize - 1));
222     memcpy(props + 2, _key.Salt, _key.SaltSize);
223     propsSize = 2 + _key.SaltSize;
224     memcpy(props + propsSize, _iv, _ivSize);
225     propsSize += _ivSize;
226   }
227 
228   return WriteStream(outStream, props, propsSize);
229 }
230 
CEncoder()231 CEncoder::CEncoder()
232 {
233   // _key.SaltSize = 4; g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);
234   // _key.NumCyclesPower = 0x3F;
235   _key.NumCyclesPower = 19;
236   _aesFilter = new CAesCbcEncoder(kKeySize);
237 }
238 
239 #endif
240 
CDecoder()241 CDecoder::CDecoder()
242 {
243   _aesFilter = new CAesCbcDecoder(kKeySize);
244 }
245 
SetDecoderProperties2(const Byte * data,UInt32 size)246 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
247 {
248   _key.ClearProps();
249 
250   _ivSize = 0;
251   unsigned i;
252   for (i = 0; i < sizeof(_iv); i++)
253     _iv[i] = 0;
254 
255   if (size == 0)
256     return S_OK;
257 
258   Byte b0 = data[0];
259 
260   _key.NumCyclesPower = b0 & 0x3F;
261   if ((b0 & 0xC0) == 0)
262     return size == 1 ? S_OK : E_INVALIDARG;
263 
264   if (size <= 1)
265     return E_INVALIDARG;
266 
267   Byte b1 = data[1];
268 
269   unsigned saltSize = ((b0 >> 7) & 1) + (b1 >> 4);
270   unsigned ivSize   = ((b0 >> 6) & 1) + (b1 & 0x0F);
271 
272   if (size != 2 + saltSize + ivSize)
273     return E_INVALIDARG;
274   _key.SaltSize = saltSize;
275   data += 2;
276   for (i = 0; i < saltSize; i++)
277     _key.Salt[i] = *data++;
278   for (i = 0; i < ivSize; i++)
279     _iv[i] = *data++;
280   return (_key.NumCyclesPower <= k_NumCyclesPower_Supported_MAX
281       || _key.NumCyclesPower == 0x3F) ? S_OK : E_NOTIMPL;
282 }
283 
284 
CryptoSetPassword(const Byte * data,UInt32 size)285 STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)
286 {
287   COM_TRY_BEGIN
288 
289   _key.Password.Wipe();
290   _key.Password.CopyFrom(data, (size_t)size);
291   return S_OK;
292 
293   COM_TRY_END
294 }
295 
Init()296 STDMETHODIMP CBaseCoder::Init()
297 {
298   COM_TRY_BEGIN
299 
300   PrepareKey();
301   CMyComPtr<ICryptoProperties> cp;
302   RINOK(_aesFilter.QueryInterface(IID_ICryptoProperties, &cp));
303   if (!cp)
304     return E_FAIL;
305   RINOK(cp->SetKey(_key.Key, kKeySize));
306   RINOK(cp->SetInitVector(_iv, sizeof(_iv)));
307   return _aesFilter->Init();
308 
309   COM_TRY_END
310 }
311 
STDMETHODIMP_(UInt32)312 STDMETHODIMP_(UInt32) CBaseCoder::Filter(Byte *data, UInt32 size)
313 {
314   return _aesFilter->Filter(data, size);
315 }
316 
317 }}
318