xref: /aosp_15_r20/external/lzma/CPP/7zip/Crypto/7zAes.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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 Z7_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 Z7_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     const size_t shaAllocSize = sizeof(CSha256) + unrollSize + bufSize * 2;
62     CAlignedBuffer1 sha(shaAllocSize);
63     Byte *buf = sha + sizeof(CSha256);
64 
65     memcpy(buf, Salt, SaltSize);
66     memcpy(buf + SaltSize, Password, Password.Size());
67     memset(buf + bufSize - 8, 0, 8);
68 
69     Sha256_Init((CSha256 *)(void *)(Byte *)sha);
70 
71     {
72       {
73         Byte *dest = buf;
74         for (UInt32 i = 1; i < numUnroll; i++)
75         {
76           dest += bufSize;
77           memcpy(dest, buf, bufSize);
78         }
79       }
80 
81       const UInt32 numRounds = (UInt32)1 << NumCyclesPower;
82       UInt32 r = 0;
83       do
84       {
85         Byte *dest = buf + bufSize - 8;
86         UInt32 i = r;
87         r += numUnroll;
88         do
89         {
90           SetUi32(dest, i)  i++; dest += bufSize;
91           // SetUi32(dest, i)  i++; dest += bufSize;
92         }
93         while (i < r);
94         Sha256_Update((CSha256 *)(void *)(Byte *)sha, buf, unrollSize);
95       }
96       while (r < numRounds);
97     }
98     /*
99     UInt64 numRounds = (UInt64)1 << NumCyclesPower;
100 
101     do
102     {
103       Sha256_Update((CSha256 *)(Byte *)sha, buf, bufSize);
104       for (unsigned i = 0; i < 8; i++)
105         if (++(ctr[i]) != 0)
106           break;
107     }
108     while (--numRounds != 0);
109     */
110 
111     Sha256_Final((CSha256 *)(void *)(Byte *)sha, Key);
112     memset(sha, 0, shaAllocSize);
113   }
114 }
115 
GetKey(CKeyInfo & key)116 bool CKeyInfoCache::GetKey(CKeyInfo &key)
117 {
118   FOR_VECTOR (i, Keys)
119   {
120     const CKeyInfo &cached = Keys[i];
121     if (key.IsEqualTo(cached))
122     {
123       for (unsigned j = 0; j < kKeySize; j++)
124         key.Key[j] = cached.Key[j];
125       if (i != 0)
126         Keys.MoveToFront(i);
127       return true;
128     }
129   }
130   return false;
131 }
132 
FindAndAdd(const CKeyInfo & key)133 void CKeyInfoCache::FindAndAdd(const CKeyInfo &key)
134 {
135   FOR_VECTOR (i, Keys)
136   {
137     const CKeyInfo &cached = Keys[i];
138     if (key.IsEqualTo(cached))
139     {
140       if (i != 0)
141         Keys.MoveToFront(i);
142       return;
143     }
144   }
145   Add(key);
146 }
147 
Add(const CKeyInfo & key)148 void CKeyInfoCache::Add(const CKeyInfo &key)
149 {
150   if (Keys.Size() >= Size)
151     Keys.DeleteBack();
152   Keys.Insert(0, key);
153 }
154 
155 static CKeyInfoCache g_GlobalKeyCache(32);
156 
157 #ifndef Z7_ST
158   static NWindows::NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection;
159   #define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection);
160 #else
161   #define MT_LOCK
162 #endif
163 
CBase()164 CBase::CBase():
165   _cachedKeys(16),
166   _ivSize(0)
167 {
168   for (unsigned i = 0; i < sizeof(_iv); i++)
169     _iv[i] = 0;
170 }
171 
PrepareKey()172 void CBase::PrepareKey()
173 {
174   // BCJ2 threads use same password. So we use long lock.
175   MT_LOCK
176 
177   bool finded = false;
178   if (!_cachedKeys.GetKey(_key))
179   {
180     finded = g_GlobalKeyCache.GetKey(_key);
181     if (!finded)
182       _key.CalcKey();
183     _cachedKeys.Add(_key);
184   }
185   if (!finded)
186     g_GlobalKeyCache.FindAndAdd(_key);
187 }
188 
189 #ifndef Z7_EXTRACT_ONLY
190 
191 /*
192 Z7_COM7F_IMF(CEncoder::ResetSalt())
193 {
194   _key.SaltSize = 4;
195   g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);
196   return S_OK;
197 }
198 */
199 
Z7_COM7F_IMF(CEncoder::ResetInitVector ())200 Z7_COM7F_IMF(CEncoder::ResetInitVector())
201 {
202   for (unsigned i = 0; i < sizeof(_iv); i++)
203     _iv[i] = 0;
204   _ivSize = 16;
205   MY_RAND_GEN(_iv, _ivSize);
206   return S_OK;
207 }
208 
Z7_COM7F_IMF(CEncoder::WriteCoderProperties (ISequentialOutStream * outStream))209 Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream))
210 {
211   Byte props[2 + sizeof(_key.Salt) + sizeof(_iv)];
212   unsigned propsSize = 1;
213 
214   props[0] = (Byte)(_key.NumCyclesPower
215       | (_key.SaltSize == 0 ? 0 : (1 << 7))
216       | (_ivSize       == 0 ? 0 : (1 << 6)));
217 
218   if (_key.SaltSize != 0 || _ivSize != 0)
219   {
220     props[1] = (Byte)(
221         ((_key.SaltSize == 0 ? 0 : _key.SaltSize - 1) << 4)
222         | (_ivSize      == 0 ? 0 : _ivSize - 1));
223     memcpy(props + 2, _key.Salt, _key.SaltSize);
224     propsSize = 2 + _key.SaltSize;
225     memcpy(props + propsSize, _iv, _ivSize);
226     propsSize += _ivSize;
227   }
228 
229   return WriteStream(outStream, props, propsSize);
230 }
231 
CEncoder()232 CEncoder::CEncoder()
233 {
234   // _key.SaltSize = 4; g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);
235   // _key.NumCyclesPower = 0x3F;
236   _key.NumCyclesPower = 19;
237   _aesFilter = new CAesCbcEncoder(kKeySize);
238 }
239 
240 #endif
241 
CDecoder()242 CDecoder::CDecoder()
243 {
244   _aesFilter = new CAesCbcDecoder(kKeySize);
245 }
246 
Z7_COM7F_IMF(CDecoder::SetDecoderProperties2 (const Byte * data,UInt32 size))247 Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size))
248 {
249   _key.ClearProps();
250 
251   _ivSize = 0;
252   unsigned i;
253   for (i = 0; i < sizeof(_iv); i++)
254     _iv[i] = 0;
255 
256   if (size == 0)
257     return S_OK;
258 
259   const unsigned b0 = data[0];
260   _key.NumCyclesPower = b0 & 0x3F;
261   if ((b0 & 0xC0) == 0)
262     return size == 1 ? S_OK : E_INVALIDARG;
263   if (size <= 1)
264     return E_INVALIDARG;
265 
266   const unsigned b1 = data[1];
267   const unsigned saltSize = ((b0 >> 7) & 1) + (b1 >> 4);
268   const unsigned ivSize   = ((b0 >> 6) & 1) + (b1 & 0x0F);
269 
270   if (size != 2 + saltSize + ivSize)
271     return E_INVALIDARG;
272   _key.SaltSize = saltSize;
273   data += 2;
274   for (i = 0; i < saltSize; i++)
275     _key.Salt[i] = *data++;
276   for (i = 0; i < ivSize; i++)
277     _iv[i] = *data++;
278   return (_key.NumCyclesPower <= k_NumCyclesPower_Supported_MAX
279       || _key.NumCyclesPower == 0x3F) ? S_OK : E_NOTIMPL;
280 }
281 
282 
Z7_COM7F_IMF(CBaseCoder::CryptoSetPassword (const Byte * data,UInt32 size))283 Z7_COM7F_IMF(CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size))
284 {
285   COM_TRY_BEGIN
286 
287   _key.Password.Wipe();
288   _key.Password.CopyFrom(data, (size_t)size);
289   return S_OK;
290 
291   COM_TRY_END
292 }
293 
Z7_COM7F_IMF(CBaseCoder::Init ())294 Z7_COM7F_IMF(CBaseCoder::Init())
295 {
296   COM_TRY_BEGIN
297 
298   PrepareKey();
299   CMyComPtr<ICryptoProperties> cp;
300   RINOK(_aesFilter.QueryInterface(IID_ICryptoProperties, &cp))
301   if (!cp)
302     return E_FAIL;
303   RINOK(cp->SetKey(_key.Key, kKeySize))
304   RINOK(cp->SetInitVector(_iv, sizeof(_iv)))
305   return _aesFilter->Init();
306 
307   COM_TRY_END
308 }
309 
Z7_COM7F_IMF2(UInt32,CBaseCoder::Filter (Byte * data,UInt32 size))310 Z7_COM7F_IMF2(UInt32, CBaseCoder::Filter(Byte *data, UInt32 size))
311 {
312   return _aesFilter->Filter(data, size);
313 }
314 
315 }}
316