1 // Crypto/MyAes.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../C/CpuArch.h"
6 
7 #include "MyAes.h"
8 
9 namespace NCrypto {
10 
CAesTabInitNCrypto::CAesTabInit11 static struct CAesTabInit { CAesTabInit() { AesGenTables();} } g_AesTabInit;
12 
CAesCoder( unsigned keySize )13 CAesCoder::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 
Init()34 Z7_COM7F_IMF(CAesCoder::Init())
35 {
36   _ctrPos = 0;
37   AesCbc_Init(Aes(), _iv);
38   return _keyIsSet ? S_OK : E_NOTIMPL; // E_FAIL
39 }
40 
Z7_COM7F_IMF2(UInt32, CAesCoder::Filter(Byte *data, UInt32 size))41 Z7_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 
SetKey(const Byte *data, UInt32 size)58 Z7_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 
SetInitVector(const Byte *data, UInt32 size)69 Z7_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 /*
84 Z7_COM7F_IMF(CAesCtrCoder::Init())
85 {
86   _ctrPos = 0;
87   return CAesCoder::Init();
88 }
89 */
90 
Z7_COM7F_IMF2(UInt32, CAesCtrCoder::Filter(Byte *data, UInt32 size))91 Z7_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
202 SET_AES_FUNCS(
203     CAesCtrCoder,
204   g_AesCtr_Code,
205     AesCtr_Code,
206     AesCtr_Code_HW,
207     AesCtr_Code_HW_256)
208 #endif
209 
210 SET_AES_FUNCS(
211     CAesCbcEncoder,
212   g_AesCbc_Encode,
213     AesCbc_Encode,
214     AesCbc_Encode_HW,
215     AesCbc_Encode_HW)
216 
217 SET_AES_FUNCS(
218     CAesCbcDecoder,
219   g_AesCbc_Decode,
220     AesCbc_Decode,
221     AesCbc_Decode_HW,
222     AesCbc_Decode_HW_256)
223 
SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)224 Z7_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