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
Z7_COM7F_IMF(CAesCoder::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
Z7_COM7F_IMF(CAesCoder::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
Z7_COM7F_IMF(CAesCoder::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
159 #if defined(__ARM_FEATURE_AES) \
160 || defined(__ARM_FEATURE_CRYPTO)
161 #define USE_HW_AES
162 #else
163 #if defined(MY_CPU_ARM64) \
164 || defined(__ARM_ARCH) && (__ARM_ARCH >= 4) \
165 || defined(Z7_MSC_VER_ORIGINAL)
166 #if defined(__ARM_FP) && \
167 ( defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \
168 || defined(__GNUC__) && (__GNUC__ >= 6) \
169 ) \
170 || defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1910)
171 #if defined(MY_CPU_ARM64) \
172 || !defined(Z7_CLANG_VERSION) \
173 || defined(__ARM_NEON) && \
174 (Z7_CLANG_VERSION < 170000 || \
175 Z7_CLANG_VERSION > 170001)
176 #define USE_HW_AES
177 #endif
178 #endif
179 #endif
180 #endif
181 #endif
182
183 #ifdef USE_HW_AES
184 // #pragma message("=== MyAES.c USE_HW_AES === ")
185
186 #define SET_AES_FUNC_2(f2) \
187 if (algo == 2) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW) \
188 { f = f2; }
189 #ifdef MY_CPU_X86_OR_AMD64
190 #define SET_AES_FUNC_23(f2, f3) \
191 SET_AES_FUNC_2(f2) \
192 if (algo == 3) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW_256) \
193 { f = f3; }
194 #else // MY_CPU_X86_OR_AMD64
195 #define SET_AES_FUNC_23(f2, f3) \
196 SET_AES_FUNC_2(f2)
197 #endif // MY_CPU_X86_OR_AMD64
198 #else // USE_HW_AES
199 #define SET_AES_FUNC_23(f2, f3)
200 #endif // USE_HW_AES
201
202 #define SET_AES_FUNCS(c, f0, f1, f2, f3) \
203 bool c::SetFunctions(UInt32 algo) { \
204 _codeFunc = f0; if (algo < 1) return true; \
205 AES_CODE_FUNC f = NULL; \
206 if (algo == 1) { f = f1; } \
207 SET_AES_FUNC_23(f2, f3) \
208 if (f) { _codeFunc = f; return true; } \
209 return false; }
210
211
212
213 #ifndef Z7_SFX
SET_AES_FUNCS(CAesCtrCoder,g_AesCtr_Code,AesCtr_Code,AesCtr_Code_HW,AesCtr_Code_HW_256)214 SET_AES_FUNCS(
215 CAesCtrCoder,
216 g_AesCtr_Code,
217 AesCtr_Code,
218 AesCtr_Code_HW,
219 AesCtr_Code_HW_256)
220 #endif
221
222 SET_AES_FUNCS(
223 CAesCbcEncoder,
224 g_AesCbc_Encode,
225 AesCbc_Encode,
226 AesCbc_Encode_HW,
227 AesCbc_Encode_HW)
228
229 SET_AES_FUNCS(
230 CAesCbcDecoder,
231 g_AesCbc_Decode,
232 AesCbc_Decode,
233 AesCbc_Decode_HW,
234 AesCbc_Decode_HW_256)
235
236 Z7_COM7F_IMF(CAesCoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps))
237 {
238 UInt32 algo = 0;
239 for (UInt32 i = 0; i < numProps; i++)
240 {
241 if (propIDs[i] == NCoderPropID::kDefaultProp)
242 {
243 const PROPVARIANT &prop = coderProps[i];
244 if (prop.vt != VT_UI4)
245 return E_INVALIDARG;
246 if (prop.ulVal > 3)
247 return E_NOTIMPL;
248 algo = prop.ulVal;
249 }
250 }
251 if (!SetFunctions(algo))
252 return E_NOTIMPL;
253 return S_OK;
254 }
255
256 #endif // Z7_EXTRACT_ONLY
257
258 }
259