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