xref: /third_party/lzma/CPP/7zip/Crypto/MyAes.cpp (revision 370b324c)
1// Crypto/MyAes.cpp
2
3#include "StdAfx.h"
4
5#include "../../../C/CpuArch.h"
6
7#include "MyAes.h"
8
9namespace NCrypto {
10
11static struct CAesTabInit { CAesTabInit() { AesGenTables();} } g_AesTabInit;
12
13CAesCoder::CAesCoder(
14      // bool encodeMode,
15      unsigned keySize
16      // , bool ctrMode
17      ):
18  _keyIsSet(false),
19  // _encodeMode(encodeMode),
20  // _ctrMode(ctrMode),
21  _keySize(keySize),
22  // _ctrPos(0), // _ctrPos =0 will be set in Init()
23  _aes(AES_NUM_IVMRK_WORDS * 4 + AES_BLOCK_SIZE * 2)
24{
25  // _offset = ((0 - (unsigned)(ptrdiff_t)_aes) & 0xF) / sizeof(UInt32);
26  memset(_iv, 0, AES_BLOCK_SIZE);
27  /*
28  // we can use the following code to test 32-bit overflow case for AES-CTR
29  for (unsigned i = 0; i < 16; i++) _iv[i] = (Byte)(i + 1);
30  _iv[0] = 0xFE; _iv[1] = _iv[2] = _iv[3] = 0xFF;
31  */
32}
33
34Z7_COM7F_IMF(CAesCoder::Init())
35{
36  _ctrPos = 0;
37  AesCbc_Init(Aes(), _iv);
38  return _keyIsSet ? S_OK : E_NOTIMPL; // E_FAIL
39}
40
41Z7_COM7F_IMF2(UInt32, CAesCoder::Filter(Byte *data, UInt32 size))
42{
43  if (!_keyIsSet)
44    return 0;
45  if (size < AES_BLOCK_SIZE)
46  {
47    if (size == 0)
48      return 0;
49    return AES_BLOCK_SIZE;
50  }
51  size >>= 4;
52  // (data) must be aligned for 16-bytes here
53  _codeFunc(Aes(), data, size);
54  return size << 4;
55}
56
57
58Z7_COM7F_IMF(CAesCoder::SetKey(const Byte *data, UInt32 size))
59{
60  if ((size & 0x7) != 0 || size < 16 || size > 32)
61    return E_INVALIDARG;
62  if (_keySize != 0 && size != _keySize)
63    return E_INVALIDARG;
64  _setKeyFunc(Aes() + 4, data, size);
65  _keyIsSet = true;
66  return S_OK;
67}
68
69Z7_COM7F_IMF(CAesCoder::SetInitVector(const Byte *data, UInt32 size))
70{
71  if (size != AES_BLOCK_SIZE)
72    return E_INVALIDARG;
73  memcpy(_iv, data, size);
74  /* we allow SetInitVector() call before SetKey() call.
75     so we ignore possible error in Init() here */
76  CAesCoder::Init(); // don't call virtual function here !!!
77  return S_OK;
78}
79
80
81#ifndef Z7_SFX
82
83/*
84Z7_COM7F_IMF(CAesCtrCoder::Init())
85{
86  _ctrPos = 0;
87  return CAesCoder::Init();
88}
89*/
90
91Z7_COM7F_IMF2(UInt32, CAesCtrCoder::Filter(Byte *data, UInt32 size))
92{
93  if (!_keyIsSet)
94    return 0;
95  if (size == 0)
96    return 0;
97
98  if (_ctrPos != 0)
99  {
100    /* Optimized caller will not call here */
101    const Byte *ctr = (Byte *)(Aes() + AES_NUM_IVMRK_WORDS);
102    unsigned num = 0;
103    for (unsigned i = _ctrPos; i != AES_BLOCK_SIZE; i++)
104    {
105      if (num == size)
106      {
107        _ctrPos = i;
108        return num;
109      }
110      data[num++] ^= ctr[i];
111    }
112    _ctrPos = 0;
113    /* if (num < size) {
114       we can filter more data with _codeFunc().
115       But it's supposed that the caller can work correctly,
116       even if we do only partial filtering here.
117       So we filter data only for current 16-byte block. }
118    */
119    /*
120    size -= num;
121    size >>= 4;
122    // (data) must be aligned for 16-bytes here
123    _codeFunc(Aes(), data + num, size);
124    return num + (size << 4);
125    */
126    return num;
127  }
128
129  if (size < AES_BLOCK_SIZE)
130  {
131    /* The good optimized caller can call here only in last Filter() call.
132       But we support also non-optimized callers,
133       where another Filter() calls are allowed after this call.
134    */
135    Byte *ctr = (Byte *)(Aes() + AES_NUM_IVMRK_WORDS);
136    memset(ctr, 0, AES_BLOCK_SIZE);
137    memcpy(ctr, data, size);
138    _codeFunc(Aes(), ctr, 1);
139    memcpy(data, ctr, size);
140    _ctrPos = size;
141    return size;
142  }
143
144  size >>= 4;
145  // (data) must be aligned for 16-bytes here
146  _codeFunc(Aes(), data, size);
147  return size << 4;
148}
149
150#endif // Z7_SFX
151
152
153#ifndef Z7_EXTRACT_ONLY
154
155#ifdef MY_CPU_X86_OR_AMD64
156  #define USE_HW_AES
157#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE)
158  #if defined(__clang__)
159    #if (__clang_major__ >= 8) // fix that check
160      #define USE_HW_AES
161    #endif
162  #elif defined(__GNUC__)
163    #if (__GNUC__ >= 6) // fix that check
164      #define USE_HW_AES
165    #endif
166  #elif defined(_MSC_VER)
167    #if _MSC_VER >= 1910
168      #define USE_HW_AES
169    #endif
170  #endif
171#endif
172
173#ifdef USE_HW_AES
174    #define SET_AES_FUNC_2(f2) \
175      if (algo == 2) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW) \
176      { f = f2; }
177  #ifdef MY_CPU_X86_OR_AMD64
178    #define SET_AES_FUNC_23(f2, f3) \
179      SET_AES_FUNC_2(f2) \
180      if (algo == 3) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW_256) \
181      { f = f3; }
182  #else  // MY_CPU_X86_OR_AMD64
183    #define SET_AES_FUNC_23(f2, f3) \
184      SET_AES_FUNC_2(f2)
185  #endif // MY_CPU_X86_OR_AMD64
186#else  // USE_HW_AES
187    #define SET_AES_FUNC_23(f2, f3)
188#endif // USE_HW_AES
189
190#define SET_AES_FUNCS(c, f0, f1, f2, f3) \
191  bool c::SetFunctions(UInt32 algo) { \
192  _codeFunc = f0; if (algo < 1) return true; \
193  AES_CODE_FUNC f = NULL; \
194  if (algo == 1) { f = f1; } \
195  SET_AES_FUNC_23(f2, f3) \
196  if (f) { _codeFunc = f; return true; } \
197  return false; }
198
199
200
201#ifndef Z7_SFX
202SET_AES_FUNCS(
203    CAesCtrCoder,
204  g_AesCtr_Code,
205    AesCtr_Code,
206    AesCtr_Code_HW,
207    AesCtr_Code_HW_256)
208#endif
209
210SET_AES_FUNCS(
211    CAesCbcEncoder,
212  g_AesCbc_Encode,
213    AesCbc_Encode,
214    AesCbc_Encode_HW,
215    AesCbc_Encode_HW)
216
217SET_AES_FUNCS(
218    CAesCbcDecoder,
219  g_AesCbc_Decode,
220    AesCbc_Decode,
221    AesCbc_Decode_HW,
222    AesCbc_Decode_HW_256)
223
224Z7_COM7F_IMF(CAesCoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps))
225{
226  UInt32 algo = 0;
227  for (UInt32 i = 0; i < numProps; i++)
228  {
229    if (propIDs[i] == NCoderPropID::kDefaultProp)
230    {
231      const PROPVARIANT &prop = coderProps[i];
232      if (prop.vt != VT_UI4)
233        return E_INVALIDARG;
234      if (prop.ulVal > 3)
235        return E_NOTIMPL;
236      algo = prop.ulVal;
237    }
238  }
239  if (!SetFunctions(algo))
240    return E_NOTIMPL;
241  return S_OK;
242}
243
244#endif // Z7_EXTRACT_ONLY
245
246}
247