1 // Crypto/RarAes.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../C/CpuArch.h"
6 #include "../../../C/RotateDefs.h"
7
8 #include "RarAes.h"
9 #include "Sha1Cls.h"
10
11 namespace NCrypto {
12 namespace NRar3 {
13
CDecoder()14 CDecoder::CDecoder():
15 CAesCbcDecoder(kAesKeySize),
16 _thereIsSalt(false),
17 _needCalc(true)
18 // _rar350Mode(false)
19 {
20 for (unsigned i = 0; i < sizeof(_salt); i++)
21 _salt[i] = 0;
22 }
23
SetDecoderProperties2(const Byte * data,UInt32 size)24 HRESULT CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
25 {
26 bool prev = _thereIsSalt;
27 _thereIsSalt = false;
28 if (size == 0)
29 {
30 if (!_needCalc && prev)
31 _needCalc = true;
32 return S_OK;
33 }
34 if (size < 8)
35 return E_INVALIDARG;
36 _thereIsSalt = true;
37 bool same = false;
38 if (_thereIsSalt == prev)
39 {
40 same = true;
41 if (_thereIsSalt)
42 {
43 for (unsigned i = 0; i < sizeof(_salt); i++)
44 if (_salt[i] != data[i])
45 {
46 same = false;
47 break;
48 }
49 }
50 }
51 for (unsigned i = 0; i < sizeof(_salt); i++)
52 _salt[i] = data[i];
53 if (!_needCalc && !same)
54 _needCalc = true;
55 return S_OK;
56 }
57
58 static const unsigned kPasswordLen_Bytes_MAX = 127 * 2;
59
SetPassword(const Byte * data,unsigned size)60 void CDecoder::SetPassword(const Byte *data, unsigned size)
61 {
62 if (size > kPasswordLen_Bytes_MAX)
63 size = kPasswordLen_Bytes_MAX;
64 bool same = false;
65 if (size == _password.Size())
66 {
67 same = true;
68 for (UInt32 i = 0; i < size; i++)
69 if (data[i] != _password[i])
70 {
71 same = false;
72 break;
73 }
74 }
75 if (!_needCalc && !same)
76 _needCalc = true;
77 _password.Wipe();
78 _password.CopyFrom(data, (size_t)size);
79 }
80
Z7_COM7F_IMF(CDecoder::Init ())81 Z7_COM7F_IMF(CDecoder::Init())
82 {
83 CalcKey();
84 RINOK(SetKey(_key, kAesKeySize))
85 RINOK(SetInitVector(_iv, AES_BLOCK_SIZE))
86 return CAesCoder::Init();
87 }
88
89
90 // if (password_size_in_bytes + SaltSize > 64),
91 // the original rar code updates password_with_salt buffer
92 // with some generated data from SHA1 code.
93
94 // #define RAR_SHA1_REDUCE
95
96 #ifdef RAR_SHA1_REDUCE
97 #define kNumW 16
98 #define WW(i) W[(i)&15]
99 #else
100 #define kNumW 80
101 #define WW(i) W[i]
102 #endif
103
UpdatePswDataSha1(Byte * data)104 static void UpdatePswDataSha1(Byte *data)
105 {
106 UInt32 W[kNumW];
107 size_t i;
108
109 for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++)
110 W[i] = GetBe32(data + i * 4);
111
112 for (i = 16; i < 80; i++)
113 {
114 const UInt32 t = WW((i)-3) ^ WW((i)-8) ^ WW((i)-14) ^ WW((i)-16);
115 WW(i) = rotlFixed(t, 1);
116 }
117
118 for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++)
119 {
120 SetUi32(data + i * 4, W[kNumW - SHA1_NUM_BLOCK_WORDS + i])
121 }
122 }
123
124
CalcKey()125 void CDecoder::CalcKey()
126 {
127 if (!_needCalc)
128 return;
129
130 const unsigned kSaltSize = 8;
131
132 MY_ALIGN (16)
133 Byte buf[kPasswordLen_Bytes_MAX + kSaltSize];
134
135 if (_password.Size() != 0)
136 memcpy(buf, _password, _password.Size());
137
138 size_t rawSize = _password.Size();
139
140 if (_thereIsSalt)
141 {
142 memcpy(buf + rawSize, _salt, kSaltSize);
143 rawSize += kSaltSize;
144 }
145
146 MY_ALIGN (16)
147 NSha1::CContext sha;
148 sha.Init();
149
150 MY_ALIGN (16)
151 Byte digest[NSha1::kDigestSize];
152 // rar reverts hash for sha.
153 const UInt32 kNumRounds = (UInt32)1 << 18;
154 UInt32 pos = 0;
155 UInt32 i;
156 for (i = 0; i < kNumRounds; i++)
157 {
158 sha.Update(buf, rawSize);
159 // if (_rar350Mode)
160 {
161 const UInt32 kBlockSize = 64;
162 const UInt32 endPos = (pos + (UInt32)rawSize) & ~(kBlockSize - 1);
163 if (endPos > pos + kBlockSize)
164 {
165 UInt32 curPos = pos & ~(kBlockSize - 1);
166 curPos += kBlockSize;
167 do
168 {
169 UpdatePswDataSha1(buf + (curPos - pos));
170 curPos += kBlockSize;
171 }
172 while (curPos != endPos);
173 }
174 }
175 pos += (UInt32)rawSize;
176 #if 1
177 UInt32 pswNum;
178 SetUi32a(&pswNum, i)
179 sha.Update((const Byte *)&pswNum, 3);
180 #else
181 Byte pswNum[3] = { (Byte)i, (Byte)(i >> 8), (Byte)(i >> 16) };
182 sha.Update(pswNum, 3);
183 #endif
184 pos += 3;
185 if (i % (kNumRounds / 16) == 0)
186 {
187 MY_ALIGN (16)
188 NSha1::CContext shaTemp = sha;
189 shaTemp.Final(digest);
190 _iv[i / (kNumRounds / 16)] = (Byte)digest[4 * 4 + 3];
191 }
192 }
193
194 sha.Final(digest);
195 for (i = 0; i < 4; i++)
196 for (unsigned j = 0; j < 4; j++)
197 _key[i * 4 + j] = (digest[i * 4 + 3 - j]);
198
199 _needCalc = false;
200 }
201
202 }}
203