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