xref: /aosp_15_r20/external/lzma/CPP/7zip/Crypto/Rar5Aes.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // Crypto/Rar5Aes.cpp
2*f6dc9357SAndroid Build Coastguard Worker 
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker 
5*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/CpuArch.h"
6*f6dc9357SAndroid Build Coastguard Worker 
7*f6dc9357SAndroid Build Coastguard Worker #ifndef Z7_ST
8*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/Synchronization.h"
9*f6dc9357SAndroid Build Coastguard Worker #endif
10*f6dc9357SAndroid Build Coastguard Worker 
11*f6dc9357SAndroid Build Coastguard Worker #include "HmacSha256.h"
12*f6dc9357SAndroid Build Coastguard Worker #include "Rar5Aes.h"
13*f6dc9357SAndroid Build Coastguard Worker 
14*f6dc9357SAndroid Build Coastguard Worker #define MY_ALIGN_FOR_SHA256  MY_ALIGN(16)
15*f6dc9357SAndroid Build Coastguard Worker 
16*f6dc9357SAndroid Build Coastguard Worker namespace NCrypto {
17*f6dc9357SAndroid Build Coastguard Worker namespace NRar5 {
18*f6dc9357SAndroid Build Coastguard Worker 
19*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumIterationsLog_Max = 24;
20*f6dc9357SAndroid Build Coastguard Worker static const unsigned kPswCheckCsumSize32 = 1;
21*f6dc9357SAndroid Build Coastguard Worker static const unsigned kCheckSize32 = kPswCheckSize32 + kPswCheckCsumSize32;
22*f6dc9357SAndroid Build Coastguard Worker 
CKey()23*f6dc9357SAndroid Build Coastguard Worker CKey::CKey():
24*f6dc9357SAndroid Build Coastguard Worker     _needCalc(true),
25*f6dc9357SAndroid Build Coastguard Worker     _numIterationsLog(0)
26*f6dc9357SAndroid Build Coastguard Worker {
27*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < sizeof(_salt); i++)
28*f6dc9357SAndroid Build Coastguard Worker     _salt[i] = 0;
29*f6dc9357SAndroid Build Coastguard Worker }
30*f6dc9357SAndroid Build Coastguard Worker 
~CKey()31*f6dc9357SAndroid Build Coastguard Worker CKey::~CKey()
32*f6dc9357SAndroid Build Coastguard Worker {
33*f6dc9357SAndroid Build Coastguard Worker   Wipe();
34*f6dc9357SAndroid Build Coastguard Worker }
35*f6dc9357SAndroid Build Coastguard Worker 
Wipe()36*f6dc9357SAndroid Build Coastguard Worker void CKey::Wipe()
37*f6dc9357SAndroid Build Coastguard Worker {
38*f6dc9357SAndroid Build Coastguard Worker   _password.Wipe();
39*f6dc9357SAndroid Build Coastguard Worker   Z7_memset_0_ARRAY(_salt);
40*f6dc9357SAndroid Build Coastguard Worker   // Z7_memset_0_ARRAY(_key32);
41*f6dc9357SAndroid Build Coastguard Worker   // Z7_memset_0_ARRAY(_check_Calced32);
42*f6dc9357SAndroid Build Coastguard Worker   // Z7_memset_0_ARRAY(_hashKey32);
43*f6dc9357SAndroid Build Coastguard Worker   CKeyBase::Wipe();
44*f6dc9357SAndroid Build Coastguard Worker }
45*f6dc9357SAndroid Build Coastguard Worker 
CDecoder()46*f6dc9357SAndroid Build Coastguard Worker CDecoder::CDecoder(): CAesCbcDecoder(kAesKeySize) {}
47*f6dc9357SAndroid Build Coastguard Worker 
ReadVarInt(const Byte * p,unsigned maxSize,UInt64 * val)48*f6dc9357SAndroid Build Coastguard Worker static unsigned ReadVarInt(const Byte *p, unsigned maxSize, UInt64 *val)
49*f6dc9357SAndroid Build Coastguard Worker {
50*f6dc9357SAndroid Build Coastguard Worker   *val = 0;
51*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < maxSize && i < 10;)
52*f6dc9357SAndroid Build Coastguard Worker   {
53*f6dc9357SAndroid Build Coastguard Worker     const Byte b = p[i];
54*f6dc9357SAndroid Build Coastguard Worker     *val |= (UInt64)(b & 0x7F) << (7 * i);
55*f6dc9357SAndroid Build Coastguard Worker     i++;
56*f6dc9357SAndroid Build Coastguard Worker     if ((b & 0x80) == 0)
57*f6dc9357SAndroid Build Coastguard Worker       return i;
58*f6dc9357SAndroid Build Coastguard Worker   }
59*f6dc9357SAndroid Build Coastguard Worker   return 0;
60*f6dc9357SAndroid Build Coastguard Worker }
61*f6dc9357SAndroid Build Coastguard Worker 
SetDecoderProps(const Byte * p,unsigned size,bool includeIV,bool isService)62*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::SetDecoderProps(const Byte *p, unsigned size, bool includeIV, bool isService)
63*f6dc9357SAndroid Build Coastguard Worker {
64*f6dc9357SAndroid Build Coastguard Worker   UInt64 Version;
65*f6dc9357SAndroid Build Coastguard Worker 
66*f6dc9357SAndroid Build Coastguard Worker   unsigned num = ReadVarInt(p, size, &Version);
67*f6dc9357SAndroid Build Coastguard Worker   if (num == 0)
68*f6dc9357SAndroid Build Coastguard Worker     return E_NOTIMPL;
69*f6dc9357SAndroid Build Coastguard Worker   p += num;
70*f6dc9357SAndroid Build Coastguard Worker   size -= num;
71*f6dc9357SAndroid Build Coastguard Worker 
72*f6dc9357SAndroid Build Coastguard Worker   if (Version != 0)
73*f6dc9357SAndroid Build Coastguard Worker     return E_NOTIMPL;
74*f6dc9357SAndroid Build Coastguard Worker 
75*f6dc9357SAndroid Build Coastguard Worker   num = ReadVarInt(p, size, &Flags);
76*f6dc9357SAndroid Build Coastguard Worker   if (num == 0)
77*f6dc9357SAndroid Build Coastguard Worker     return E_NOTIMPL;
78*f6dc9357SAndroid Build Coastguard Worker   p += num;
79*f6dc9357SAndroid Build Coastguard Worker   size -= num;
80*f6dc9357SAndroid Build Coastguard Worker 
81*f6dc9357SAndroid Build Coastguard Worker   bool isCheck = IsThereCheck();
82*f6dc9357SAndroid Build Coastguard Worker   if (size != 1 + kSaltSize + (includeIV ? AES_BLOCK_SIZE : 0) + (unsigned)(isCheck ? kCheckSize32 * 4 : 0))
83*f6dc9357SAndroid Build Coastguard Worker     return E_NOTIMPL;
84*f6dc9357SAndroid Build Coastguard Worker 
85*f6dc9357SAndroid Build Coastguard Worker   if (_numIterationsLog != p[0])
86*f6dc9357SAndroid Build Coastguard Worker   {
87*f6dc9357SAndroid Build Coastguard Worker     _numIterationsLog = p[0];
88*f6dc9357SAndroid Build Coastguard Worker     _needCalc = true;
89*f6dc9357SAndroid Build Coastguard Worker   }
90*f6dc9357SAndroid Build Coastguard Worker 
91*f6dc9357SAndroid Build Coastguard Worker   p++;
92*f6dc9357SAndroid Build Coastguard Worker 
93*f6dc9357SAndroid Build Coastguard Worker   if (memcmp(_salt, p, kSaltSize) != 0)
94*f6dc9357SAndroid Build Coastguard Worker   {
95*f6dc9357SAndroid Build Coastguard Worker     memcpy(_salt, p, kSaltSize);
96*f6dc9357SAndroid Build Coastguard Worker     _needCalc = true;
97*f6dc9357SAndroid Build Coastguard Worker   }
98*f6dc9357SAndroid Build Coastguard Worker 
99*f6dc9357SAndroid Build Coastguard Worker   p += kSaltSize;
100*f6dc9357SAndroid Build Coastguard Worker 
101*f6dc9357SAndroid Build Coastguard Worker   if (includeIV)
102*f6dc9357SAndroid Build Coastguard Worker   {
103*f6dc9357SAndroid Build Coastguard Worker     memcpy(_iv, p, AES_BLOCK_SIZE);
104*f6dc9357SAndroid Build Coastguard Worker     p += AES_BLOCK_SIZE;
105*f6dc9357SAndroid Build Coastguard Worker   }
106*f6dc9357SAndroid Build Coastguard Worker 
107*f6dc9357SAndroid Build Coastguard Worker   _canCheck = true;
108*f6dc9357SAndroid Build Coastguard Worker 
109*f6dc9357SAndroid Build Coastguard Worker   if (isCheck)
110*f6dc9357SAndroid Build Coastguard Worker   {
111*f6dc9357SAndroid Build Coastguard Worker     memcpy(_check32, p, sizeof(_check32));
112*f6dc9357SAndroid Build Coastguard Worker     MY_ALIGN_FOR_SHA256
113*f6dc9357SAndroid Build Coastguard Worker     CSha256 sha;
114*f6dc9357SAndroid Build Coastguard Worker     MY_ALIGN_FOR_SHA256
115*f6dc9357SAndroid Build Coastguard Worker     Byte digest[SHA256_DIGEST_SIZE];
116*f6dc9357SAndroid Build Coastguard Worker     Sha256_Init(&sha);
117*f6dc9357SAndroid Build Coastguard Worker     Sha256_Update(&sha, (const Byte *)_check32, sizeof(_check32));
118*f6dc9357SAndroid Build Coastguard Worker     Sha256_Final(&sha, digest);
119*f6dc9357SAndroid Build Coastguard Worker     _canCheck = (memcmp(digest, p + sizeof(_check32), kPswCheckCsumSize32 * 4) == 0);
120*f6dc9357SAndroid Build Coastguard Worker     if (_canCheck && isService)
121*f6dc9357SAndroid Build Coastguard Worker     {
122*f6dc9357SAndroid Build Coastguard Worker       // There was bug in RAR 5.21- : PswCheck field in service records ("QO") contained zeros.
123*f6dc9357SAndroid Build Coastguard Worker       // so we disable password checking for such bad records.
124*f6dc9357SAndroid Build Coastguard Worker       _canCheck = false;
125*f6dc9357SAndroid Build Coastguard Worker       for (unsigned i = 0; i < kPswCheckSize32 * 4; i++)
126*f6dc9357SAndroid Build Coastguard Worker         if (p[i] != 0)
127*f6dc9357SAndroid Build Coastguard Worker         {
128*f6dc9357SAndroid Build Coastguard Worker           _canCheck = true;
129*f6dc9357SAndroid Build Coastguard Worker           break;
130*f6dc9357SAndroid Build Coastguard Worker         }
131*f6dc9357SAndroid Build Coastguard Worker     }
132*f6dc9357SAndroid Build Coastguard Worker   }
133*f6dc9357SAndroid Build Coastguard Worker 
134*f6dc9357SAndroid Build Coastguard Worker   return (_numIterationsLog <= kNumIterationsLog_Max ? S_OK : E_NOTIMPL);
135*f6dc9357SAndroid Build Coastguard Worker }
136*f6dc9357SAndroid Build Coastguard Worker 
137*f6dc9357SAndroid Build Coastguard Worker 
SetPassword(const Byte * data,size_t size)138*f6dc9357SAndroid Build Coastguard Worker void CDecoder::SetPassword(const Byte *data, size_t size)
139*f6dc9357SAndroid Build Coastguard Worker {
140*f6dc9357SAndroid Build Coastguard Worker   if (size != _password.Size() || memcmp(data, _password, size) != 0)
141*f6dc9357SAndroid Build Coastguard Worker   {
142*f6dc9357SAndroid Build Coastguard Worker     _needCalc = true;
143*f6dc9357SAndroid Build Coastguard Worker     _password.Wipe();
144*f6dc9357SAndroid Build Coastguard Worker     _password.CopyFrom(data, size);
145*f6dc9357SAndroid Build Coastguard Worker   }
146*f6dc9357SAndroid Build Coastguard Worker }
147*f6dc9357SAndroid Build Coastguard Worker 
148*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CDecoder::Init ())149*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::Init())
150*f6dc9357SAndroid Build Coastguard Worker {
151*f6dc9357SAndroid Build Coastguard Worker   CalcKey_and_CheckPassword();
152*f6dc9357SAndroid Build Coastguard Worker   RINOK(SetKey((const Byte *)_key32, kAesKeySize))
153*f6dc9357SAndroid Build Coastguard Worker   RINOK(SetInitVector(_iv, AES_BLOCK_SIZE))
154*f6dc9357SAndroid Build Coastguard Worker   return CAesCoder::Init();
155*f6dc9357SAndroid Build Coastguard Worker }
156*f6dc9357SAndroid Build Coastguard Worker 
157*f6dc9357SAndroid Build Coastguard Worker 
Hmac_Convert_Crc32(UInt32 crc) const158*f6dc9357SAndroid Build Coastguard Worker UInt32 CDecoder::Hmac_Convert_Crc32(UInt32 crc) const
159*f6dc9357SAndroid Build Coastguard Worker {
160*f6dc9357SAndroid Build Coastguard Worker   MY_ALIGN_FOR_SHA256
161*f6dc9357SAndroid Build Coastguard Worker   NSha256::CHmac ctx;
162*f6dc9357SAndroid Build Coastguard Worker   ctx.SetKey((const Byte *)_hashKey32, NSha256::kDigestSize);
163*f6dc9357SAndroid Build Coastguard Worker   UInt32 v;
164*f6dc9357SAndroid Build Coastguard Worker   SetUi32a(&v, crc)
165*f6dc9357SAndroid Build Coastguard Worker   ctx.Update((const Byte *)&v, 4);
166*f6dc9357SAndroid Build Coastguard Worker   MY_ALIGN_FOR_SHA256
167*f6dc9357SAndroid Build Coastguard Worker   UInt32 h[SHA256_NUM_DIGEST_WORDS];
168*f6dc9357SAndroid Build Coastguard Worker   ctx.Final((Byte *)h);
169*f6dc9357SAndroid Build Coastguard Worker   crc = 0;
170*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < SHA256_NUM_DIGEST_WORDS; i++)
171*f6dc9357SAndroid Build Coastguard Worker     crc ^= (UInt32)GetUi32a(h + i);
172*f6dc9357SAndroid Build Coastguard Worker   return crc;
173*f6dc9357SAndroid Build Coastguard Worker }
174*f6dc9357SAndroid Build Coastguard Worker 
175*f6dc9357SAndroid Build Coastguard Worker 
Hmac_Convert_32Bytes(Byte * data) const176*f6dc9357SAndroid Build Coastguard Worker void CDecoder::Hmac_Convert_32Bytes(Byte *data) const
177*f6dc9357SAndroid Build Coastguard Worker {
178*f6dc9357SAndroid Build Coastguard Worker   MY_ALIGN_FOR_SHA256
179*f6dc9357SAndroid Build Coastguard Worker   NSha256::CHmac ctx;
180*f6dc9357SAndroid Build Coastguard Worker   ctx.SetKey((const Byte *)_hashKey32, NSha256::kDigestSize);
181*f6dc9357SAndroid Build Coastguard Worker   ctx.Update(data, NSha256::kDigestSize);
182*f6dc9357SAndroid Build Coastguard Worker   ctx.Final(data);
183*f6dc9357SAndroid Build Coastguard Worker }
184*f6dc9357SAndroid Build Coastguard Worker 
185*f6dc9357SAndroid Build Coastguard Worker 
186*f6dc9357SAndroid Build Coastguard Worker static CKey g_Key;
187*f6dc9357SAndroid Build Coastguard Worker 
188*f6dc9357SAndroid Build Coastguard Worker #ifndef Z7_ST
189*f6dc9357SAndroid Build Coastguard Worker   static NWindows::NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection;
190*f6dc9357SAndroid Build Coastguard Worker   #define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection);
191*f6dc9357SAndroid Build Coastguard Worker #else
192*f6dc9357SAndroid Build Coastguard Worker   #define MT_LOCK
193*f6dc9357SAndroid Build Coastguard Worker #endif
194*f6dc9357SAndroid Build Coastguard Worker 
CalcKey_and_CheckPassword()195*f6dc9357SAndroid Build Coastguard Worker bool CDecoder::CalcKey_and_CheckPassword()
196*f6dc9357SAndroid Build Coastguard Worker {
197*f6dc9357SAndroid Build Coastguard Worker   if (_needCalc)
198*f6dc9357SAndroid Build Coastguard Worker   {
199*f6dc9357SAndroid Build Coastguard Worker     {
200*f6dc9357SAndroid Build Coastguard Worker       MT_LOCK
201*f6dc9357SAndroid Build Coastguard Worker       if (!g_Key._needCalc && IsKeyEqualTo(g_Key))
202*f6dc9357SAndroid Build Coastguard Worker       {
203*f6dc9357SAndroid Build Coastguard Worker         CopyCalcedKeysFrom(g_Key);
204*f6dc9357SAndroid Build Coastguard Worker         _needCalc = false;
205*f6dc9357SAndroid Build Coastguard Worker       }
206*f6dc9357SAndroid Build Coastguard Worker     }
207*f6dc9357SAndroid Build Coastguard Worker 
208*f6dc9357SAndroid Build Coastguard Worker     if (_needCalc)
209*f6dc9357SAndroid Build Coastguard Worker     {
210*f6dc9357SAndroid Build Coastguard Worker       MY_ALIGN_FOR_SHA256
211*f6dc9357SAndroid Build Coastguard Worker       UInt32 pswCheck[SHA256_NUM_DIGEST_WORDS];
212*f6dc9357SAndroid Build Coastguard Worker       {
213*f6dc9357SAndroid Build Coastguard Worker         // Pbkdf HMAC-SHA-256
214*f6dc9357SAndroid Build Coastguard Worker         MY_ALIGN_FOR_SHA256
215*f6dc9357SAndroid Build Coastguard Worker         NSha256::CHmac baseCtx;
216*f6dc9357SAndroid Build Coastguard Worker         baseCtx.SetKey(_password, _password.Size());
217*f6dc9357SAndroid Build Coastguard Worker         MY_ALIGN_FOR_SHA256
218*f6dc9357SAndroid Build Coastguard Worker         NSha256::CHmac ctx;
219*f6dc9357SAndroid Build Coastguard Worker         ctx = baseCtx;
220*f6dc9357SAndroid Build Coastguard Worker         ctx.Update(_salt, sizeof(_salt));
221*f6dc9357SAndroid Build Coastguard Worker 
222*f6dc9357SAndroid Build Coastguard Worker         MY_ALIGN_FOR_SHA256
223*f6dc9357SAndroid Build Coastguard Worker         UInt32 u[SHA256_NUM_DIGEST_WORDS];
224*f6dc9357SAndroid Build Coastguard Worker         MY_ALIGN_FOR_SHA256
225*f6dc9357SAndroid Build Coastguard Worker         UInt32 key[SHA256_NUM_DIGEST_WORDS];
226*f6dc9357SAndroid Build Coastguard Worker 
227*f6dc9357SAndroid Build Coastguard Worker         // u[0] = 0;
228*f6dc9357SAndroid Build Coastguard Worker         // u[1] = 0;
229*f6dc9357SAndroid Build Coastguard Worker         // u[2] = 0;
230*f6dc9357SAndroid Build Coastguard Worker         // u[3] = 1;
231*f6dc9357SAndroid Build Coastguard Worker         SetUi32a(u, 0x1000000)
232*f6dc9357SAndroid Build Coastguard Worker 
233*f6dc9357SAndroid Build Coastguard Worker         ctx.Update((const Byte *)(const void *)u, 4);
234*f6dc9357SAndroid Build Coastguard Worker         ctx.Final((Byte *)(void *)u);
235*f6dc9357SAndroid Build Coastguard Worker 
236*f6dc9357SAndroid Build Coastguard Worker         memcpy(key, u, NSha256::kDigestSize);
237*f6dc9357SAndroid Build Coastguard Worker 
238*f6dc9357SAndroid Build Coastguard Worker         UInt32 numIterations = ((UInt32)1 << _numIterationsLog) - 1;
239*f6dc9357SAndroid Build Coastguard Worker 
240*f6dc9357SAndroid Build Coastguard Worker         for (unsigned i = 0; i < 3; i++)
241*f6dc9357SAndroid Build Coastguard Worker         {
242*f6dc9357SAndroid Build Coastguard Worker           for (; numIterations != 0; numIterations--)
243*f6dc9357SAndroid Build Coastguard Worker           {
244*f6dc9357SAndroid Build Coastguard Worker             ctx = baseCtx;
245*f6dc9357SAndroid Build Coastguard Worker             ctx.Update((const Byte *)(const void *)u, NSha256::kDigestSize);
246*f6dc9357SAndroid Build Coastguard Worker             ctx.Final((Byte *)(void *)u);
247*f6dc9357SAndroid Build Coastguard Worker             for (unsigned s = 0; s < Z7_ARRAY_SIZE(u); s++)
248*f6dc9357SAndroid Build Coastguard Worker               key[s] ^= u[s];
249*f6dc9357SAndroid Build Coastguard Worker           }
250*f6dc9357SAndroid Build Coastguard Worker 
251*f6dc9357SAndroid Build Coastguard Worker           // RAR uses additional iterations for additional keys
252*f6dc9357SAndroid Build Coastguard Worker           memcpy(i == 0 ? _key32 : i == 1 ? _hashKey32 : pswCheck,
253*f6dc9357SAndroid Build Coastguard Worker               key, NSha256::kDigestSize);
254*f6dc9357SAndroid Build Coastguard Worker           numIterations = 16;
255*f6dc9357SAndroid Build Coastguard Worker         }
256*f6dc9357SAndroid Build Coastguard Worker       }
257*f6dc9357SAndroid Build Coastguard Worker      _check_Calced32[0] = pswCheck[0] ^ pswCheck[2] ^ pswCheck[4] ^ pswCheck[6];
258*f6dc9357SAndroid Build Coastguard Worker      _check_Calced32[1] = pswCheck[1] ^ pswCheck[3] ^ pswCheck[5] ^ pswCheck[7];
259*f6dc9357SAndroid Build Coastguard Worker       _needCalc = false;
260*f6dc9357SAndroid Build Coastguard Worker       {
261*f6dc9357SAndroid Build Coastguard Worker         MT_LOCK
262*f6dc9357SAndroid Build Coastguard Worker         g_Key = *this;
263*f6dc9357SAndroid Build Coastguard Worker       }
264*f6dc9357SAndroid Build Coastguard Worker     }
265*f6dc9357SAndroid Build Coastguard Worker   }
266*f6dc9357SAndroid Build Coastguard Worker 
267*f6dc9357SAndroid Build Coastguard Worker   if (IsThereCheck() && _canCheck)
268*f6dc9357SAndroid Build Coastguard Worker     return memcmp(_check_Calced32, _check32, sizeof(_check32)) == 0;
269*f6dc9357SAndroid Build Coastguard Worker   return true;
270*f6dc9357SAndroid Build Coastguard Worker }
271*f6dc9357SAndroid Build Coastguard Worker 
272*f6dc9357SAndroid Build Coastguard Worker }}
273