xref: /aosp_15_r20/external/lzma/CPP/7zip/Crypto/WzAes.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // Crypto/WzAes.cpp
2 /*
3 This code implements Brian Gladman's scheme
4 specified in "A Password Based File Encryption Utility".
5 
6 Note: you must include MyAes.cpp to project to initialize AES tables
7 */
8 
9 #include "StdAfx.h"
10 
11 #include "../../../C/CpuArch.h"
12 
13 #include "../Common/StreamUtils.h"
14 
15 #include "Pbkdf2HmacSha1.h"
16 #include "RandGen.h"
17 #include "WzAes.h"
18 
19 namespace NCrypto {
20 namespace NWzAes {
21 
22 const unsigned kAesKeySizeMax = 32;
23 
24 static const UInt32 kNumKeyGenIterations = 1000;
25 
Z7_COM7F_IMF(CBaseCoder::CryptoSetPassword (const Byte * data,UInt32 size))26 Z7_COM7F_IMF(CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size))
27 {
28   if (size > kPasswordSizeMax)
29     return E_INVALIDARG;
30   _key.Password.Wipe();
31   _key.Password.CopyFrom(data, (size_t)size);
32   return S_OK;
33 }
34 
Init2()35 void CBaseCoder::Init2()
36 {
37   _hmacOverCalc = 0;
38   const unsigned dkSizeMax32 = (2 * kAesKeySizeMax + kPwdVerifSize + 3) / 4;
39   Byte dk[dkSizeMax32 * 4];
40 
41   const unsigned keySize = _key.GetKeySize();
42   const unsigned dkSize = 2 * keySize + ((kPwdVerifSize + 3) & ~(unsigned)3);
43 
44   // for (unsigned ii = 0; ii < 1000; ii++)
45   {
46     NSha1::Pbkdf2Hmac(
47         _key.Password, _key.Password.Size(),
48         _key.Salt, _key.GetSaltSize(),
49         kNumKeyGenIterations,
50         dk, dkSize);
51   }
52 
53   Hmac()->SetKey(dk + keySize, keySize);
54   memcpy(_key.PwdVerifComputed, dk + 2 * keySize, kPwdVerifSize);
55 
56   // Aes_SetKey_Enc(_aes.Aes() + 8, dk, keySize);
57   // AesCtr2_Init(&_aes);
58   _aesCoderSpec->SetKeySize(keySize);
59   if (_aesCoderSpec->SetKey(dk, keySize) != S_OK) throw 2;
60   if (_aesCoderSpec->Init() != S_OK) throw 3;
61 }
62 
Z7_COM7F_IMF(CBaseCoder::Init ())63 Z7_COM7F_IMF(CBaseCoder::Init())
64 {
65   return S_OK;
66 }
67 
WriteHeader(ISequentialOutStream * outStream)68 HRESULT CEncoder::WriteHeader(ISequentialOutStream *outStream)
69 {
70   unsigned saltSize = _key.GetSaltSize();
71   MY_RAND_GEN(_key.Salt, saltSize);
72   Init2();
73   RINOK(WriteStream(outStream, _key.Salt, saltSize))
74   return WriteStream(outStream, _key.PwdVerifComputed, kPwdVerifSize);
75 }
76 
WriteFooter(ISequentialOutStream * outStream)77 HRESULT CEncoder::WriteFooter(ISequentialOutStream *outStream)
78 {
79   MY_ALIGN (16)
80   UInt32 mac[NSha1::kNumDigestWords];
81   Hmac()->Final((Byte *)mac);
82   return WriteStream(outStream, mac, kMacSize);
83 }
84 
85 /*
86 Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size))
87 {
88   if (size != 1)
89     return E_INVALIDARG;
90   _key.Init();
91   return SetKeyMode(data[0]) ? S_OK : E_INVALIDARG;
92 }
93 */
94 
ReadHeader(ISequentialInStream * inStream)95 HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream)
96 {
97   const unsigned saltSize = _key.GetSaltSize();
98   const unsigned extraSize = saltSize + kPwdVerifSize;
99   Byte temp[kSaltSizeMax + kPwdVerifSize];
100   RINOK(ReadStream_FAIL(inStream, temp, extraSize))
101   unsigned i;
102   for (i = 0; i < saltSize; i++)
103     _key.Salt[i] = temp[i];
104   for (i = 0; i < kPwdVerifSize; i++)
105     _pwdVerifFromArchive[i] = temp[saltSize + i];
106   return S_OK;
107 }
108 
CompareArrays(const Byte * p1,const Byte * p2,unsigned size)109 static inline bool CompareArrays(const Byte *p1, const Byte *p2, unsigned size)
110 {
111   for (unsigned i = 0; i < size; i++)
112     if (p1[i] != p2[i])
113       return false;
114   return true;
115 }
116 
Init_and_CheckPassword()117 bool CDecoder::Init_and_CheckPassword()
118 {
119   Init2();
120   return CompareArrays(_key.PwdVerifComputed, _pwdVerifFromArchive, kPwdVerifSize);
121 }
122 
CheckMac(ISequentialInStream * inStream,bool & isOK)123 HRESULT CDecoder::CheckMac(ISequentialInStream *inStream, bool &isOK)
124 {
125   isOK = false;
126   MY_ALIGN (16)
127   Byte mac1[kMacSize];
128   RINOK(ReadStream_FAIL(inStream, mac1, kMacSize))
129   MY_ALIGN (16)
130   UInt32 mac2[NSha1::kNumDigestWords];
131   Hmac()->Final((Byte *)mac2);
132   isOK = CompareArrays(mac1, (const Byte *)mac2, kMacSize);
133   if (_hmacOverCalc)
134     isOK = false;
135   return S_OK;
136 }
137 
138 /*
139 
140 CAesCtr2::CAesCtr2():
141     aes((4 + AES_NUM_IVMRK_WORDS) * 4)
142 {
143   // offset = ((0 - (unsigned)(ptrdiff_t)aes) & 0xF) / sizeof(UInt32);
144   // first 16 bytes are buffer for last block data.
145   // so the ivAES is aligned for (Align + 16).
146 }
147 
148 void AesCtr2_Init(CAesCtr2 *p)
149 {
150   UInt32 *ctr = p->Aes() + 4;
151   unsigned i;
152   for (i = 0; i < 4; i++)
153     ctr[i] = 0;
154   p->pos = AES_BLOCK_SIZE;
155 }
156 
157 // (size != 16 * N) is allowed only for last call
158 
159 void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size)
160 {
161   unsigned pos = p->pos;
162   UInt32 *buf32 = p->Aes();
163   if (size == 0)
164     return;
165 
166   if (pos != AES_BLOCK_SIZE)
167   {
168     const Byte *buf = (const Byte *)buf32;
169     do
170       *data++ ^= buf[pos++];
171     while (--size != 0 && pos != AES_BLOCK_SIZE);
172   }
173 
174   // (size == 0 || pos == AES_BLOCK_SIZE)
175 
176   if (size >= 16)
177   {
178     SizeT size2 = size >> 4;
179     g_AesCtr_Code(buf32 + 4, data, size2);
180     size2 <<= 4;
181     data += size2;
182     size -= size2;
183     // (pos == AES_BLOCK_SIZE)
184   }
185 
186   // (size < 16)
187 
188   if (size != 0)
189   {
190     unsigned j;
191     const Byte *buf;
192     for (j = 0; j < 4; j++)
193       buf32[j] = 0;
194     g_AesCtr_Code(buf32 + 4, (Byte *)buf32, 1);
195     buf = (const Byte *)buf32;
196     pos = 0;
197     do
198       *data++ ^= buf[pos++];
199     while (--size != 0);
200   }
201 
202   p->pos = pos;
203 }
204 */
205 
206 /* (size != 16 * N) is allowed only for last Filter() call */
207 
Z7_COM7F_IMF2(UInt32,CEncoder::Filter (Byte * data,UInt32 size))208 Z7_COM7F_IMF2(UInt32, CEncoder::Filter(Byte *data, UInt32 size))
209 {
210   // AesCtr2_Code(&_aes, data, size);
211   size = _aesCoder->Filter(data, size);
212   Hmac()->Update(data, size);
213   return size;
214 }
215 
Z7_COM7F_IMF2(UInt32,CDecoder::Filter (Byte * data,UInt32 size))216 Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size))
217 {
218   if (size >= 16)
219     size &= ~(UInt32)15;
220   if (_hmacOverCalc < size)
221   {
222     Hmac()->Update(data + _hmacOverCalc, size - _hmacOverCalc);
223     _hmacOverCalc = size;
224   }
225   // AesCtr2_Code(&_aes, data, size);
226   size = _aesCoder->Filter(data, size);
227   _hmacOverCalc -= size;
228   return size;
229 }
230 
231 }}
232