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