AES.hpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /*
  2. * ZeroTier One - Network Virtualization Everywhere
  3. * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * --
  19. *
  20. * You can be released from the requirements of the license by purchasing
  21. * a commercial license. Buying such a license is mandatory as soon as you
  22. * develop commercial closed-source software that incorporates or links
  23. * directly against ZeroTier software without disclosing the source code
  24. * of your own application.
  25. */
  26. #ifndef ZT_AES_HPP
  27. #define ZT_AES_HPP
  28. #include "Constants.hpp"
  29. #include "Utils.hpp"
  30. #if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
  31. #include <wmmintrin.h>
  32. #include <emmintrin.h>
  33. #include <smmintrin.h>
  34. #define ZT_AES_AESNI 1
  35. #endif
  36. namespace ZeroTier {
  37. /**
  38. * AES-256 and GCM AEAD
  39. *
  40. * AES with 128-bit or 192-bit key sizes isn't supported here. This also only
  41. * supports the encrypt operation since we use AES in GCM mode. For HW acceleration
  42. * the code is inlined for maximum performance.
  43. */
  44. class AES
  45. {
  46. public:
  47. /**
  48. * This will be true if your platform's type of AES acceleration is supported on this machine
  49. */
  50. static const bool HW_ACCEL;
  51. inline AES() {}
  52. inline AES(const uint8_t key[32]) { this->init(key); }
  53. inline ~AES()
  54. {
  55. Utils::burn(&_k,sizeof(_k)); // ensure that expanded key memory is zeroed on object destruction
  56. }
  57. inline void init(const uint8_t key[32])
  58. {
  59. if (HW_ACCEL) {
  60. #ifdef ZT_AES_AESNI
  61. _init_aesni(key);
  62. #endif
  63. } else {
  64. _initSW(key);
  65. }
  66. }
  67. inline void encrypt(const uint8_t in[16],uint8_t out[16]) const
  68. {
  69. if (HW_ACCEL) {
  70. #ifdef ZT_AES_AESNI
  71. _encrypt_aesni(in,out);
  72. #endif
  73. } else {
  74. _encryptSW(in,out);
  75. }
  76. }
  77. // These are public so the software mode can always be tested in self-test.
  78. // Normally init(), encrypt(), etc. should be used.
  79. void _initSW(const uint8_t key[32]);
  80. void _encryptSW(const uint8_t in[16],uint8_t out[16]) const;
  81. private:
  82. #ifdef ZT_AES_AESNI
  83. static inline __m128i _init256_1(__m128i a,__m128i b)
  84. {
  85. __m128i x,y;
  86. b = _mm_shuffle_epi32(b,0xff);
  87. y = _mm_slli_si128(a,0x04);
  88. x = _mm_xor_si128(a,y);
  89. y = _mm_slli_si128(y,0x04);
  90. x = _mm_xor_si128(x,y);
  91. y = _mm_slli_si128(y,0x04);
  92. x = _mm_xor_si128(x,y);
  93. x = _mm_xor_si128(x,b);
  94. return x;
  95. }
  96. static inline __m128i _init256_2(__m128i a,__m128i b)
  97. {
  98. __m128i x,y,z;
  99. y = _mm_aeskeygenassist_si128(a,0x00);
  100. z = _mm_shuffle_epi32(y,0xaa);
  101. y = _mm_slli_si128(b,0x04);
  102. x = _mm_xor_si128(b,y);
  103. y = _mm_slli_si128(y,0x04);
  104. x = _mm_xor_si128(x,y);
  105. y = _mm_slli_si128(y,0x04);
  106. x = _mm_xor_si128(x,y);
  107. x = _mm_xor_si128(x,z);
  108. return x;
  109. }
  110. inline void _init_aesni(const uint8_t key[32])
  111. {
  112. __m128i t1,t2;
  113. _k.ni[0] = t1 = _mm_loadu_si128((const __m128i *)key);
  114. _k.ni[1] = t2 = _mm_loadu_si128((const __m128i *)(key+16));
  115. _k.ni[2] = t1 = _init256_1(t1,_mm_aeskeygenassist_si128(t2,0x01));
  116. _k.ni[3] = t2 = _init256_2(t1,t2);
  117. _k.ni[4] = t1 = _init256_1(t1,_mm_aeskeygenassist_si128(t2,0x02));
  118. _k.ni[5] = t2 = _init256_2(t1,t2);
  119. _k.ni[6] = t1 = _init256_1(t1,_mm_aeskeygenassist_si128(t2,0x04));
  120. _k.ni[7] = t2 = _init256_2(t1,t2);
  121. _k.ni[8] = t1 = _init256_1(t1,_mm_aeskeygenassist_si128(t2,0x08));
  122. _k.ni[9] = t2 = _init256_2(t1,t2);
  123. _k.ni[10] = t1 = _init256_1(t1,_mm_aeskeygenassist_si128(t2,0x10));
  124. _k.ni[11] = t2 = _init256_2(t1,t2);
  125. _k.ni[12] = t1 = _init256_1(t1,_mm_aeskeygenassist_si128(t2,0x20));
  126. _k.ni[13] = t2 = _init256_2(t1,t2);
  127. _k.ni[14] = _init256_1(t1,_mm_aeskeygenassist_si128(t2,0x40));
  128. }
  129. inline void _encrypt_aesni(const void *in,void *out) const
  130. {
  131. __m128i tmp;
  132. tmp = _mm_loadu_si128((const __m128i *)in);
  133. tmp = _mm_xor_si128(tmp,_k.ni[0]);
  134. tmp = _mm_aesenc_si128(tmp,_k.ni[1]);
  135. tmp = _mm_aesenc_si128(tmp,_k.ni[2]);
  136. tmp = _mm_aesenc_si128(tmp,_k.ni[3]);
  137. tmp = _mm_aesenc_si128(tmp,_k.ni[4]);
  138. tmp = _mm_aesenc_si128(tmp,_k.ni[5]);
  139. tmp = _mm_aesenc_si128(tmp,_k.ni[6]);
  140. tmp = _mm_aesenc_si128(tmp,_k.ni[7]);
  141. tmp = _mm_aesenc_si128(tmp,_k.ni[8]);
  142. tmp = _mm_aesenc_si128(tmp,_k.ni[9]);
  143. tmp = _mm_aesenc_si128(tmp,_k.ni[10]);
  144. tmp = _mm_aesenc_si128(tmp,_k.ni[11]);
  145. tmp = _mm_aesenc_si128(tmp,_k.ni[12]);
  146. tmp = _mm_aesenc_si128(tmp,_k.ni[13]);
  147. _mm_storeu_si128((__m128i *)out,_mm_aesenclast_si128(tmp,_k.ni[14]));
  148. }
  149. #endif
  150. union {
  151. #ifdef ZT_AES_AESNI
  152. __m128i ni[15]; // AES-NI expanded key
  153. #endif
  154. uint32_t sw[60]; // software mode expanded key
  155. } _k;
  156. };
  157. } // namespace ZeroTier
  158. #endif