Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1257 lines
36 KiB

  1. // rijndael.cpp - modified by Chris Morgan <[email protected]>
  2. // and Wei Dai from Paulo Baretto's Rijndael implementation
  3. // The original code and all modifications are in the public domain.
  4. // use "cl /EP /P /DCRYPTOPP_GENERATE_X64_MASM rijndael.cpp" to generate MASM code
  5. /*
  6. July 2010: Added support for AES-NI instructions via compiler intrinsics.
  7. */
  8. /*
  9. Feb 2009: The x86/x64 assembly code was rewritten in by Wei Dai to do counter mode
  10. caching, which was invented by Hongjun Wu and popularized by Daniel J. Bernstein
  11. and Peter Schwabe in their paper "New AES software speed records". The round
  12. function was also modified to include a trick similar to one in Brian Gladman's
  13. x86 assembly code, doing an 8-bit register move to minimize the number of
  14. register spills. Also switched to compressed tables and copying round keys to
  15. the stack.
  16. The C++ implementation now uses compressed tables if
  17. CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS is defined.
  18. */
  19. /*
  20. July 2006: Defense against timing attacks was added in by Wei Dai.
  21. The code now uses smaller tables in the first and last rounds,
  22. and preloads them into L1 cache before usage (by loading at least
  23. one element in each cache line).
  24. We try to delay subsequent accesses to each table (used in the first
  25. and last rounds) until all of the table has been preloaded. Hopefully
  26. the compiler isn't smart enough to optimize that code away.
  27. After preloading the table, we also try not to access any memory location
  28. other than the table and the stack, in order to prevent table entries from
  29. being unloaded from L1 cache, until that round is finished.
  30. (Some popular CPUs have 2-way associative caches.)
  31. */
  32. // This is the original introductory comment:
  33. /**
  34. * version 3.0 (December 2000)
  35. *
  36. * Optimised ANSI C code for the Rijndael cipher (now AES)
  37. *
  38. * author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
  39. * author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
  40. * author Paulo Barreto <paulo.barreto@terra.com.br>
  41. *
  42. * This code is hereby placed in the public domain.
  43. *
  44. * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
  45. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  46. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  47. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
  48. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  49. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  50. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  51. * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  52. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  53. * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  54. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  55. */
  56. #include "pch.h"
  57. #ifndef CRYPTOPP_IMPORTS
  58. #ifndef CRYPTOPP_GENERATE_X64_MASM
  59. #include "rijndael.h"
  60. #include "misc.h"
  61. #include "cpu.h"
  62. NAMESPACE_BEGIN(CryptoPP)
  63. #ifdef CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS
  64. #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE || defined(CRYPTOPP_X64_MASM_AVAILABLE)
  65. namespace rdtable {CRYPTOPP_ALIGN_DATA(16) word64 Te[256+2];}
  66. using namespace rdtable;
  67. #else
  68. static word64 Te[256];
  69. #endif
  70. static word64 Td[256];
  71. #else
  72. static word32 Te[256*4], Td[256*4];
  73. #endif
  74. static volatile bool s_TeFilled = false, s_TdFilled = false;
  75. // ************************* Portable Code ************************************
  76. #define QUARTER_ROUND(L, T, t, a, b, c, d) \
  77. a ^= L(T, 3, byte(t)); t >>= 8;\
  78. b ^= L(T, 2, byte(t)); t >>= 8;\
  79. c ^= L(T, 1, byte(t)); t >>= 8;\
  80. d ^= L(T, 0, t);
  81. #define QUARTER_ROUND_LE(t, a, b, c, d) \
  82. tempBlock[a] = ((byte *)(Te+byte(t)))[1]; t >>= 8;\
  83. tempBlock[b] = ((byte *)(Te+byte(t)))[1]; t >>= 8;\
  84. tempBlock[c] = ((byte *)(Te+byte(t)))[1]; t >>= 8;\
  85. tempBlock[d] = ((byte *)(Te+t))[1];
  86. #ifdef CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS
  87. #define QUARTER_ROUND_LD(t, a, b, c, d) \
  88. tempBlock[a] = ((byte *)(Td+byte(t)))[GetNativeByteOrder()*7]; t >>= 8;\
  89. tempBlock[b] = ((byte *)(Td+byte(t)))[GetNativeByteOrder()*7]; t >>= 8;\
  90. tempBlock[c] = ((byte *)(Td+byte(t)))[GetNativeByteOrder()*7]; t >>= 8;\
  91. tempBlock[d] = ((byte *)(Td+t))[GetNativeByteOrder()*7];
  92. #else
  93. #define QUARTER_ROUND_LD(t, a, b, c, d) \
  94. tempBlock[a] = Sd[byte(t)]; t >>= 8;\
  95. tempBlock[b] = Sd[byte(t)]; t >>= 8;\
  96. tempBlock[c] = Sd[byte(t)]; t >>= 8;\
  97. tempBlock[d] = Sd[t];
  98. #endif
  99. #define QUARTER_ROUND_E(t, a, b, c, d) QUARTER_ROUND(TL_M, Te, t, a, b, c, d)
  100. #define QUARTER_ROUND_D(t, a, b, c, d) QUARTER_ROUND(TL_M, Td, t, a, b, c, d)
  101. #ifdef IS_LITTLE_ENDIAN
  102. #define QUARTER_ROUND_FE(t, a, b, c, d) QUARTER_ROUND(TL_F, Te, t, d, c, b, a)
  103. #define QUARTER_ROUND_FD(t, a, b, c, d) QUARTER_ROUND(TL_F, Td, t, d, c, b, a)
  104. #ifdef CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS
  105. #define TL_F(T, i, x) (*(word32 *)((byte *)T + x*8 + (6-i)%4+1))
  106. #define TL_M(T, i, x) (*(word32 *)((byte *)T + x*8 + (i+3)%4+1))
  107. #else
  108. #define TL_F(T, i, x) rotrFixed(T[x], (3-i)*8)
  109. #define TL_M(T, i, x) T[i*256 + x]
  110. #endif
  111. #else
  112. #define QUARTER_ROUND_FE(t, a, b, c, d) QUARTER_ROUND(TL_F, Te, t, a, b, c, d)
  113. #define QUARTER_ROUND_FD(t, a, b, c, d) QUARTER_ROUND(TL_F, Td, t, a, b, c, d)
  114. #ifdef CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS
  115. #define TL_F(T, i, x) (*(word32 *)((byte *)T + x*8 + (4-i)%4))
  116. #define TL_M TL_F
  117. #else
  118. #define TL_F(T, i, x) rotrFixed(T[x], i*8)
  119. #define TL_M(T, i, x) T[i*256 + x]
  120. #endif
  121. #endif
  122. #define f2(x) ((x<<1)^(((x>>7)&1)*0x11b))
  123. #define f4(x) ((x<<2)^(((x>>6)&1)*0x11b)^(((x>>6)&2)*0x11b))
  124. #define f8(x) ((x<<3)^(((x>>5)&1)*0x11b)^(((x>>5)&2)*0x11b)^(((x>>5)&4)*0x11b))
  125. #define f3(x) (f2(x) ^ x)
  126. #define f9(x) (f8(x) ^ x)
  127. #define fb(x) (f8(x) ^ f2(x) ^ x)
  128. #define fd(x) (f8(x) ^ f4(x) ^ x)
  129. #define fe(x) (f8(x) ^ f4(x) ^ f2(x))
  130. void Rijndael::Base::FillEncTable()
  131. {
  132. for (int i=0; i<256; i++)
  133. {
  134. byte x = Se[i];
  135. #ifdef CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS
  136. word32 y = word32(x)<<8 | word32(x)<<16 | word32(f2(x))<<24;
  137. Te[i] = word64(y | f3(x))<<32 | y;
  138. #else
  139. word32 y = f3(x) | word32(x)<<8 | word32(x)<<16 | word32(f2(x))<<24;
  140. for (int j=0; j<4; j++)
  141. {
  142. Te[i+j*256] = y;
  143. y = rotrFixed(y, 8);
  144. }
  145. #endif
  146. }
  147. #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE || defined(CRYPTOPP_X64_MASM_AVAILABLE)
  148. Te[256] = Te[257] = 0;
  149. #endif
  150. s_TeFilled = true;
  151. }
  152. void Rijndael::Base::FillDecTable()
  153. {
  154. for (int i=0; i<256; i++)
  155. {
  156. byte x = Sd[i];
  157. #ifdef CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS
  158. word32 y = word32(fd(x))<<8 | word32(f9(x))<<16 | word32(fe(x))<<24;
  159. Td[i] = word64(y | fb(x))<<32 | y | x;
  160. #else
  161. word32 y = fb(x) | word32(fd(x))<<8 | word32(f9(x))<<16 | word32(fe(x))<<24;;
  162. for (int j=0; j<4; j++)
  163. {
  164. Td[i+j*256] = y;
  165. y = rotrFixed(y, 8);
  166. }
  167. #endif
  168. }
  169. s_TdFilled = true;
  170. }
  171. void Rijndael::Base::UncheckedSetKey(const byte *userKey, unsigned int keylen, const NameValuePairs &)
  172. {
  173. AssertValidKeyLength(keylen);
  174. m_rounds = keylen/4 + 6;
  175. m_key.New(4*(m_rounds+1));
  176. word32 *rk = m_key;
  177. #if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE && (!defined(_MSC_VER) || _MSC_VER >= 1600 || CRYPTOPP_BOOL_X86)
  178. // MSVC 2008 SP1 generates bad code for _mm_extract_epi32() when compiling for X64
  179. if (HasAESNI())
  180. {
  181. static const word32 rcLE[] = {
  182. 0x01, 0x02, 0x04, 0x08,
  183. 0x10, 0x20, 0x40, 0x80,
  184. 0x1B, 0x36, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
  185. };
  186. const word32 *rc = rcLE;
  187. __m128i temp = _mm_loadu_si128((__m128i *)(userKey+keylen-16));
  188. memcpy(rk, userKey, keylen);
  189. while (true)
  190. {
  191. rk[keylen/4] = rk[0] ^ _mm_extract_epi32(_mm_aeskeygenassist_si128(temp, 0), 3) ^ *(rc++);
  192. rk[keylen/4+1] = rk[1] ^ rk[keylen/4];
  193. rk[keylen/4+2] = rk[2] ^ rk[keylen/4+1];
  194. rk[keylen/4+3] = rk[3] ^ rk[keylen/4+2];
  195. if (rk + keylen/4 + 4 == m_key.end())
  196. break;
  197. if (keylen == 24)
  198. {
  199. rk[10] = rk[ 4] ^ rk[ 9];
  200. rk[11] = rk[ 5] ^ rk[10];
  201. temp = _mm_insert_epi32(temp, rk[11], 3);
  202. }
  203. else if (keylen == 32)
  204. {
  205. temp = _mm_insert_epi32(temp, rk[11], 3);
  206. rk[12] = rk[ 4] ^ _mm_extract_epi32(_mm_aeskeygenassist_si128(temp, 0), 2);
  207. rk[13] = rk[ 5] ^ rk[12];
  208. rk[14] = rk[ 6] ^ rk[13];
  209. rk[15] = rk[ 7] ^ rk[14];
  210. temp = _mm_insert_epi32(temp, rk[15], 3);
  211. }
  212. else
  213. temp = _mm_insert_epi32(temp, rk[7], 3);
  214. rk += keylen/4;
  215. }
  216. if (!IsForwardTransformation())
  217. {
  218. rk = m_key;
  219. unsigned int i, j;
  220. std::swap(*(__m128i *)(rk), *(__m128i *)(rk+4*m_rounds));
  221. for (i = 4, j = 4*m_rounds-4; i < j; i += 4, j -= 4)
  222. {
  223. temp = _mm_aesimc_si128(*(__m128i *)(rk+i));
  224. *(__m128i *)(rk+i) = _mm_aesimc_si128(*(__m128i *)(rk+j));
  225. *(__m128i *)(rk+j) = temp;
  226. }
  227. *(__m128i *)(rk+i) = _mm_aesimc_si128(*(__m128i *)(rk+i));
  228. }
  229. return;
  230. }
  231. #endif
  232. GetUserKey(BIG_ENDIAN_ORDER, rk, keylen/4, userKey, keylen);
  233. const word32 *rc = rcon;
  234. word32 temp;
  235. while (true)
  236. {
  237. temp = rk[keylen/4-1];
  238. word32 x = (word32(Se[GETBYTE(temp, 2)]) << 24) ^ (word32(Se[GETBYTE(temp, 1)]) << 16) ^ (word32(Se[GETBYTE(temp, 0)]) << 8) ^ Se[GETBYTE(temp, 3)];
  239. rk[keylen/4] = rk[0] ^ x ^ *(rc++);
  240. rk[keylen/4+1] = rk[1] ^ rk[keylen/4];
  241. rk[keylen/4+2] = rk[2] ^ rk[keylen/4+1];
  242. rk[keylen/4+3] = rk[3] ^ rk[keylen/4+2];
  243. if (rk + keylen/4 + 4 == m_key.end())
  244. break;
  245. if (keylen == 24)
  246. {
  247. rk[10] = rk[ 4] ^ rk[ 9];
  248. rk[11] = rk[ 5] ^ rk[10];
  249. }
  250. else if (keylen == 32)
  251. {
  252. temp = rk[11];
  253. rk[12] = rk[ 4] ^ (word32(Se[GETBYTE(temp, 3)]) << 24) ^ (word32(Se[GETBYTE(temp, 2)]) << 16) ^ (word32(Se[GETBYTE(temp, 1)]) << 8) ^ Se[GETBYTE(temp, 0)];
  254. rk[13] = rk[ 5] ^ rk[12];
  255. rk[14] = rk[ 6] ^ rk[13];
  256. rk[15] = rk[ 7] ^ rk[14];
  257. }
  258. rk += keylen/4;
  259. }
  260. rk = m_key;
  261. if (IsForwardTransformation())
  262. {
  263. if (!s_TeFilled)
  264. FillEncTable();
  265. ConditionalByteReverse(BIG_ENDIAN_ORDER, rk, rk, 16);
  266. ConditionalByteReverse(BIG_ENDIAN_ORDER, rk + m_rounds*4, rk + m_rounds*4, 16);
  267. }
  268. else
  269. {
  270. if (!s_TdFilled)
  271. FillDecTable();
  272. unsigned int i, j;
  273. #define InverseMixColumn(x) TL_M(Td, 0, Se[GETBYTE(x, 3)]) ^ TL_M(Td, 1, Se[GETBYTE(x, 2)]) ^ TL_M(Td, 2, Se[GETBYTE(x, 1)]) ^ TL_M(Td, 3, Se[GETBYTE(x, 0)])
  274. for (i = 4, j = 4*m_rounds-4; i < j; i += 4, j -= 4)
  275. {
  276. temp = InverseMixColumn(rk[i ]); rk[i ] = InverseMixColumn(rk[j ]); rk[j ] = temp;
  277. temp = InverseMixColumn(rk[i + 1]); rk[i + 1] = InverseMixColumn(rk[j + 1]); rk[j + 1] = temp;
  278. temp = InverseMixColumn(rk[i + 2]); rk[i + 2] = InverseMixColumn(rk[j + 2]); rk[j + 2] = temp;
  279. temp = InverseMixColumn(rk[i + 3]); rk[i + 3] = InverseMixColumn(rk[j + 3]); rk[j + 3] = temp;
  280. }
  281. rk[i+0] = InverseMixColumn(rk[i+0]);
  282. rk[i+1] = InverseMixColumn(rk[i+1]);
  283. rk[i+2] = InverseMixColumn(rk[i+2]);
  284. rk[i+3] = InverseMixColumn(rk[i+3]);
  285. temp = ConditionalByteReverse(BIG_ENDIAN_ORDER, rk[0]); rk[0] = ConditionalByteReverse(BIG_ENDIAN_ORDER, rk[4*m_rounds+0]); rk[4*m_rounds+0] = temp;
  286. temp = ConditionalByteReverse(BIG_ENDIAN_ORDER, rk[1]); rk[1] = ConditionalByteReverse(BIG_ENDIAN_ORDER, rk[4*m_rounds+1]); rk[4*m_rounds+1] = temp;
  287. temp = ConditionalByteReverse(BIG_ENDIAN_ORDER, rk[2]); rk[2] = ConditionalByteReverse(BIG_ENDIAN_ORDER, rk[4*m_rounds+2]); rk[4*m_rounds+2] = temp;
  288. temp = ConditionalByteReverse(BIG_ENDIAN_ORDER, rk[3]); rk[3] = ConditionalByteReverse(BIG_ENDIAN_ORDER, rk[4*m_rounds+3]); rk[4*m_rounds+3] = temp;
  289. }
  290. #if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
  291. if (HasAESNI())
  292. ConditionalByteReverse(BIG_ENDIAN_ORDER, rk+4, rk+4, (m_rounds-1)*16);
  293. #endif
  294. }
  295. void Rijndael::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
  296. {
  297. #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE || defined(CRYPTOPP_X64_MASM_AVAILABLE) || CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
  298. if (HasSSE2())
  299. {
  300. Rijndael::Enc::AdvancedProcessBlocks(inBlock, xorBlock, outBlock, 16, 0);
  301. return;
  302. }
  303. #endif
  304. typedef BlockGetAndPut<word32, NativeByteOrder> Block;
  305. word32 s0, s1, s2, s3, t0, t1, t2, t3;
  306. Block::Get(inBlock)(s0)(s1)(s2)(s3);
  307. const word32 *rk = m_key;
  308. s0 ^= rk[0];
  309. s1 ^= rk[1];
  310. s2 ^= rk[2];
  311. s3 ^= rk[3];
  312. t0 = rk[4];
  313. t1 = rk[5];
  314. t2 = rk[6];
  315. t3 = rk[7];
  316. rk += 8;
  317. // timing attack countermeasure. see comments at top for more details
  318. const int cacheLineSize = GetCacheLineSize();
  319. unsigned int i;
  320. word32 u = 0;
  321. #ifdef CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS
  322. for (i=0; i<2048; i+=cacheLineSize)
  323. #else
  324. for (i=0; i<1024; i+=cacheLineSize)
  325. #endif
  326. u &= *(const word32 *)(((const byte *)Te)+i);
  327. u &= Te[255];
  328. s0 |= u; s1 |= u; s2 |= u; s3 |= u;
  329. QUARTER_ROUND_FE(s3, t0, t1, t2, t3)
  330. QUARTER_ROUND_FE(s2, t3, t0, t1, t2)
  331. QUARTER_ROUND_FE(s1, t2, t3, t0, t1)
  332. QUARTER_ROUND_FE(s0, t1, t2, t3, t0)
  333. // Nr - 2 full rounds:
  334. unsigned int r = m_rounds/2 - 1;
  335. do
  336. {
  337. s0 = rk[0]; s1 = rk[1]; s2 = rk[2]; s3 = rk[3];
  338. QUARTER_ROUND_E(t3, s0, s1, s2, s3)
  339. QUARTER_ROUND_E(t2, s3, s0, s1, s2)
  340. QUARTER_ROUND_E(t1, s2, s3, s0, s1)
  341. QUARTER_ROUND_E(t0, s1, s2, s3, s0)
  342. t0 = rk[4]; t1 = rk[5]; t2 = rk[6]; t3 = rk[7];
  343. QUARTER_ROUND_E(s3, t0, t1, t2, t3)
  344. QUARTER_ROUND_E(s2, t3, t0, t1, t2)
  345. QUARTER_ROUND_E(s1, t2, t3, t0, t1)
  346. QUARTER_ROUND_E(s0, t1, t2, t3, t0)
  347. rk += 8;
  348. } while (--r);
  349. word32 tbw[4];
  350. byte *const tempBlock = (byte *)tbw;
  351. QUARTER_ROUND_LE(t2, 15, 2, 5, 8)
  352. QUARTER_ROUND_LE(t1, 11, 14, 1, 4)
  353. QUARTER_ROUND_LE(t0, 7, 10, 13, 0)
  354. QUARTER_ROUND_LE(t3, 3, 6, 9, 12)
  355. Block::Put(xorBlock, outBlock)(tbw[0]^rk[0])(tbw[1]^rk[1])(tbw[2]^rk[2])(tbw[3]^rk[3]);
  356. }
  357. void Rijndael::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
  358. {
  359. #if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
  360. if (HasAESNI())
  361. {
  362. Rijndael::Dec::AdvancedProcessBlocks(inBlock, xorBlock, outBlock, 16, 0);
  363. return;
  364. }
  365. #endif
  366. typedef BlockGetAndPut<word32, NativeByteOrder> Block;
  367. word32 s0, s1, s2, s3, t0, t1, t2, t3;
  368. Block::Get(inBlock)(s0)(s1)(s2)(s3);
  369. const word32 *rk = m_key;
  370. s0 ^= rk[0];
  371. s1 ^= rk[1];
  372. s2 ^= rk[2];
  373. s3 ^= rk[3];
  374. t0 = rk[4];
  375. t1 = rk[5];
  376. t2 = rk[6];
  377. t3 = rk[7];
  378. rk += 8;
  379. // timing attack countermeasure. see comments at top for more details
  380. const int cacheLineSize = GetCacheLineSize();
  381. unsigned int i;
  382. word32 u = 0;
  383. #ifdef CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS
  384. for (i=0; i<2048; i+=cacheLineSize)
  385. #else
  386. for (i=0; i<1024; i+=cacheLineSize)
  387. #endif
  388. u &= *(const word32 *)(((const byte *)Td)+i);
  389. u &= Td[255];
  390. s0 |= u; s1 |= u; s2 |= u; s3 |= u;
  391. QUARTER_ROUND_FD(s3, t2, t1, t0, t3)
  392. QUARTER_ROUND_FD(s2, t1, t0, t3, t2)
  393. QUARTER_ROUND_FD(s1, t0, t3, t2, t1)
  394. QUARTER_ROUND_FD(s0, t3, t2, t1, t0)
  395. // Nr - 2 full rounds:
  396. unsigned int r = m_rounds/2 - 1;
  397. do
  398. {
  399. s0 = rk[0]; s1 = rk[1]; s2 = rk[2]; s3 = rk[3];
  400. QUARTER_ROUND_D(t3, s2, s1, s0, s3)
  401. QUARTER_ROUND_D(t2, s1, s0, s3, s2)
  402. QUARTER_ROUND_D(t1, s0, s3, s2, s1)
  403. QUARTER_ROUND_D(t0, s3, s2, s1, s0)
  404. t0 = rk[4]; t1 = rk[5]; t2 = rk[6]; t3 = rk[7];
  405. QUARTER_ROUND_D(s3, t2, t1, t0, t3)
  406. QUARTER_ROUND_D(s2, t1, t0, t3, t2)
  407. QUARTER_ROUND_D(s1, t0, t3, t2, t1)
  408. QUARTER_ROUND_D(s0, t3, t2, t1, t0)
  409. rk += 8;
  410. } while (--r);
  411. #ifndef CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS
  412. // timing attack countermeasure. see comments at top for more details
  413. // If CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS is defined,
  414. // QUARTER_ROUND_LD will use Td, which is already preloaded.
  415. u = 0;
  416. for (i=0; i<256; i+=cacheLineSize)
  417. u &= *(const word32 *)(Sd+i);
  418. u &= *(const word32 *)(Sd+252);
  419. t0 |= u; t1 |= u; t2 |= u; t3 |= u;
  420. #endif
  421. word32 tbw[4];
  422. byte *const tempBlock = (byte *)tbw;
  423. QUARTER_ROUND_LD(t2, 7, 2, 13, 8)
  424. QUARTER_ROUND_LD(t1, 3, 14, 9, 4)
  425. QUARTER_ROUND_LD(t0, 15, 10, 5, 0)
  426. QUARTER_ROUND_LD(t3, 11, 6, 1, 12)
  427. Block::Put(xorBlock, outBlock)(tbw[0]^rk[0])(tbw[1]^rk[1])(tbw[2]^rk[2])(tbw[3]^rk[3]);
  428. }
  429. // ************************* Assembly Code ************************************
  430. #pragma warning(disable: 4731) // frame pointer register 'ebp' modified by inline assembly code
  431. #endif // #ifndef CRYPTOPP_GENERATE_X64_MASM
  432. #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
  433. CRYPTOPP_NAKED void CRYPTOPP_FASTCALL Rijndael_Enc_AdvancedProcessBlocks(void *locals, const word32 *k)
  434. {
  435. #if CRYPTOPP_BOOL_X86
  436. #define L_REG esp
  437. #define L_INDEX(i) (L_REG+512+i)
  438. #define L_INXORBLOCKS L_INBLOCKS+4
  439. #define L_OUTXORBLOCKS L_INBLOCKS+8
  440. #define L_OUTBLOCKS L_INBLOCKS+12
  441. #define L_INCREMENTS L_INDEX(16*15)
  442. #define L_SP L_INDEX(16*16)
  443. #define L_LENGTH L_INDEX(16*16+4)
  444. #define L_KEYS_BEGIN L_INDEX(16*16+8)
  445. #define MOVD movd
  446. #define MM(i) mm##i
  447. #define MXOR(a,b,c) \
  448. AS2( movzx esi, b)\
  449. AS2( movd mm7, DWORD PTR [AS_REG_7+8*WORD_REG(si)+MAP0TO4(c)])\
  450. AS2( pxor MM(a), mm7)\
  451. #define MMOV(a,b,c) \
  452. AS2( movzx esi, b)\
  453. AS2( movd MM(a), DWORD PTR [AS_REG_7+8*WORD_REG(si)+MAP0TO4(c)])\
  454. #else
  455. #define L_REG r8
  456. #define L_INDEX(i) (L_REG+i)
  457. #define L_INXORBLOCKS L_INBLOCKS+8
  458. #define L_OUTXORBLOCKS L_INBLOCKS+16
  459. #define L_OUTBLOCKS L_INBLOCKS+24
  460. #define L_INCREMENTS L_INDEX(16*16)
  461. #define L_LENGTH L_INDEX(16*18+8)
  462. #define L_KEYS_BEGIN L_INDEX(16*19)
  463. #define MOVD mov
  464. #define MM_0 r9d
  465. #define MM_1 r12d
  466. #ifdef __GNUC__
  467. #define MM_2 r11d
  468. #else
  469. #define MM_2 r10d
  470. #endif
  471. #define MM(i) MM_##i
  472. #define MXOR(a,b,c) \
  473. AS2( movzx esi, b)\
  474. AS2( xor MM(a), DWORD PTR [AS_REG_7+8*WORD_REG(si)+MAP0TO4(c)])\
  475. #define MMOV(a,b,c) \
  476. AS2( movzx esi, b)\
  477. AS2( mov MM(a), DWORD PTR [AS_REG_7+8*WORD_REG(si)+MAP0TO4(c)])\
  478. #endif
  479. #define L_SUBKEYS L_INDEX(0)
  480. #define L_SAVED_X L_SUBKEYS
  481. #define L_KEY12 L_INDEX(16*12)
  482. #define L_LASTROUND L_INDEX(16*13)
  483. #define L_INBLOCKS L_INDEX(16*14)
  484. #define MAP0TO4(i) (ASM_MOD(i+3,4)+1)
  485. #define XOR(a,b,c) \
  486. AS2( movzx esi, b)\
  487. AS2( xor a, DWORD PTR [AS_REG_7+8*WORD_REG(si)+MAP0TO4(c)])\
  488. #define MOV(a,b,c) \
  489. AS2( movzx esi, b)\
  490. AS2( mov a, DWORD PTR [AS_REG_7+8*WORD_REG(si)+MAP0TO4(c)])\
  491. #ifdef CRYPTOPP_GENERATE_X64_MASM
  492. ALIGN 8
  493. Rijndael_Enc_AdvancedProcessBlocks PROC FRAME
  494. rex_push_reg rsi
  495. push_reg rdi
  496. push_reg rbx
  497. push_reg r12
  498. .endprolog
  499. mov L_REG, rcx
  500. mov AS_REG_7, ?Te@rdtable@CryptoPP@@3PA_KA
  501. mov edi, DWORD PTR [?g_cacheLineSize@CryptoPP@@3IA]
  502. #elif defined(__GNUC__)
  503. __asm__ __volatile__
  504. (
  505. ".intel_syntax noprefix;"
  506. #if CRYPTOPP_BOOL_X64
  507. AS2( mov L_REG, rcx)
  508. #endif
  509. AS_PUSH_IF86(bx)
  510. AS_PUSH_IF86(bp)
  511. AS2( mov AS_REG_7, WORD_REG(si))
  512. #else
  513. AS_PUSH_IF86(si)
  514. AS_PUSH_IF86(di)
  515. AS_PUSH_IF86(bx)
  516. AS_PUSH_IF86(bp)
  517. AS2( lea AS_REG_7, [Te])
  518. AS2( mov edi, [g_cacheLineSize])
  519. #endif
  520. #if CRYPTOPP_BOOL_X86
  521. AS2( mov [ecx+16*12+16*4], esp) // save esp to L_SP
  522. AS2( lea esp, [ecx-512])
  523. #endif
  524. // copy subkeys to stack
  525. AS2( mov WORD_REG(si), [L_KEYS_BEGIN])
  526. AS2( mov WORD_REG(ax), 16)
  527. AS2( and WORD_REG(ax), WORD_REG(si))
  528. AS2( movdqa xmm3, XMMWORD_PTR [WORD_REG(dx)+16+WORD_REG(ax)]) // subkey 1 (non-counter) or 2 (counter)
  529. AS2( movdqa [L_KEY12], xmm3)
  530. AS2( lea WORD_REG(ax), [WORD_REG(dx)+WORD_REG(ax)+2*16])
  531. AS2( sub WORD_REG(ax), WORD_REG(si))
  532. ASL(0)
  533. AS2( movdqa xmm0, [WORD_REG(ax)+WORD_REG(si)])
  534. AS2( movdqa XMMWORD_PTR [L_SUBKEYS+WORD_REG(si)], xmm0)
  535. AS2( add WORD_REG(si), 16)
  536. AS2( cmp WORD_REG(si), 16*12)
  537. ASJ( jl, 0, b)
  538. // read subkeys 0, 1 and last
  539. AS2( movdqa xmm4, [WORD_REG(ax)+WORD_REG(si)]) // last subkey
  540. AS2( movdqa xmm1, [WORD_REG(dx)]) // subkey 0
  541. AS2( MOVD MM(1), [WORD_REG(dx)+4*4]) // 0,1,2,3
  542. AS2( mov ebx, [WORD_REG(dx)+5*4]) // 4,5,6,7
  543. AS2( mov ecx, [WORD_REG(dx)+6*4]) // 8,9,10,11
  544. AS2( mov edx, [WORD_REG(dx)+7*4]) // 12,13,14,15
  545. // load table into cache
  546. AS2( xor WORD_REG(ax), WORD_REG(ax))
  547. ASL(9)
  548. AS2( mov esi, [AS_REG_7+WORD_REG(ax)])
  549. AS2( add WORD_REG(ax), WORD_REG(di))
  550. AS2( mov esi, [AS_REG_7+WORD_REG(ax)])
  551. AS2( add WORD_REG(ax), WORD_REG(di))
  552. AS2( mov esi, [AS_REG_7+WORD_REG(ax)])
  553. AS2( add WORD_REG(ax), WORD_REG(di))
  554. AS2( mov esi, [AS_REG_7+WORD_REG(ax)])
  555. AS2( add WORD_REG(ax), WORD_REG(di))
  556. AS2( cmp WORD_REG(ax), 2048)
  557. ASJ( jl, 9, b)
  558. AS1( lfence)
  559. AS2( test DWORD PTR [L_LENGTH], 1)
  560. ASJ( jz, 8, f)
  561. // counter mode one-time setup
  562. AS2( mov WORD_REG(si), [L_INBLOCKS])
  563. AS2( movdqu xmm2, [WORD_REG(si)]) // counter
  564. AS2( pxor xmm2, xmm1)
  565. AS2( psrldq xmm1, 14)
  566. AS2( movd eax, xmm1)
  567. AS2( mov al, BYTE PTR [WORD_REG(si)+15])
  568. AS2( MOVD MM(2), eax)
  569. #if CRYPTOPP_BOOL_X86
  570. AS2( mov eax, 1)
  571. AS2( movd mm3, eax)
  572. #endif
  573. // partial first round, in: xmm2(15,14,13,12;11,10,9,8;7,6,5,4;3,2,1,0), out: mm1, ebx, ecx, edx
  574. AS2( movd eax, xmm2)
  575. AS2( psrldq xmm2, 4)
  576. AS2( movd edi, xmm2)
  577. AS2( psrldq xmm2, 4)
  578. MXOR( 1, al, 0) // 0
  579. XOR( edx, ah, 1) // 1
  580. AS2( shr eax, 16)
  581. XOR( ecx, al, 2) // 2
  582. XOR( ebx, ah, 3) // 3
  583. AS2( mov eax, edi)
  584. AS2( movd edi, xmm2)
  585. AS2( psrldq xmm2, 4)
  586. XOR( ebx, al, 0) // 4
  587. MXOR( 1, ah, 1) // 5
  588. AS2( shr eax, 16)
  589. XOR( edx, al, 2) // 6
  590. XOR( ecx, ah, 3) // 7
  591. AS2( mov eax, edi)
  592. AS2( movd edi, xmm2)
  593. XOR( ecx, al, 0) // 8
  594. XOR( ebx, ah, 1) // 9
  595. AS2( shr eax, 16)
  596. MXOR( 1, al, 2) // 10
  597. XOR( edx, ah, 3) // 11
  598. AS2( mov eax, edi)
  599. XOR( edx, al, 0) // 12
  600. XOR( ecx, ah, 1) // 13
  601. AS2( shr eax, 16)
  602. XOR( ebx, al, 2) // 14
  603. AS2( psrldq xmm2, 3)
  604. // partial second round, in: ebx(4,5,6,7), ecx(8,9,10,11), edx(12,13,14,15), out: eax, ebx, edi, mm0
  605. AS2( mov eax, [L_KEY12+0*4])
  606. AS2( mov edi, [L_KEY12+2*4])
  607. AS2( MOVD MM(0), [L_KEY12+3*4])
  608. MXOR( 0, cl, 3) /* 11 */
  609. XOR( edi, bl, 3) /* 7 */
  610. MXOR( 0, bh, 2) /* 6 */
  611. AS2( shr ebx, 16) /* 4,5 */
  612. XOR( eax, bl, 1) /* 5 */
  613. MOV( ebx, bh, 0) /* 4 */
  614. AS2( xor ebx, [L_KEY12+1*4])
  615. XOR( eax, ch, 2) /* 10 */
  616. AS2( shr ecx, 16) /* 8,9 */
  617. XOR( eax, dl, 3) /* 15 */
  618. XOR( ebx, dh, 2) /* 14 */
  619. AS2( shr edx, 16) /* 12,13 */
  620. XOR( edi, ch, 0) /* 8 */
  621. XOR( ebx, cl, 1) /* 9 */
  622. XOR( edi, dl, 1) /* 13 */
  623. MXOR( 0, dh, 0) /* 12 */
  624. AS2( movd ecx, xmm2)
  625. AS2( MOVD edx, MM(1))
  626. AS2( MOVD [L_SAVED_X+3*4], MM(0))
  627. AS2( mov [L_SAVED_X+0*4], eax)
  628. AS2( mov [L_SAVED_X+1*4], ebx)
  629. AS2( mov [L_SAVED_X+2*4], edi)
  630. ASJ( jmp, 5, f)
  631. ASL(3)
  632. // non-counter mode per-block setup
  633. AS2( MOVD MM(1), [L_KEY12+0*4]) // 0,1,2,3
  634. AS2( mov ebx, [L_KEY12+1*4]) // 4,5,6,7
  635. AS2( mov ecx, [L_KEY12+2*4]) // 8,9,10,11
  636. AS2( mov edx, [L_KEY12+3*4]) // 12,13,14,15
  637. ASL(8)
  638. AS2( mov WORD_REG(ax), [L_INBLOCKS])
  639. AS2( movdqu xmm2, [WORD_REG(ax)])
  640. AS2( mov WORD_REG(si), [L_INXORBLOCKS])
  641. AS2( movdqu xmm5, [WORD_REG(si)])
  642. AS2( pxor xmm2, xmm1)
  643. AS2( pxor xmm2, xmm5)
  644. // first round, in: xmm2(15,14,13,12;11,10,9,8;7,6,5,4;3,2,1,0), out: eax, ebx, ecx, edx
  645. AS2( movd eax, xmm2)
  646. AS2( psrldq xmm2, 4)
  647. AS2( movd edi, xmm2)
  648. AS2( psrldq xmm2, 4)
  649. MXOR( 1, al, 0) // 0
  650. XOR( edx, ah, 1) // 1
  651. AS2( shr eax, 16)
  652. XOR( ecx, al, 2) // 2
  653. XOR( ebx, ah, 3) // 3
  654. AS2( mov eax, edi)
  655. AS2( movd edi, xmm2)
  656. AS2( psrldq xmm2, 4)
  657. XOR( ebx, al, 0) // 4
  658. MXOR( 1, ah, 1) // 5
  659. AS2( shr eax, 16)
  660. XOR( edx, al, 2) // 6
  661. XOR( ecx, ah, 3) // 7
  662. AS2( mov eax, edi)
  663. AS2( movd edi, xmm2)
  664. XOR( ecx, al, 0) // 8
  665. XOR( ebx, ah, 1) // 9
  666. AS2( shr eax, 16)
  667. MXOR( 1, al, 2) // 10
  668. XOR( edx, ah, 3) // 11
  669. AS2( mov eax, edi)
  670. XOR( edx, al, 0) // 12
  671. XOR( ecx, ah, 1) // 13
  672. AS2( shr eax, 16)
  673. XOR( ebx, al, 2) // 14
  674. MXOR( 1, ah, 3) // 15
  675. AS2( MOVD eax, MM(1))
  676. AS2( add L_REG, [L_KEYS_BEGIN])
  677. AS2( add L_REG, 4*16)
  678. ASJ( jmp, 2, f)
  679. ASL(1)
  680. // counter-mode per-block setup
  681. AS2( MOVD ecx, MM(2))
  682. AS2( MOVD edx, MM(1))
  683. AS2( mov eax, [L_SAVED_X+0*4])
  684. AS2( mov ebx, [L_SAVED_X+1*4])
  685. AS2( xor cl, ch)
  686. AS2( and WORD_REG(cx), 255)
  687. ASL(5)
  688. #if CRYPTOPP_BOOL_X86
  689. AS2( paddb MM(2), mm3)
  690. #else
  691. AS2( add MM(2), 1)
  692. #endif
  693. // remaining part of second round, in: edx(previous round),esi(keyed counter byte) eax,ebx,[L_SAVED_X+2*4],[L_SAVED_X+3*4], out: eax,ebx,ecx,edx
  694. AS2( xor edx, DWORD PTR [AS_REG_7+WORD_REG(cx)*8+3])
  695. XOR( ebx, dl, 3)
  696. MOV( ecx, dh, 2)
  697. AS2( shr edx, 16)
  698. AS2( xor ecx, [L_SAVED_X+2*4])
  699. XOR( eax, dh, 0)
  700. MOV( edx, dl, 1)
  701. AS2( xor edx, [L_SAVED_X+3*4])
  702. AS2( add L_REG, [L_KEYS_BEGIN])
  703. AS2( add L_REG, 3*16)
  704. ASJ( jmp, 4, f)
  705. // in: eax(0,1,2,3), ebx(4,5,6,7), ecx(8,9,10,11), edx(12,13,14,15)
  706. // out: eax, ebx, edi, mm0
  707. #define ROUND() \
  708. MXOR( 0, cl, 3) /* 11 */\
  709. AS2( mov cl, al) /* 8,9,10,3 */\
  710. XOR( edi, ah, 2) /* 2 */\
  711. AS2( shr eax, 16) /* 0,1 */\
  712. XOR( edi, bl, 3) /* 7 */\
  713. MXOR( 0, bh, 2) /* 6 */\
  714. AS2( shr ebx, 16) /* 4,5 */\
  715. MXOR( 0, al, 1) /* 1 */\
  716. MOV( eax, ah, 0) /* 0 */\
  717. XOR( eax, bl, 1) /* 5 */\
  718. MOV( ebx, bh, 0) /* 4 */\
  719. XOR( eax, ch, 2) /* 10 */\
  720. XOR( ebx, cl, 3) /* 3 */\
  721. AS2( shr ecx, 16) /* 8,9 */\
  722. XOR( eax, dl, 3) /* 15 */\
  723. XOR( ebx, dh, 2) /* 14 */\
  724. AS2( shr edx, 16) /* 12,13 */\
  725. XOR( edi, ch, 0) /* 8 */\
  726. XOR( ebx, cl, 1) /* 9 */\
  727. XOR( edi, dl, 1) /* 13 */\
  728. MXOR( 0, dh, 0) /* 12 */\
  729. ASL(2) // 2-round loop
  730. AS2( MOVD MM(0), [L_SUBKEYS-4*16+3*4])
  731. AS2( mov edi, [L_SUBKEYS-4*16+2*4])
  732. ROUND()
  733. AS2( mov ecx, edi)
  734. AS2( xor eax, [L_SUBKEYS-4*16+0*4])
  735. AS2( xor ebx, [L_SUBKEYS-4*16+1*4])
  736. AS2( MOVD edx, MM(0))
  737. ASL(4)
  738. AS2( MOVD MM(0), [L_SUBKEYS-4*16+7*4])
  739. AS2( mov edi, [L_SUBKEYS-4*16+6*4])
  740. ROUND()
  741. AS2( mov ecx, edi)
  742. AS2( xor eax, [L_SUBKEYS-4*16+4*4])
  743. AS2( xor ebx, [L_SUBKEYS-4*16+5*4])
  744. AS2( MOVD edx, MM(0))
  745. AS2( add L_REG, 32)
  746. AS2( test L_REG, 255)
  747. ASJ( jnz, 2, b)
  748. AS2( sub L_REG, 16*16)
  749. #define LAST(a, b, c) \
  750. AS2( movzx esi, a )\
  751. AS2( movzx edi, BYTE PTR [AS_REG_7+WORD_REG(si)*8+1] )\
  752. AS2( movzx esi, b )\
  753. AS2( xor edi, DWORD PTR [AS_REG_7+WORD_REG(si)*8+0] )\
  754. AS2( mov WORD PTR [L_LASTROUND+c], di )\
  755. // last round
  756. LAST(ch, dl, 2)
  757. LAST(dh, al, 6)
  758. AS2( shr edx, 16)
  759. LAST(ah, bl, 10)
  760. AS2( shr eax, 16)
  761. LAST(bh, cl, 14)
  762. AS2( shr ebx, 16)
  763. LAST(dh, al, 12)
  764. AS2( shr ecx, 16)
  765. LAST(ah, bl, 0)
  766. LAST(bh, cl, 4)
  767. LAST(ch, dl, 8)
  768. AS2( mov WORD_REG(ax), [L_OUTXORBLOCKS])
  769. AS2( mov WORD_REG(bx), [L_OUTBLOCKS])
  770. AS2( mov WORD_REG(cx), [L_LENGTH])
  771. AS2( sub WORD_REG(cx), 16)
  772. AS2( movdqu xmm2, [WORD_REG(ax)])
  773. AS2( pxor xmm2, xmm4)
  774. #if CRYPTOPP_BOOL_X86
  775. AS2( movdqa xmm0, [L_INCREMENTS])
  776. AS2( paddd xmm0, [L_INBLOCKS])
  777. AS2( movdqa [L_INBLOCKS], xmm0)
  778. #else
  779. AS2( movdqa xmm0, [L_INCREMENTS+16])
  780. AS2( paddq xmm0, [L_INBLOCKS+16])
  781. AS2( movdqa [L_INBLOCKS+16], xmm0)
  782. #endif
  783. AS2( pxor xmm2, [L_LASTROUND])
  784. AS2( movdqu [WORD_REG(bx)], xmm2)
  785. ASJ( jle, 7, f)
  786. AS2( mov [L_LENGTH], WORD_REG(cx))
  787. AS2( test WORD_REG(cx), 1)
  788. ASJ( jnz, 1, b)
  789. #if CRYPTOPP_BOOL_X64
  790. AS2( movdqa xmm0, [L_INCREMENTS])
  791. AS2( paddq xmm0, [L_INBLOCKS])
  792. AS2( movdqa [L_INBLOCKS], xmm0)
  793. #endif
  794. ASJ( jmp, 3, b)
  795. ASL(7)
  796. // erase keys on stack
  797. AS2( xorps xmm0, xmm0)
  798. AS2( lea WORD_REG(ax), [L_SUBKEYS+7*16])
  799. AS2( movaps [WORD_REG(ax)-7*16], xmm0)
  800. AS2( movaps [WORD_REG(ax)-6*16], xmm0)
  801. AS2( movaps [WORD_REG(ax)-5*16], xmm0)
  802. AS2( movaps [WORD_REG(ax)-4*16], xmm0)
  803. AS2( movaps [WORD_REG(ax)-3*16], xmm0)
  804. AS2( movaps [WORD_REG(ax)-2*16], xmm0)
  805. AS2( movaps [WORD_REG(ax)-1*16], xmm0)
  806. AS2( movaps [WORD_REG(ax)+0*16], xmm0)
  807. AS2( movaps [WORD_REG(ax)+1*16], xmm0)
  808. AS2( movaps [WORD_REG(ax)+2*16], xmm0)
  809. AS2( movaps [WORD_REG(ax)+3*16], xmm0)
  810. AS2( movaps [WORD_REG(ax)+4*16], xmm0)
  811. AS2( movaps [WORD_REG(ax)+5*16], xmm0)
  812. AS2( movaps [WORD_REG(ax)+6*16], xmm0)
  813. #if CRYPTOPP_BOOL_X86
  814. AS2( mov esp, [L_SP])
  815. AS1( emms)
  816. #endif
  817. AS_POP_IF86(bp)
  818. AS_POP_IF86(bx)
  819. #if defined(_MSC_VER) && CRYPTOPP_BOOL_X86
  820. AS_POP_IF86(di)
  821. AS_POP_IF86(si)
  822. AS1(ret)
  823. #endif
  824. #ifdef CRYPTOPP_GENERATE_X64_MASM
  825. pop r12
  826. pop rbx
  827. pop rdi
  828. pop rsi
  829. ret
  830. Rijndael_Enc_AdvancedProcessBlocks ENDP
  831. #endif
  832. #ifdef __GNUC__
  833. ".att_syntax prefix;"
  834. :
  835. : "c" (locals), "d" (k), "S" (Te), "D" (g_cacheLineSize)
  836. : "memory", "cc", "%eax"
  837. #if CRYPTOPP_BOOL_X64
  838. , "%rbx", "%r8", "%r9", "%r10", "%r11", "%r12"
  839. #endif
  840. );
  841. #endif
  842. }
  843. #endif
  844. #ifndef CRYPTOPP_GENERATE_X64_MASM
  845. #ifdef CRYPTOPP_X64_MASM_AVAILABLE
  846. extern "C" {
  847. void Rijndael_Enc_AdvancedProcessBlocks(void *locals, const word32 *k);
  848. }
  849. #endif
  850. #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X86
  851. static inline bool AliasedWithTable(const byte *begin, const byte *end)
  852. {
  853. size_t s0 = size_t(begin)%4096, s1 = size_t(end)%4096;
  854. size_t t0 = size_t(Te)%4096, t1 = (size_t(Te)+sizeof(Te))%4096;
  855. if (t1 > t0)
  856. return (s0 >= t0 && s0 < t1) || (s1 > t0 && s1 <= t1);
  857. else
  858. return (s0 < t1 || s1 <= t1) || (s0 >= t0 || s1 > t0);
  859. }
  860. #if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
  861. inline void AESNI_Enc_Block(__m128i &block, const __m128i *subkeys, unsigned int rounds)
  862. {
  863. block = _mm_xor_si128(block, subkeys[0]);
  864. for (unsigned int i=1; i<rounds-1; i+=2)
  865. {
  866. block = _mm_aesenc_si128(block, subkeys[i]);
  867. block = _mm_aesenc_si128(block, subkeys[i+1]);
  868. }
  869. block = _mm_aesenc_si128(block, subkeys[rounds-1]);
  870. block = _mm_aesenclast_si128(block, subkeys[rounds]);
  871. }
  872. inline void AESNI_Enc_4_Blocks(__m128i &block0, __m128i &block1, __m128i &block2, __m128i &block3, const __m128i *subkeys, unsigned int rounds)
  873. {
  874. __m128i rk = subkeys[0];
  875. block0 = _mm_xor_si128(block0, rk);
  876. block1 = _mm_xor_si128(block1, rk);
  877. block2 = _mm_xor_si128(block2, rk);
  878. block3 = _mm_xor_si128(block3, rk);
  879. for (unsigned int i=1; i<rounds; i++)
  880. {
  881. rk = subkeys[i];
  882. block0 = _mm_aesenc_si128(block0, rk);
  883. block1 = _mm_aesenc_si128(block1, rk);
  884. block2 = _mm_aesenc_si128(block2, rk);
  885. block3 = _mm_aesenc_si128(block3, rk);
  886. }
  887. rk = subkeys[rounds];
  888. block0 = _mm_aesenclast_si128(block0, rk);
  889. block1 = _mm_aesenclast_si128(block1, rk);
  890. block2 = _mm_aesenclast_si128(block2, rk);
  891. block3 = _mm_aesenclast_si128(block3, rk);
  892. }
  893. inline void AESNI_Dec_Block(__m128i &block, const __m128i *subkeys, unsigned int rounds)
  894. {
  895. block = _mm_xor_si128(block, subkeys[0]);
  896. for (unsigned int i=1; i<rounds-1; i+=2)
  897. {
  898. block = _mm_aesdec_si128(block, subkeys[i]);
  899. block = _mm_aesdec_si128(block, subkeys[i+1]);
  900. }
  901. block = _mm_aesdec_si128(block, subkeys[rounds-1]);
  902. block = _mm_aesdeclast_si128(block, subkeys[rounds]);
  903. }
  904. inline void AESNI_Dec_4_Blocks(__m128i &block0, __m128i &block1, __m128i &block2, __m128i &block3, const __m128i *subkeys, unsigned int rounds)
  905. {
  906. __m128i rk = subkeys[0];
  907. block0 = _mm_xor_si128(block0, rk);
  908. block1 = _mm_xor_si128(block1, rk);
  909. block2 = _mm_xor_si128(block2, rk);
  910. block3 = _mm_xor_si128(block3, rk);
  911. for (unsigned int i=1; i<rounds; i++)
  912. {
  913. rk = subkeys[i];
  914. block0 = _mm_aesdec_si128(block0, rk);
  915. block1 = _mm_aesdec_si128(block1, rk);
  916. block2 = _mm_aesdec_si128(block2, rk);
  917. block3 = _mm_aesdec_si128(block3, rk);
  918. }
  919. rk = subkeys[rounds];
  920. block0 = _mm_aesdeclast_si128(block0, rk);
  921. block1 = _mm_aesdeclast_si128(block1, rk);
  922. block2 = _mm_aesdeclast_si128(block2, rk);
  923. block3 = _mm_aesdeclast_si128(block3, rk);
  924. }
  925. static CRYPTOPP_ALIGN_DATA(16) const word32 s_one[] = {0, 0, 0, 1<<24};
  926. template <typename F1, typename F4>
  927. inline size_t AESNI_AdvancedProcessBlocks(F1 func1, F4 func4, const __m128i *subkeys, unsigned int rounds, const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags)
  928. {
  929. size_t blockSize = 16;
  930. size_t inIncrement = (flags & (BlockTransformation::BT_InBlockIsCounter|BlockTransformation::BT_DontIncrementInOutPointers)) ? 0 : blockSize;
  931. size_t xorIncrement = xorBlocks ? blockSize : 0;
  932. size_t outIncrement = (flags & BlockTransformation::BT_DontIncrementInOutPointers) ? 0 : blockSize;
  933. if (flags & BlockTransformation::BT_ReverseDirection)
  934. {
  935. assert(length % blockSize == 0);
  936. inBlocks += length - blockSize;
  937. xorBlocks += length - blockSize;
  938. outBlocks += length - blockSize;
  939. inIncrement = 0-inIncrement;
  940. xorIncrement = 0-xorIncrement;
  941. outIncrement = 0-outIncrement;
  942. }
  943. if (flags & BlockTransformation::BT_AllowParallel)
  944. {
  945. while (length >= 4*blockSize)
  946. {
  947. __m128i block0 = _mm_loadu_si128((const __m128i *)inBlocks), block1, block2, block3;
  948. if (flags & BlockTransformation::BT_InBlockIsCounter)
  949. {
  950. const __m128i be1 = *(const __m128i *)s_one;
  951. block1 = _mm_add_epi32(block0, be1);
  952. block2 = _mm_add_epi32(block1, be1);
  953. block3 = _mm_add_epi32(block2, be1);
  954. _mm_storeu_si128((__m128i *)inBlocks, _mm_add_epi32(block3, be1));
  955. }
  956. else
  957. {
  958. inBlocks += inIncrement;
  959. block1 = _mm_loadu_si128((const __m128i *)inBlocks);
  960. inBlocks += inIncrement;
  961. block2 = _mm_loadu_si128((const __m128i *)inBlocks);
  962. inBlocks += inIncrement;
  963. block3 = _mm_loadu_si128((const __m128i *)inBlocks);
  964. inBlocks += inIncrement;
  965. }
  966. if (flags & BlockTransformation::BT_XorInput)
  967. {
  968. block0 = _mm_xor_si128(block0, _mm_loadu_si128((const __m128i *)xorBlocks));
  969. xorBlocks += xorIncrement;
  970. block1 = _mm_xor_si128(block1, _mm_loadu_si128((const __m128i *)xorBlocks));
  971. xorBlocks += xorIncrement;
  972. block2 = _mm_xor_si128(block2, _mm_loadu_si128((const __m128i *)xorBlocks));
  973. xorBlocks += xorIncrement;
  974. block3 = _mm_xor_si128(block3, _mm_loadu_si128((const __m128i *)xorBlocks));
  975. xorBlocks += xorIncrement;
  976. }
  977. func4(block0, block1, block2, block3, subkeys, rounds);
  978. if (xorBlocks && !(flags & BlockTransformation::BT_XorInput))
  979. {
  980. block0 = _mm_xor_si128(block0, _mm_loadu_si128((const __m128i *)xorBlocks));
  981. xorBlocks += xorIncrement;
  982. block1 = _mm_xor_si128(block1, _mm_loadu_si128((const __m128i *)xorBlocks));
  983. xorBlocks += xorIncrement;
  984. block2 = _mm_xor_si128(block2, _mm_loadu_si128((const __m128i *)xorBlocks));
  985. xorBlocks += xorIncrement;
  986. block3 = _mm_xor_si128(block3, _mm_loadu_si128((const __m128i *)xorBlocks));
  987. xorBlocks += xorIncrement;
  988. }
  989. _mm_storeu_si128((__m128i *)outBlocks, block0);
  990. outBlocks += outIncrement;
  991. _mm_storeu_si128((__m128i *)outBlocks, block1);
  992. outBlocks += outIncrement;
  993. _mm_storeu_si128((__m128i *)outBlocks, block2);
  994. outBlocks += outIncrement;
  995. _mm_storeu_si128((__m128i *)outBlocks, block3);
  996. outBlocks += outIncrement;
  997. length -= 4*blockSize;
  998. }
  999. }
  1000. while (length >= blockSize)
  1001. {
  1002. __m128i block = _mm_loadu_si128((const __m128i *)inBlocks);
  1003. if (flags & BlockTransformation::BT_XorInput)
  1004. block = _mm_xor_si128(block, _mm_loadu_si128((const __m128i *)xorBlocks));
  1005. if (flags & BlockTransformation::BT_InBlockIsCounter)
  1006. const_cast<byte *>(inBlocks)[15]++;
  1007. func1(block, subkeys, rounds);
  1008. if (xorBlocks && !(flags & BlockTransformation::BT_XorInput))
  1009. block = _mm_xor_si128(block, _mm_loadu_si128((const __m128i *)xorBlocks));
  1010. _mm_storeu_si128((__m128i *)outBlocks, block);
  1011. inBlocks += inIncrement;
  1012. outBlocks += outIncrement;
  1013. xorBlocks += xorIncrement;
  1014. length -= blockSize;
  1015. }
  1016. return length;
  1017. }
  1018. #endif
  1019. size_t Rijndael::Enc::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const
  1020. {
  1021. #if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
  1022. if (HasAESNI())
  1023. return AESNI_AdvancedProcessBlocks(AESNI_Enc_Block, AESNI_Enc_4_Blocks, (const __m128i *)m_key.begin(), m_rounds, inBlocks, xorBlocks, outBlocks, length, flags);
  1024. #endif
  1025. #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE || defined(CRYPTOPP_X64_MASM_AVAILABLE)
  1026. if (HasSSE2())
  1027. {
  1028. if (length < BLOCKSIZE)
  1029. return length;
  1030. struct Locals
  1031. {
  1032. word32 subkeys[4*12], workspace[8];
  1033. const byte *inBlocks, *inXorBlocks, *outXorBlocks;
  1034. byte *outBlocks;
  1035. size_t inIncrement, inXorIncrement, outXorIncrement, outIncrement;
  1036. size_t regSpill, lengthAndCounterFlag, keysBegin;
  1037. };
  1038. size_t increment = BLOCKSIZE;
  1039. const byte* zeros = (byte *)(Te+256);
  1040. byte *space;
  1041. do {
  1042. space = (byte *)alloca(255+sizeof(Locals));
  1043. space += (256-(size_t)space%256)%256;
  1044. }
  1045. while (AliasedWithTable(space, space+sizeof(Locals)));
  1046. if (flags & BT_ReverseDirection)
  1047. {
  1048. assert(length % BLOCKSIZE == 0);
  1049. inBlocks += length - BLOCKSIZE;
  1050. xorBlocks += length - BLOCKSIZE;
  1051. outBlocks += length - BLOCKSIZE;
  1052. increment = 0-increment;
  1053. }
  1054. Locals &locals = *(Locals *)space;
  1055. locals.inBlocks = inBlocks;
  1056. locals.inXorBlocks = (flags & BT_XorInput) && xorBlocks ? xorBlocks : zeros;
  1057. locals.outXorBlocks = (flags & BT_XorInput) || !xorBlocks ? zeros : xorBlocks;
  1058. locals.outBlocks = outBlocks;
  1059. locals.inIncrement = (flags & BT_DontIncrementInOutPointers) ? 0 : increment;
  1060. locals.inXorIncrement = (flags & BT_XorInput) && xorBlocks ? increment : 0;
  1061. locals.outXorIncrement = (flags & BT_XorInput) || !xorBlocks ? 0 : increment;
  1062. locals.outIncrement = (flags & BT_DontIncrementInOutPointers) ? 0 : increment;
  1063. locals.lengthAndCounterFlag = length - (length%16) - bool(flags & BT_InBlockIsCounter);
  1064. int keysToCopy = m_rounds - (flags & BT_InBlockIsCounter ? 3 : 2);
  1065. locals.keysBegin = (12-keysToCopy)*16;
  1066. Rijndael_Enc_AdvancedProcessBlocks(&locals, m_key);
  1067. return length % BLOCKSIZE;
  1068. }
  1069. #endif
  1070. return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags);
  1071. }
  1072. #endif
  1073. #if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
  1074. size_t Rijndael::Dec::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const
  1075. {
  1076. if (HasAESNI())
  1077. return AESNI_AdvancedProcessBlocks(AESNI_Dec_Block, AESNI_Dec_4_Blocks, (const __m128i *)m_key.begin(), m_rounds, inBlocks, xorBlocks, outBlocks, length, flags);
  1078. return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags);
  1079. }
  1080. #endif // #if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
  1081. NAMESPACE_END
  1082. #endif
  1083. #endif