xref: /aosp_15_r20/external/lzma/CPP/7zip/Crypto/RarAes.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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