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.

828 lines
23 KiB

  1. // gcm.cpp - written and placed in the public domain by Wei Dai
  2. // use "cl /EP /P /DCRYPTOPP_GENERATE_X64_MASM gcm.cpp" to generate MASM code
  3. #include "pch.h"
  4. #ifndef CRYPTOPP_IMPORTS
  5. #ifndef CRYPTOPP_GENERATE_X64_MASM
  6. #include "gcm.h"
  7. #include "cpu.h"
  8. NAMESPACE_BEGIN(CryptoPP)
  9. word16 GCM_Base::s_reductionTable[256];
  10. volatile bool GCM_Base::s_reductionTableInitialized = false;
  11. void GCM_Base::GCTR::IncrementCounterBy256()
  12. {
  13. IncrementCounterByOne(m_counterArray+BlockSize()-4, 3);
  14. }
  15. #if 0
  16. // preserved for testing
  17. void gcm_gf_mult(const unsigned char *a, const unsigned char *b, unsigned char *c)
  18. {
  19. word64 Z0=0, Z1=0, V0, V1;
  20. typedef BlockGetAndPut<word64, BigEndian> Block;
  21. Block::Get(a)(V0)(V1);
  22. for (int i=0; i<16; i++)
  23. {
  24. for (int j=0x80; j!=0; j>>=1)
  25. {
  26. int x = b[i] & j;
  27. Z0 ^= x ? V0 : 0;
  28. Z1 ^= x ? V1 : 0;
  29. x = (int)V1 & 1;
  30. V1 = (V1>>1) | (V0<<63);
  31. V0 = (V0>>1) ^ (x ? W64LIT(0xe1) << 56 : 0);
  32. }
  33. }
  34. Block::Put(NULL, c)(Z0)(Z1);
  35. }
  36. __m128i _mm_clmulepi64_si128(const __m128i &a, const __m128i &b, int i)
  37. {
  38. word64 A[1] = {ByteReverse(((word64*)&a)[i&1])};
  39. word64 B[1] = {ByteReverse(((word64*)&b)[i>>4])};
  40. PolynomialMod2 pa((byte *)A, 8);
  41. PolynomialMod2 pb((byte *)B, 8);
  42. PolynomialMod2 c = pa*pb;
  43. __m128i output;
  44. for (int i=0; i<16; i++)
  45. ((byte *)&output)[i] = c.GetByte(i);
  46. return output;
  47. }
  48. #endif
  49. #if CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE || CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
  50. inline static void SSE2_Xor16(byte *a, const byte *b, const byte *c)
  51. {
  52. #if CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
  53. *(__m128i *)a = _mm_xor_si128(*(__m128i *)b, *(__m128i *)c);
  54. #else
  55. asm ("movdqa %1, %%xmm0; pxor %2, %%xmm0; movdqa %%xmm0, %0;" : "=m" (a[0]) : "m"(b[0]), "m"(c[0]));
  56. #endif
  57. }
  58. #endif
  59. inline static void Xor16(byte *a, const byte *b, const byte *c)
  60. {
  61. ((word64 *)a)[0] = ((word64 *)b)[0] ^ ((word64 *)c)[0];
  62. ((word64 *)a)[1] = ((word64 *)b)[1] ^ ((word64 *)c)[1];
  63. }
  64. #if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
  65. static CRYPTOPP_ALIGN_DATA(16) const word64 s_clmulConstants64[] = {
  66. W64LIT(0xe100000000000000), W64LIT(0xc200000000000000),
  67. W64LIT(0x08090a0b0c0d0e0f), W64LIT(0x0001020304050607),
  68. W64LIT(0x0001020304050607), W64LIT(0x08090a0b0c0d0e0f)};
  69. static const __m128i *s_clmulConstants = (const __m128i *)s_clmulConstants64;
  70. static const unsigned int s_clmulTableSizeInBlocks = 8;
  71. inline __m128i CLMUL_Reduce(__m128i c0, __m128i c1, __m128i c2, const __m128i &r)
  72. {
  73. /*
  74. The polynomial to be reduced is c0 * x^128 + c1 * x^64 + c2. c0t below refers to the most
  75. significant half of c0 as a polynomial, which, due to GCM's bit reflection, are in the
  76. rightmost bit positions, and the lowest byte addresses.
  77. c1 ^= c0t * 0xc200000000000000
  78. c2t ^= c0t
  79. t = shift (c1t ^ c0b) left 1 bit
  80. c2 ^= t * 0xe100000000000000
  81. c2t ^= c1b
  82. shift c2 left 1 bit and xor in lowest bit of c1t
  83. */
  84. #if 0 // MSVC 2010 workaround: see http://connect.microsoft.com/VisualStudio/feedback/details/575301
  85. c2 = _mm_xor_si128(c2, _mm_move_epi64(c0));
  86. #else
  87. c1 = _mm_xor_si128(c1, _mm_slli_si128(c0, 8));
  88. #endif
  89. c1 = _mm_xor_si128(c1, _mm_clmulepi64_si128(c0, r, 0x10));
  90. c0 = _mm_srli_si128(c0, 8);
  91. c0 = _mm_xor_si128(c0, c1);
  92. c0 = _mm_slli_epi64(c0, 1);
  93. c0 = _mm_clmulepi64_si128(c0, r, 0);
  94. c2 = _mm_xor_si128(c2, c0);
  95. c2 = _mm_xor_si128(c2, _mm_srli_si128(c1, 8));
  96. c1 = _mm_unpacklo_epi64(c1, c2);
  97. c1 = _mm_srli_epi64(c1, 63);
  98. c2 = _mm_slli_epi64(c2, 1);
  99. return _mm_xor_si128(c2, c1);
  100. }
  101. inline __m128i CLMUL_GF_Mul(const __m128i &x, const __m128i &h, const __m128i &r)
  102. {
  103. __m128i c0 = _mm_clmulepi64_si128(x,h,0);
  104. __m128i c1 = _mm_xor_si128(_mm_clmulepi64_si128(x,h,1), _mm_clmulepi64_si128(x,h,0x10));
  105. __m128i c2 = _mm_clmulepi64_si128(x,h,0x11);
  106. return CLMUL_Reduce(c0, c1, c2, r);
  107. }
  108. #endif
  109. void GCM_Base::SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs &params)
  110. {
  111. BlockCipher &blockCipher = AccessBlockCipher();
  112. blockCipher.SetKey(userKey, keylength, params);
  113. if (blockCipher.BlockSize() != REQUIRED_BLOCKSIZE)
  114. throw InvalidArgument(AlgorithmName() + ": block size of underlying block cipher is not 16");
  115. int tableSize, i, j, k;
  116. #if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
  117. if (HasCLMUL())
  118. {
  119. params.GetIntValue(Name::TableSize(), tableSize); // avoid "parameter not used" error
  120. tableSize = s_clmulTableSizeInBlocks * REQUIRED_BLOCKSIZE;
  121. }
  122. else
  123. #endif
  124. {
  125. if (params.GetIntValue(Name::TableSize(), tableSize))
  126. tableSize = (tableSize >= 64*1024) ? 64*1024 : 2*1024;
  127. else
  128. tableSize = (GetTablesOption() == GCM_64K_Tables) ? 64*1024 : 2*1024;
  129. #if defined(_MSC_VER) && (_MSC_VER >= 1300 && _MSC_VER < 1400)
  130. // VC 2003 workaround: compiler generates bad code for 64K tables
  131. tableSize = 2*1024;
  132. #endif
  133. }
  134. m_buffer.resize(3*REQUIRED_BLOCKSIZE + tableSize);
  135. byte *table = MulTable();
  136. byte *hashKey = HashKey();
  137. memset(hashKey, 0, REQUIRED_BLOCKSIZE);
  138. blockCipher.ProcessBlock(hashKey);
  139. #if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
  140. if (HasCLMUL())
  141. {
  142. const __m128i r = s_clmulConstants[0];
  143. __m128i h0 = _mm_shuffle_epi8(_mm_load_si128((__m128i *)hashKey), s_clmulConstants[1]);
  144. __m128i h = h0;
  145. for (i=0; i<tableSize; i+=32)
  146. {
  147. __m128i h1 = CLMUL_GF_Mul(h, h0, r);
  148. _mm_storel_epi64((__m128i *)(table+i), h);
  149. _mm_storeu_si128((__m128i *)(table+i+16), h1);
  150. _mm_storeu_si128((__m128i *)(table+i+8), h);
  151. _mm_storel_epi64((__m128i *)(table+i+8), h1);
  152. h = CLMUL_GF_Mul(h1, h0, r);
  153. }
  154. return;
  155. }
  156. #endif
  157. word64 V0, V1;
  158. typedef BlockGetAndPut<word64, BigEndian> Block;
  159. Block::Get(hashKey)(V0)(V1);
  160. if (tableSize == 64*1024)
  161. {
  162. for (i=0; i<128; i++)
  163. {
  164. k = i%8;
  165. Block::Put(NULL, table+(i/8)*256*16+(size_t(1)<<(11-k)))(V0)(V1);
  166. int x = (int)V1 & 1;
  167. V1 = (V1>>1) | (V0<<63);
  168. V0 = (V0>>1) ^ (x ? W64LIT(0xe1) << 56 : 0);
  169. }
  170. for (i=0; i<16; i++)
  171. {
  172. memset(table+i*256*16, 0, 16);
  173. #if CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE || CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
  174. if (HasSSE2())
  175. for (j=2; j<=0x80; j*=2)
  176. for (k=1; k<j; k++)
  177. SSE2_Xor16(table+i*256*16+(j+k)*16, table+i*256*16+j*16, table+i*256*16+k*16);
  178. else
  179. #endif
  180. for (j=2; j<=0x80; j*=2)
  181. for (k=1; k<j; k++)
  182. Xor16(table+i*256*16+(j+k)*16, table+i*256*16+j*16, table+i*256*16+k*16);
  183. }
  184. }
  185. else
  186. {
  187. if (!s_reductionTableInitialized)
  188. {
  189. s_reductionTable[0] = 0;
  190. word16 x = 0x01c2;
  191. s_reductionTable[1] = ByteReverse(x);
  192. for (int i=2; i<=0x80; i*=2)
  193. {
  194. x <<= 1;
  195. s_reductionTable[i] = ByteReverse(x);
  196. for (int j=1; j<i; j++)
  197. s_reductionTable[i+j] = s_reductionTable[i] ^ s_reductionTable[j];
  198. }
  199. s_reductionTableInitialized = true;
  200. }
  201. for (i=0; i<128-24; i++)
  202. {
  203. k = i%32;
  204. if (k < 4)
  205. Block::Put(NULL, table+1024+(i/32)*256+(size_t(1)<<(7-k)))(V0)(V1);
  206. else if (k < 8)
  207. Block::Put(NULL, table+(i/32)*256+(size_t(1)<<(11-k)))(V0)(V1);
  208. int x = (int)V1 & 1;
  209. V1 = (V1>>1) | (V0<<63);
  210. V0 = (V0>>1) ^ (x ? W64LIT(0xe1) << 56 : 0);
  211. }
  212. for (i=0; i<4; i++)
  213. {
  214. memset(table+i*256, 0, 16);
  215. memset(table+1024+i*256, 0, 16);
  216. #if CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE || CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
  217. if (HasSSE2())
  218. for (j=2; j<=8; j*=2)
  219. for (k=1; k<j; k++)
  220. {
  221. SSE2_Xor16(table+i*256+(j+k)*16, table+i*256+j*16, table+i*256+k*16);
  222. SSE2_Xor16(table+1024+i*256+(j+k)*16, table+1024+i*256+j*16, table+1024+i*256+k*16);
  223. }
  224. else
  225. #endif
  226. for (j=2; j<=8; j*=2)
  227. for (k=1; k<j; k++)
  228. {
  229. Xor16(table+i*256+(j+k)*16, table+i*256+j*16, table+i*256+k*16);
  230. Xor16(table+1024+i*256+(j+k)*16, table+1024+i*256+j*16, table+1024+i*256+k*16);
  231. }
  232. }
  233. }
  234. }
  235. inline void GCM_Base::ReverseHashBufferIfNeeded()
  236. {
  237. #if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
  238. if (HasCLMUL())
  239. {
  240. __m128i &x = *(__m128i *)HashBuffer();
  241. x = _mm_shuffle_epi8(x, s_clmulConstants[1]);
  242. }
  243. #endif
  244. }
  245. void GCM_Base::Resync(const byte *iv, size_t len)
  246. {
  247. BlockCipher &cipher = AccessBlockCipher();
  248. byte *hashBuffer = HashBuffer();
  249. if (len == 12)
  250. {
  251. memcpy(hashBuffer, iv, len);
  252. memset(hashBuffer+len, 0, 3);
  253. hashBuffer[len+3] = 1;
  254. }
  255. else
  256. {
  257. size_t origLen = len;
  258. memset(hashBuffer, 0, HASH_BLOCKSIZE);
  259. if (len >= HASH_BLOCKSIZE)
  260. {
  261. len = GCM_Base::AuthenticateBlocks(iv, len);
  262. iv += (origLen - len);
  263. }
  264. if (len > 0)
  265. {
  266. memcpy(m_buffer, iv, len);
  267. memset(m_buffer+len, 0, HASH_BLOCKSIZE-len);
  268. GCM_Base::AuthenticateBlocks(m_buffer, HASH_BLOCKSIZE);
  269. }
  270. PutBlock<word64, BigEndian, true>(NULL, m_buffer)(0)(origLen*8);
  271. GCM_Base::AuthenticateBlocks(m_buffer, HASH_BLOCKSIZE);
  272. ReverseHashBufferIfNeeded();
  273. }
  274. if (m_state >= State_IVSet)
  275. m_ctr.Resynchronize(hashBuffer, REQUIRED_BLOCKSIZE);
  276. else
  277. m_ctr.SetCipherWithIV(cipher, hashBuffer);
  278. m_ctr.Seek(HASH_BLOCKSIZE);
  279. memset(hashBuffer, 0, HASH_BLOCKSIZE);
  280. }
  281. unsigned int GCM_Base::OptimalDataAlignment() const
  282. {
  283. return
  284. #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE || defined(CRYPTOPP_X64_MASM_AVAILABLE)
  285. HasSSE2() ? 16 :
  286. #endif
  287. GetBlockCipher().OptimalDataAlignment();
  288. }
  289. #pragma warning(disable: 4731) // frame pointer register 'ebp' modified by inline assembly code
  290. #endif // #ifndef CRYPTOPP_GENERATE_X64_MASM
  291. #ifdef CRYPTOPP_X64_MASM_AVAILABLE
  292. extern "C" {
  293. void GCM_AuthenticateBlocks_2K(const byte *data, size_t blocks, word64 *hashBuffer, const word16 *reductionTable);
  294. void GCM_AuthenticateBlocks_64K(const byte *data, size_t blocks, word64 *hashBuffer);
  295. }
  296. #endif
  297. #ifndef CRYPTOPP_GENERATE_X64_MASM
  298. size_t GCM_Base::AuthenticateBlocks(const byte *data, size_t len)
  299. {
  300. #if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
  301. if (HasCLMUL())
  302. {
  303. const __m128i *table = (const __m128i *)MulTable();
  304. __m128i x = _mm_load_si128((__m128i *)HashBuffer());
  305. const __m128i r = s_clmulConstants[0], bswapMask = s_clmulConstants[1], bswapMask2 = s_clmulConstants[2];
  306. while (len >= 16)
  307. {
  308. size_t s = UnsignedMin(len/16, s_clmulTableSizeInBlocks), i=0;
  309. __m128i d, d2 = _mm_shuffle_epi8(_mm_loadu_si128((const __m128i *)(data+(s-1)*16)), bswapMask2);;
  310. __m128i c0 = _mm_setzero_si128();
  311. __m128i c1 = _mm_setzero_si128();
  312. __m128i c2 = _mm_setzero_si128();
  313. while (true)
  314. {
  315. __m128i h0 = _mm_load_si128(table+i);
  316. __m128i h1 = _mm_load_si128(table+i+1);
  317. __m128i h01 = _mm_xor_si128(h0, h1);
  318. if (++i == s)
  319. {
  320. d = _mm_shuffle_epi8(_mm_loadu_si128((const __m128i *)data), bswapMask);
  321. d = _mm_xor_si128(d, x);
  322. c0 = _mm_xor_si128(c0, _mm_clmulepi64_si128(d, h0, 0));
  323. c2 = _mm_xor_si128(c2, _mm_clmulepi64_si128(d, h1, 1));
  324. d = _mm_xor_si128(d, _mm_shuffle_epi32(d, _MM_SHUFFLE(1, 0, 3, 2)));
  325. c1 = _mm_xor_si128(c1, _mm_clmulepi64_si128(d, h01, 0));
  326. break;
  327. }
  328. d = _mm_shuffle_epi8(_mm_loadu_si128((const __m128i *)(data+(s-i)*16-8)), bswapMask2);
  329. c0 = _mm_xor_si128(c0, _mm_clmulepi64_si128(d2, h0, 1));
  330. c2 = _mm_xor_si128(c2, _mm_clmulepi64_si128(d, h1, 1));
  331. d2 = _mm_xor_si128(d2, d);
  332. c1 = _mm_xor_si128(c1, _mm_clmulepi64_si128(d2, h01, 1));
  333. if (++i == s)
  334. {
  335. d = _mm_shuffle_epi8(_mm_loadu_si128((const __m128i *)data), bswapMask);
  336. d = _mm_xor_si128(d, x);
  337. c0 = _mm_xor_si128(c0, _mm_clmulepi64_si128(d, h0, 0x10));
  338. c2 = _mm_xor_si128(c2, _mm_clmulepi64_si128(d, h1, 0x11));
  339. d = _mm_xor_si128(d, _mm_shuffle_epi32(d, _MM_SHUFFLE(1, 0, 3, 2)));
  340. c1 = _mm_xor_si128(c1, _mm_clmulepi64_si128(d, h01, 0x10));
  341. break;
  342. }
  343. d2 = _mm_shuffle_epi8(_mm_loadu_si128((const __m128i *)(data+(s-i)*16-8)), bswapMask);
  344. c0 = _mm_xor_si128(c0, _mm_clmulepi64_si128(d, h0, 0x10));
  345. c2 = _mm_xor_si128(c2, _mm_clmulepi64_si128(d2, h1, 0x10));
  346. d = _mm_xor_si128(d, d2);
  347. c1 = _mm_xor_si128(c1, _mm_clmulepi64_si128(d, h01, 0x10));
  348. }
  349. data += s*16;
  350. len -= s*16;
  351. c1 = _mm_xor_si128(_mm_xor_si128(c1, c0), c2);
  352. x = CLMUL_Reduce(c0, c1, c2, r);
  353. }
  354. _mm_store_si128((__m128i *)HashBuffer(), x);
  355. return len;
  356. }
  357. #endif
  358. typedef BlockGetAndPut<word64, NativeByteOrder> Block;
  359. word64 *hashBuffer = (word64 *)HashBuffer();
  360. switch (2*(m_buffer.size()>=64*1024)
  361. #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE || defined(CRYPTOPP_X64_MASM_AVAILABLE)
  362. + HasSSE2()
  363. #endif
  364. )
  365. {
  366. case 0: // non-SSE2 and 2K tables
  367. {
  368. byte *table = MulTable();
  369. word64 x0 = hashBuffer[0], x1 = hashBuffer[1];
  370. do
  371. {
  372. word64 y0, y1, a0, a1, b0, b1, c0, c1, d0, d1;
  373. Block::Get(data)(y0)(y1);
  374. x0 ^= y0;
  375. x1 ^= y1;
  376. data += HASH_BLOCKSIZE;
  377. len -= HASH_BLOCKSIZE;
  378. #define READ_TABLE_WORD64_COMMON(a, b, c, d) *(word64 *)(table+(a*1024)+(b*256)+c+d*8)
  379. #ifdef IS_LITTLE_ENDIAN
  380. #if CRYPTOPP_BOOL_SLOW_WORD64
  381. word32 z0 = (word32)x0;
  382. word32 z1 = (word32)(x0>>32);
  383. word32 z2 = (word32)x1;
  384. word32 z3 = (word32)(x1>>32);
  385. #define READ_TABLE_WORD64(a, b, c, d, e) READ_TABLE_WORD64_COMMON((d%2), c, (d?(z##c>>((d?d-1:0)*4))&0xf0:(z##c&0xf)<<4), e)
  386. #else
  387. #define READ_TABLE_WORD64(a, b, c, d, e) READ_TABLE_WORD64_COMMON((d%2), c, ((d+8*b)?(x##a>>(((d+8*b)?(d+8*b)-1:1)*4))&0xf0:(x##a&0xf)<<4), e)
  388. #endif
  389. #define GF_MOST_SIG_8BITS(a) (a##1 >> 7*8)
  390. #define GF_SHIFT_8(a) a##1 = (a##1 << 8) ^ (a##0 >> 7*8); a##0 <<= 8;
  391. #else
  392. #define READ_TABLE_WORD64(a, b, c, d, e) READ_TABLE_WORD64_COMMON((1-d%2), c, ((15-d-8*b)?(x##a>>(((15-d-8*b)?(15-d-8*b)-1:0)*4))&0xf0:(x##a&0xf)<<4), e)
  393. #define GF_MOST_SIG_8BITS(a) (a##1 & 0xff)
  394. #define GF_SHIFT_8(a) a##1 = (a##1 >> 8) ^ (a##0 << 7*8); a##0 >>= 8;
  395. #endif
  396. #define GF_MUL_32BY128(op, a, b, c) \
  397. a0 op READ_TABLE_WORD64(a, b, c, 0, 0) ^ READ_TABLE_WORD64(a, b, c, 1, 0);\
  398. a1 op READ_TABLE_WORD64(a, b, c, 0, 1) ^ READ_TABLE_WORD64(a, b, c, 1, 1);\
  399. b0 op READ_TABLE_WORD64(a, b, c, 2, 0) ^ READ_TABLE_WORD64(a, b, c, 3, 0);\
  400. b1 op READ_TABLE_WORD64(a, b, c, 2, 1) ^ READ_TABLE_WORD64(a, b, c, 3, 1);\
  401. c0 op READ_TABLE_WORD64(a, b, c, 4, 0) ^ READ_TABLE_WORD64(a, b, c, 5, 0);\
  402. c1 op READ_TABLE_WORD64(a, b, c, 4, 1) ^ READ_TABLE_WORD64(a, b, c, 5, 1);\
  403. d0 op READ_TABLE_WORD64(a, b, c, 6, 0) ^ READ_TABLE_WORD64(a, b, c, 7, 0);\
  404. d1 op READ_TABLE_WORD64(a, b, c, 6, 1) ^ READ_TABLE_WORD64(a, b, c, 7, 1);\
  405. GF_MUL_32BY128(=, 0, 0, 0)
  406. GF_MUL_32BY128(^=, 0, 1, 1)
  407. GF_MUL_32BY128(^=, 1, 0, 2)
  408. GF_MUL_32BY128(^=, 1, 1, 3)
  409. word32 r = (word32)s_reductionTable[GF_MOST_SIG_8BITS(d)] << 16;
  410. GF_SHIFT_8(d)
  411. c0 ^= d0; c1 ^= d1;
  412. r ^= (word32)s_reductionTable[GF_MOST_SIG_8BITS(c)] << 8;
  413. GF_SHIFT_8(c)
  414. b0 ^= c0; b1 ^= c1;
  415. r ^= s_reductionTable[GF_MOST_SIG_8BITS(b)];
  416. GF_SHIFT_8(b)
  417. a0 ^= b0; a1 ^= b1;
  418. a0 ^= ConditionalByteReverse<word64>(LITTLE_ENDIAN_ORDER, r);
  419. x0 = a0; x1 = a1;
  420. }
  421. while (len >= HASH_BLOCKSIZE);
  422. hashBuffer[0] = x0; hashBuffer[1] = x1;
  423. return len;
  424. }
  425. case 2: // non-SSE2 and 64K tables
  426. {
  427. byte *table = MulTable();
  428. word64 x0 = hashBuffer[0], x1 = hashBuffer[1];
  429. do
  430. {
  431. word64 y0, y1, a0, a1;
  432. Block::Get(data)(y0)(y1);
  433. x0 ^= y0;
  434. x1 ^= y1;
  435. data += HASH_BLOCKSIZE;
  436. len -= HASH_BLOCKSIZE;
  437. #undef READ_TABLE_WORD64_COMMON
  438. #undef READ_TABLE_WORD64
  439. #define READ_TABLE_WORD64_COMMON(a, c, d) *(word64 *)(table+(a)*256*16+(c)+(d)*8)
  440. #ifdef IS_LITTLE_ENDIAN
  441. #if CRYPTOPP_BOOL_SLOW_WORD64
  442. word32 z0 = (word32)x0;
  443. word32 z1 = (word32)(x0>>32);
  444. word32 z2 = (word32)x1;
  445. word32 z3 = (word32)(x1>>32);
  446. #define READ_TABLE_WORD64(b, c, d, e) READ_TABLE_WORD64_COMMON(c*4+d, (d?(z##c>>((d?d:1)*8-4))&0xff0:(z##c&0xff)<<4), e)
  447. #else
  448. #define READ_TABLE_WORD64(b, c, d, e) READ_TABLE_WORD64_COMMON(c*4+d, ((d+4*(c%2))?(x##b>>(((d+4*(c%2))?(d+4*(c%2)):1)*8-4))&0xff0:(x##b&0xff)<<4), e)
  449. #endif
  450. #else
  451. #define READ_TABLE_WORD64(b, c, d, e) READ_TABLE_WORD64_COMMON(c*4+d, ((7-d-4*(c%2))?(x##b>>(((7-d-4*(c%2))?(7-d-4*(c%2)):1)*8-4))&0xff0:(x##b&0xff)<<4), e)
  452. #endif
  453. #define GF_MUL_8BY128(op, b, c, d) \
  454. a0 op READ_TABLE_WORD64(b, c, d, 0);\
  455. a1 op READ_TABLE_WORD64(b, c, d, 1);\
  456. GF_MUL_8BY128(=, 0, 0, 0)
  457. GF_MUL_8BY128(^=, 0, 0, 1)
  458. GF_MUL_8BY128(^=, 0, 0, 2)
  459. GF_MUL_8BY128(^=, 0, 0, 3)
  460. GF_MUL_8BY128(^=, 0, 1, 0)
  461. GF_MUL_8BY128(^=, 0, 1, 1)
  462. GF_MUL_8BY128(^=, 0, 1, 2)
  463. GF_MUL_8BY128(^=, 0, 1, 3)
  464. GF_MUL_8BY128(^=, 1, 2, 0)
  465. GF_MUL_8BY128(^=, 1, 2, 1)
  466. GF_MUL_8BY128(^=, 1, 2, 2)
  467. GF_MUL_8BY128(^=, 1, 2, 3)
  468. GF_MUL_8BY128(^=, 1, 3, 0)
  469. GF_MUL_8BY128(^=, 1, 3, 1)
  470. GF_MUL_8BY128(^=, 1, 3, 2)
  471. GF_MUL_8BY128(^=, 1, 3, 3)
  472. x0 = a0; x1 = a1;
  473. }
  474. while (len >= HASH_BLOCKSIZE);
  475. hashBuffer[0] = x0; hashBuffer[1] = x1;
  476. return len;
  477. }
  478. #endif // #ifndef CRYPTOPP_GENERATE_X64_MASM
  479. #ifdef CRYPTOPP_X64_MASM_AVAILABLE
  480. case 1: // SSE2 and 2K tables
  481. GCM_AuthenticateBlocks_2K(data, len/16, hashBuffer, s_reductionTable);
  482. return len % 16;
  483. case 3: // SSE2 and 64K tables
  484. GCM_AuthenticateBlocks_64K(data, len/16, hashBuffer);
  485. return len % 16;
  486. #endif
  487. #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
  488. case 1: // SSE2 and 2K tables
  489. {
  490. #ifdef __GNUC__
  491. __asm__ __volatile__
  492. (
  493. ".intel_syntax noprefix;"
  494. #elif defined(CRYPTOPP_GENERATE_X64_MASM)
  495. ALIGN 8
  496. GCM_AuthenticateBlocks_2K PROC FRAME
  497. rex_push_reg rsi
  498. push_reg rdi
  499. push_reg rbx
  500. .endprolog
  501. mov rsi, r8
  502. mov r11, r9
  503. #else
  504. AS2( mov WORD_REG(cx), data )
  505. AS2( mov WORD_REG(dx), len )
  506. AS2( mov WORD_REG(si), hashBuffer )
  507. AS2( shr WORD_REG(dx), 4 )
  508. #endif
  509. AS_PUSH_IF86( bx)
  510. AS_PUSH_IF86( bp)
  511. #ifdef __GNUC__
  512. AS2( mov AS_REG_7, WORD_REG(di))
  513. #elif CRYPTOPP_BOOL_X86
  514. AS2( lea AS_REG_7, s_reductionTable)
  515. #endif
  516. AS2( movdqa xmm0, [WORD_REG(si)] )
  517. #define MUL_TABLE_0 WORD_REG(si) + 32
  518. #define MUL_TABLE_1 WORD_REG(si) + 32 + 1024
  519. #define RED_TABLE AS_REG_7
  520. ASL(0)
  521. AS2( movdqu xmm4, [WORD_REG(cx)] )
  522. AS2( pxor xmm0, xmm4 )
  523. AS2( movd ebx, xmm0 )
  524. AS2( mov eax, AS_HEX(f0f0f0f0) )
  525. AS2( and eax, ebx )
  526. AS2( shl ebx, 4 )
  527. AS2( and ebx, AS_HEX(f0f0f0f0) )
  528. AS2( movzx edi, ah )
  529. AS2( movdqa xmm5, XMMWORD_PTR [MUL_TABLE_1 + WORD_REG(di)] )
  530. AS2( movzx edi, al )
  531. AS2( movdqa xmm4, XMMWORD_PTR [MUL_TABLE_1 + WORD_REG(di)] )
  532. AS2( shr eax, 16 )
  533. AS2( movzx edi, ah )
  534. AS2( movdqa xmm3, XMMWORD_PTR [MUL_TABLE_1 + WORD_REG(di)] )
  535. AS2( movzx edi, al )
  536. AS2( movdqa xmm2, XMMWORD_PTR [MUL_TABLE_1 + WORD_REG(di)] )
  537. #define SSE2_MUL_32BITS(i) \
  538. AS2( psrldq xmm0, 4 )\
  539. AS2( movd eax, xmm0 )\
  540. AS2( and eax, AS_HEX(f0f0f0f0) )\
  541. AS2( movzx edi, bh )\
  542. AS2( pxor xmm5, XMMWORD_PTR [MUL_TABLE_0 + (i-1)*256 + WORD_REG(di)] )\
  543. AS2( movzx edi, bl )\
  544. AS2( pxor xmm4, XMMWORD_PTR [MUL_TABLE_0 + (i-1)*256 + WORD_REG(di)] )\
  545. AS2( shr ebx, 16 )\
  546. AS2( movzx edi, bh )\
  547. AS2( pxor xmm3, XMMWORD_PTR [MUL_TABLE_0 + (i-1)*256 + WORD_REG(di)] )\
  548. AS2( movzx edi, bl )\
  549. AS2( pxor xmm2, XMMWORD_PTR [MUL_TABLE_0 + (i-1)*256 + WORD_REG(di)] )\
  550. AS2( movd ebx, xmm0 )\
  551. AS2( shl ebx, 4 )\
  552. AS2( and ebx, AS_HEX(f0f0f0f0) )\
  553. AS2( movzx edi, ah )\
  554. AS2( pxor xmm5, XMMWORD_PTR [MUL_TABLE_1 + i*256 + WORD_REG(di)] )\
  555. AS2( movzx edi, al )\
  556. AS2( pxor xmm4, XMMWORD_PTR [MUL_TABLE_1 + i*256 + WORD_REG(di)] )\
  557. AS2( shr eax, 16 )\
  558. AS2( movzx edi, ah )\
  559. AS2( pxor xmm3, XMMWORD_PTR [MUL_TABLE_1 + i*256 + WORD_REG(di)] )\
  560. AS2( movzx edi, al )\
  561. AS2( pxor xmm2, XMMWORD_PTR [MUL_TABLE_1 + i*256 + WORD_REG(di)] )\
  562. SSE2_MUL_32BITS(1)
  563. SSE2_MUL_32BITS(2)
  564. SSE2_MUL_32BITS(3)
  565. AS2( movzx edi, bh )
  566. AS2( pxor xmm5, XMMWORD_PTR [MUL_TABLE_0 + 3*256 + WORD_REG(di)] )
  567. AS2( movzx edi, bl )
  568. AS2( pxor xmm4, XMMWORD_PTR [MUL_TABLE_0 + 3*256 + WORD_REG(di)] )
  569. AS2( shr ebx, 16 )
  570. AS2( movzx edi, bh )
  571. AS2( pxor xmm3, XMMWORD_PTR [MUL_TABLE_0 + 3*256 + WORD_REG(di)] )
  572. AS2( movzx edi, bl )
  573. AS2( pxor xmm2, XMMWORD_PTR [MUL_TABLE_0 + 3*256 + WORD_REG(di)] )
  574. AS2( movdqa xmm0, xmm3 )
  575. AS2( pslldq xmm3, 1 )
  576. AS2( pxor xmm2, xmm3 )
  577. AS2( movdqa xmm1, xmm2 )
  578. AS2( pslldq xmm2, 1 )
  579. AS2( pxor xmm5, xmm2 )
  580. AS2( psrldq xmm0, 15 )
  581. AS2( movd WORD_REG(di), xmm0 )
  582. AS2( movzx eax, WORD PTR [RED_TABLE + WORD_REG(di)*2] )
  583. AS2( shl eax, 8 )
  584. AS2( movdqa xmm0, xmm5 )
  585. AS2( pslldq xmm5, 1 )
  586. AS2( pxor xmm4, xmm5 )
  587. AS2( psrldq xmm1, 15 )
  588. AS2( movd WORD_REG(di), xmm1 )
  589. AS2( xor ax, WORD PTR [RED_TABLE + WORD_REG(di)*2] )
  590. AS2( shl eax, 8 )
  591. AS2( psrldq xmm0, 15 )
  592. AS2( movd WORD_REG(di), xmm0 )
  593. AS2( xor ax, WORD PTR [RED_TABLE + WORD_REG(di)*2] )
  594. AS2( movd xmm0, eax )
  595. AS2( pxor xmm0, xmm4 )
  596. AS2( add WORD_REG(cx), 16 )
  597. AS2( sub WORD_REG(dx), 1 )
  598. ASJ( jnz, 0, b )
  599. AS2( movdqa [WORD_REG(si)], xmm0 )
  600. AS_POP_IF86( bp)
  601. AS_POP_IF86( bx)
  602. #ifdef __GNUC__
  603. ".att_syntax prefix;"
  604. :
  605. : "c" (data), "d" (len/16), "S" (hashBuffer), "D" (s_reductionTable)
  606. : "memory", "cc", "%eax"
  607. #if CRYPTOPP_BOOL_X64
  608. , "%ebx", "%r11"
  609. #endif
  610. );
  611. #elif defined(CRYPTOPP_GENERATE_X64_MASM)
  612. pop rbx
  613. pop rdi
  614. pop rsi
  615. ret
  616. GCM_AuthenticateBlocks_2K ENDP
  617. #endif
  618. return len%16;
  619. }
  620. case 3: // SSE2 and 64K tables
  621. {
  622. #ifdef __GNUC__
  623. __asm__ __volatile__
  624. (
  625. ".intel_syntax noprefix;"
  626. #elif defined(CRYPTOPP_GENERATE_X64_MASM)
  627. ALIGN 8
  628. GCM_AuthenticateBlocks_64K PROC FRAME
  629. rex_push_reg rsi
  630. push_reg rdi
  631. .endprolog
  632. mov rsi, r8
  633. #else
  634. AS2( mov WORD_REG(cx), data )
  635. AS2( mov WORD_REG(dx), len )
  636. AS2( mov WORD_REG(si), hashBuffer )
  637. AS2( shr WORD_REG(dx), 4 )
  638. #endif
  639. AS2( movdqa xmm0, [WORD_REG(si)] )
  640. #undef MUL_TABLE
  641. #define MUL_TABLE(i,j) WORD_REG(si) + 32 + (i*4+j)*256*16
  642. ASL(1)
  643. AS2( movdqu xmm1, [WORD_REG(cx)] )
  644. AS2( pxor xmm1, xmm0 )
  645. AS2( pxor xmm0, xmm0 )
  646. #undef SSE2_MUL_32BITS
  647. #define SSE2_MUL_32BITS(i) \
  648. AS2( movd eax, xmm1 )\
  649. AS2( psrldq xmm1, 4 )\
  650. AS2( movzx edi, al )\
  651. AS2( add WORD_REG(di), WORD_REG(di) )\
  652. AS2( pxor xmm0, [MUL_TABLE(i,0) + WORD_REG(di)*8] )\
  653. AS2( movzx edi, ah )\
  654. AS2( add WORD_REG(di), WORD_REG(di) )\
  655. AS2( pxor xmm0, [MUL_TABLE(i,1) + WORD_REG(di)*8] )\
  656. AS2( shr eax, 16 )\
  657. AS2( movzx edi, al )\
  658. AS2( add WORD_REG(di), WORD_REG(di) )\
  659. AS2( pxor xmm0, [MUL_TABLE(i,2) + WORD_REG(di)*8] )\
  660. AS2( movzx edi, ah )\
  661. AS2( add WORD_REG(di), WORD_REG(di) )\
  662. AS2( pxor xmm0, [MUL_TABLE(i,3) + WORD_REG(di)*8] )\
  663. SSE2_MUL_32BITS(0)
  664. SSE2_MUL_32BITS(1)
  665. SSE2_MUL_32BITS(2)
  666. SSE2_MUL_32BITS(3)
  667. AS2( add WORD_REG(cx), 16 )
  668. AS2( sub WORD_REG(dx), 1 )
  669. ASJ( jnz, 1, b )
  670. AS2( movdqa [WORD_REG(si)], xmm0 )
  671. #ifdef __GNUC__
  672. ".att_syntax prefix;"
  673. :
  674. : "c" (data), "d" (len/16), "S" (hashBuffer)
  675. : "memory", "cc", "%edi", "%eax"
  676. );
  677. #elif defined(CRYPTOPP_GENERATE_X64_MASM)
  678. pop rdi
  679. pop rsi
  680. ret
  681. GCM_AuthenticateBlocks_64K ENDP
  682. #endif
  683. return len%16;
  684. }
  685. #endif
  686. #ifndef CRYPTOPP_GENERATE_X64_MASM
  687. }
  688. return len%16;
  689. }
  690. void GCM_Base::AuthenticateLastHeaderBlock()
  691. {
  692. if (m_bufferedDataLength > 0)
  693. {
  694. memset(m_buffer+m_bufferedDataLength, 0, HASH_BLOCKSIZE-m_bufferedDataLength);
  695. m_bufferedDataLength = 0;
  696. GCM_Base::AuthenticateBlocks(m_buffer, HASH_BLOCKSIZE);
  697. }
  698. }
  699. void GCM_Base::AuthenticateLastConfidentialBlock()
  700. {
  701. GCM_Base::AuthenticateLastHeaderBlock();
  702. PutBlock<word64, BigEndian, true>(NULL, m_buffer)(m_totalHeaderLength*8)(m_totalMessageLength*8);
  703. GCM_Base::AuthenticateBlocks(m_buffer, HASH_BLOCKSIZE);
  704. }
  705. void GCM_Base::AuthenticateLastFooterBlock(byte *mac, size_t macSize)
  706. {
  707. m_ctr.Seek(0);
  708. ReverseHashBufferIfNeeded();
  709. m_ctr.ProcessData(mac, HashBuffer(), macSize);
  710. }
  711. NAMESPACE_END
  712. #endif // #ifndef CRYPTOPP_GENERATE_X64_MASM
  713. #endif