aes.h (13809B)
1 /* 2 Copyright 2010-2011, D. E. Shaw Research. 3 All rights reserved. 4 5 Redistribution and use in source and binary forms, with or without 6 modification, are permitted provided that the following conditions are 7 met: 8 9 * Redistributions of source code must retain the above copyright 10 notice, this list of conditions, and the following disclaimer. 11 12 * Redistributions in binary form must reproduce the above copyright 13 notice, this list of conditions, and the following disclaimer in the 14 documentation and/or other materials provided with the distribution. 15 16 * Neither the name of D. E. Shaw Research nor the names of its 17 contributors may be used to endorse or promote products derived from 18 this software without specific prior written permission. 19 20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 #ifndef __Random123_aes_dot_hpp__ 33 #define __Random123_aes_dot_hpp__ 34 35 #include "features/compilerfeatures.h" 36 #include "array.h" 37 38 /* Implement a bona fide AES block cipher. It's minimally 39 // checked against the test vector in FIPS-197 in ut_aes.cpp. */ 40 #if R123_USE_AES_NI 41 42 /** @ingroup AESNI */ 43 typedef struct r123array1xm128i aesni1xm128i_ctr_t; 44 /** @ingroup AESNI */ 45 typedef struct r123array1xm128i aesni1xm128i_ukey_t; 46 /** @ingroup AESNI */ 47 typedef struct r123array4x32 aesni4x32_ukey_t; 48 /** @ingroup AESNI */ 49 enum r123_enum_aesni1xm128i { aesni1xm128i_rounds = 10 }; 50 51 /** \cond HIDDEN_FROM_DOXYGEN */ 52 R123_STATIC_INLINE __m128i AES_128_ASSIST (__m128i temp1, __m128i temp2) { 53 __m128i temp3; 54 temp2 = _mm_shuffle_epi32 (temp2 ,0xff); 55 temp3 = _mm_slli_si128 (temp1, 0x4); 56 temp1 = _mm_xor_si128 (temp1, temp3); 57 temp3 = _mm_slli_si128 (temp3, 0x4); 58 temp1 = _mm_xor_si128 (temp1, temp3); 59 temp3 = _mm_slli_si128 (temp3, 0x4); 60 temp1 = _mm_xor_si128 (temp1, temp3); 61 temp1 = _mm_xor_si128 (temp1, temp2); 62 return temp1; 63 } 64 65 R123_STATIC_INLINE void aesni1xm128iexpand(aesni1xm128i_ukey_t uk, __m128i ret[11]) 66 { 67 __m128i rkey = uk.v[0].m; 68 __m128i tmp2; 69 70 ret[0] = rkey; 71 tmp2 = _mm_aeskeygenassist_si128(rkey, 0x1); 72 rkey = AES_128_ASSIST(rkey, tmp2); 73 ret[1] = rkey; 74 75 tmp2 = _mm_aeskeygenassist_si128(rkey, 0x2); 76 rkey = AES_128_ASSIST(rkey, tmp2); 77 ret[2] = rkey; 78 79 tmp2 = _mm_aeskeygenassist_si128(rkey, 0x4); 80 rkey = AES_128_ASSIST(rkey, tmp2); 81 ret[3] = rkey; 82 83 tmp2 = _mm_aeskeygenassist_si128(rkey, 0x8); 84 rkey = AES_128_ASSIST(rkey, tmp2); 85 ret[4] = rkey; 86 87 tmp2 = _mm_aeskeygenassist_si128(rkey, 0x10); 88 rkey = AES_128_ASSIST(rkey, tmp2); 89 ret[5] = rkey; 90 91 tmp2 = _mm_aeskeygenassist_si128(rkey, 0x20); 92 rkey = AES_128_ASSIST(rkey, tmp2); 93 ret[6] = rkey; 94 95 tmp2 = _mm_aeskeygenassist_si128(rkey, 0x40); 96 rkey = AES_128_ASSIST(rkey, tmp2); 97 ret[7] = rkey; 98 99 tmp2 = _mm_aeskeygenassist_si128(rkey, 0x80); 100 rkey = AES_128_ASSIST(rkey, tmp2); 101 ret[8] = rkey; 102 103 tmp2 = _mm_aeskeygenassist_si128(rkey, 0x1b); 104 rkey = AES_128_ASSIST(rkey, tmp2); 105 ret[9] = rkey; 106 107 tmp2 = _mm_aeskeygenassist_si128(rkey, 0x36); 108 rkey = AES_128_ASSIST(rkey, tmp2); 109 ret[10] = rkey; 110 } 111 /** \endcond */ 112 113 #ifdef __cplusplus 114 /** @ingroup AESNI */ 115 struct aesni1xm128i_key_t{ 116 __m128i k[11]; 117 aesni1xm128i_key_t(){ 118 aesni1xm128i_ukey_t uk; 119 uk.v[0].m = _mm_setzero_si128(); 120 aesni1xm128iexpand(uk, k); 121 } 122 aesni1xm128i_key_t(const aesni1xm128i_ukey_t& uk){ 123 aesni1xm128iexpand(uk, k); 124 } 125 aesni1xm128i_key_t(const aesni4x32_ukey_t& uk){ 126 aesni1xm128i_ukey_t uk128; 127 uk128.v[0].m = _mm_set_epi32(uk.v[3], uk.v[2], uk.v[1], uk.v[0]); 128 aesni1xm128iexpand(uk128, k); 129 } 130 aesni1xm128i_key_t& operator=(const aesni1xm128i_ukey_t& uk){ 131 aesni1xm128iexpand(uk, k); 132 return *this; 133 } 134 aesni1xm128i_key_t& operator=(const aesni4x32_ukey_t& uk){ 135 aesni1xm128i_ukey_t uk128; 136 uk128.v[0].m = _mm_set_epi32(uk.v[3], uk.v[2], uk.v[1], uk.v[0]); 137 aesni1xm128iexpand(uk128, k); 138 return *this; 139 } 140 bool operator==(const aesni1xm128i_key_t& rhs) const{ 141 for(int i=0; i<11; ++i){ 142 // Sigh... No r123m128i(__m128i) constructor! 143 r123m128i li; li.m = k[i]; 144 r123m128i ri; ri.m = rhs.k[i]; 145 if( li != ri ) return false; 146 } 147 return true; 148 } 149 bool operator!=(const aesni1xm128i_key_t& rhs) const{ 150 return !(*this == rhs); 151 } 152 friend std::ostream& operator<<(std::ostream& os, const aesni1xm128i_key_t& v){ 153 r123m128i ki; 154 for(int i=0; i<10; ++i){ 155 ki.m = v.k[i]; 156 os << ki << " "; 157 } 158 ki.m = v.k[10]; 159 return os << ki; 160 } 161 friend std::istream& operator>>(std::istream& is, aesni1xm128i_key_t& v){ 162 r123m128i ki; 163 for(int i=0; i<11; ++i){ 164 is >> ki; 165 v.k[i] = ki; 166 } 167 return is; 168 } 169 }; 170 #else 171 typedef struct { 172 __m128i k[11]; 173 }aesni1xm128i_key_t; 174 175 /** @ingroup AESNI */ 176 R123_STATIC_INLINE aesni1xm128i_key_t aesni1xm128ikeyinit(aesni1xm128i_ukey_t uk){ 177 aesni1xm128i_key_t ret; 178 aesni1xm128iexpand(uk, ret.k); 179 return ret; 180 } 181 #endif 182 183 /** @ingroup AESNI */ 184 R123_STATIC_INLINE aesni1xm128i_ctr_t aesni1xm128i(aesni1xm128i_ctr_t in, aesni1xm128i_key_t k) { 185 __m128i x = _mm_xor_si128(k.k[0], in.v[0].m); 186 x = _mm_aesenc_si128(x, k.k[1]); 187 x = _mm_aesenc_si128(x, k.k[2]); 188 x = _mm_aesenc_si128(x, k.k[3]); 189 x = _mm_aesenc_si128(x, k.k[4]); 190 x = _mm_aesenc_si128(x, k.k[5]); 191 x = _mm_aesenc_si128(x, k.k[6]); 192 x = _mm_aesenc_si128(x, k.k[7]); 193 x = _mm_aesenc_si128(x, k.k[8]); 194 x = _mm_aesenc_si128(x, k.k[9]); 195 x = _mm_aesenclast_si128(x, k.k[10]); 196 { 197 aesni1xm128i_ctr_t ret; 198 ret.v[0].m = x; 199 return ret; 200 } 201 } 202 203 /** @ingroup AESNI */ 204 R123_STATIC_INLINE aesni1xm128i_ctr_t aesni1xm128i_R(unsigned R, aesni1xm128i_ctr_t in, aesni1xm128i_key_t k){ 205 R123_ASSERT(R==10); 206 return aesni1xm128i(in, k); 207 } 208 209 210 /** @ingroup AESNI */ 211 typedef struct r123array4x32 aesni4x32_ctr_t; 212 /** @ingroup AESNI */ 213 typedef aesni1xm128i_key_t aesni4x32_key_t; 214 /** @ingroup AESNI */ 215 enum r123_enum_aesni4x32 { aesni4x32_rounds = 10 }; 216 /** @ingroup AESNI */ 217 R123_STATIC_INLINE aesni4x32_key_t aesni4x32keyinit(aesni4x32_ukey_t uk){ 218 aesni1xm128i_ukey_t uk128; 219 aesni4x32_key_t ret; 220 uk128.v[0].m = _mm_set_epi32(uk.v[3], uk.v[2], uk.v[1], uk.v[0]); 221 aesni1xm128iexpand(uk128, ret.k); 222 return ret; 223 } 224 225 /** @ingroup AESNI */ 226 /** The aesni4x32_R function provides a C API to the @ref AESNI "AESNI" CBRNG, allowing the number of rounds to be specified explicitly **/ 227 R123_STATIC_INLINE aesni4x32_ctr_t aesni4x32_R(unsigned int Nrounds, aesni4x32_ctr_t c, aesni4x32_key_t k){ 228 aesni1xm128i_ctr_t c128; 229 c128.v[0].m = _mm_set_epi32(c.v[3], c.v[2], c.v[1], c.v[0]); 230 c128 = aesni1xm128i_R(Nrounds, c128, k); 231 _mm_storeu_si128((__m128i*)&c.v[0], c128.v[0].m); 232 return c; 233 } 234 235 #define aesni4x32_rounds aesni1xm128i_rounds 236 237 /** The aesni4x32 macro provides a C API to the @ref AESNI "AESNI" CBRNG, uses the default number of rounds i.e. \c aesni4x32_rounds **/ 238 /** @ingroup AESNI */ 239 #define aesni4x32(c,k) aesni4x32_R(aesni4x32_rounds, c, k) 240 241 #ifdef __cplusplus 242 namespace r123{ 243 /** 244 @defgroup AESNI ARS and AESNI Classes and Typedefs 245 246 The ARS4x32, ARS1xm128i, AESNI4x32 and AESNI1xm128i classes export the member functions, typedefs and 247 operator overloads required by a @ref CBRNG "CBRNG" class. 248 249 ARS1xm128i and AESNI1xm128i are based on the AES block cipher and rely on the AES-NI hardware instructions 250 available on some some new (2011) CPUs. 251 252 The ARS1xm128i CBRNG and the use of AES for random number generation are described in 253 <a href="http://dl.acm.org/citation.cfm?doid=2063405"><i>Parallel Random Numbers: As Easy as 1, 2, 3</i> </a>. 254 Although it uses some cryptographic primitives, ARS1xm128i uses a cryptographically weak key schedule and is \b not suitable for cryptographic use. 255 256 @class AESNI1xm128i 257 @ingroup AESNI 258 AESNI exports the member functions, typedefs and operator overloads required by a @ref CBRNG class. 259 260 AESNI1xm128i uses the crypotgraphic AES round function, including the cryptographic key schedule. 261 262 In contrast to the other CBRNGs in the Random123 library, the AESNI1xm128i_R::key_type is opaque 263 and is \b not identical to the AESNI1xm128i_R::ukey_type. Creating a key_type, using either the constructor 264 or assignment operator, is significantly more time-consuming than running the bijection (hundreds 265 of clock cycles vs. tens of clock cycles). 266 267 AESNI1xm128i is only available when the feature-test macro R123_USE_AES_NI is true, which 268 should occur only when the compiler is configured to generate AES-NI instructions (or 269 when defaults are overridden by compile-time, compiler-command-line options). 270 271 As of September 2011, the authors know of no statistical flaws with AESNI1xm128i. It 272 would be an event of major cryptographic note if any such flaws were ever found. 273 */ 274 struct AESNI1xm128i{ 275 typedef aesni1xm128i_ctr_t ctr_type; 276 typedef aesni1xm128i_ukey_t ukey_type; 277 typedef aesni1xm128i_key_t key_type; 278 static const unsigned int rounds=10; 279 ctr_type operator()(ctr_type ctr, key_type key) const{ 280 return aesni1xm128i(ctr, key); 281 } 282 }; 283 284 /* @class AESNI4x32 */ 285 struct AESNI4x32{ 286 typedef aesni4x32_ctr_t ctr_type; 287 typedef aesni4x32_ukey_t ukey_type; 288 typedef aesni4x32_key_t key_type; 289 static const unsigned int rounds=10; 290 ctr_type operator()(ctr_type ctr, key_type key) const{ 291 return aesni4x32(ctr, key); 292 } 293 }; 294 295 /** @ingroup AESNI 296 @class AESNI1xm128i_R 297 298 AESNI1xm128i_R is provided for completeness, but is only instantiable with ROUNDS=10, in 299 which case it is identical to AESNI1xm128i */ 300 template <unsigned ROUNDS=10> 301 struct AESNI1xm128i_R : public AESNI1xm128i{ 302 R123_STATIC_ASSERT(ROUNDS==10, "AESNI1xm128i_R<R> is only valid with R=10"); 303 }; 304 305 /** @class AESNI4x32_R **/ 306 template <unsigned ROUNDS=10> 307 struct AESNI4x32_R : public AESNI4x32{ 308 R123_STATIC_ASSERT(ROUNDS==10, "AESNI4x32_R<R> is only valid with R=10"); 309 }; 310 } // namespace r123 311 #endif /* __cplusplus */ 312 313 #endif /* R123_USE_AES_NI */ 314 315 #if R123_USE_AES_OPENSSL 316 #include "string.h" 317 #include <openssl/aes.h> 318 typedef struct r123array16x8 aesopenssl16x8_ctr_t; 319 typedef struct r123array16x8 aesopenssl16x8_ukey_t; 320 #ifdef __cplusplus 321 struct aesopenssl16x8_key_t{ 322 AES_KEY k; 323 aesopenssl16x8_key_t(){ 324 aesopenssl16x8_ukey_t ukey={{}}; 325 AES_set_encrypt_key((const unsigned char *)&ukey.v[0], 128, &k); 326 } 327 aesopenssl16x8_key_t(const aesopenssl16x8_ukey_t& ukey){ 328 AES_set_encrypt_key((const unsigned char *)&ukey.v[0], 128, &k); 329 } 330 aesopenssl16x8_key_t& operator=(const aesopenssl16x8_ukey_t& ukey){ 331 AES_set_encrypt_key((const unsigned char *)&ukey.v[0], 128, &k); 332 return *this; 333 } 334 bool operator==(const aesopenssl16x8_key_t& rhs) const{ 335 return (k.rounds == rhs.k.rounds) && 0==::memcmp(&k.rd_key[0], &rhs.k.rd_key[0], (k.rounds+1) * 4 * sizeof(uint32_t)); 336 } 337 bool operator!=(const aesopenssl16x8_key_t& rhs) const{ 338 return !(*this == rhs); 339 } 340 friend std::ostream& operator<<(std::ostream& os, const aesopenssl16x8_key_t& v){ 341 os << v.k.rounds; 342 const unsigned int *p = &v.k.rd_key[0]; 343 for(int i=0; i<(v.k.rounds+1); ++i){ 344 os << " " << p[0] << " " << p[1] << " " << p[2] << " " << p[3]; 345 p += 4; 346 } 347 return os; 348 } 349 friend std::istream& operator>>(std::istream& is, aesopenssl16x8_key_t& v){ 350 is >> v.k.rounds; 351 unsigned int *p = &v.k.rd_key[0]; 352 for(int i=0; i<(v.k.rounds+1); ++i){ 353 is >> p[0] >> p[1] >> p[2] >> p[3]; 354 p += 4; 355 } 356 return is; 357 } 358 }; 359 #else 360 typedef struct aesopenssl16x8_key_t{ 361 AES_KEY k; 362 }aesopenssl16x8_key_t; 363 R123_STATIC_INLINE struct aesopenssl16x8_key_t aesopenssl16x8keyinit(aesopenssl16x8_ukey_t uk){ 364 aesopenssl16x8_key_t ret; 365 AES_set_encrypt_key((const unsigned char *)&uk.v[0], 128, &ret.k); 366 return ret; 367 } 368 #endif 369 370 R123_STATIC_INLINE R123_FORCE_INLINE(aesopenssl16x8_ctr_t aesopenssl16x8_R(aesopenssl16x8_ctr_t ctr, aesopenssl16x8_key_t key)); 371 R123_STATIC_INLINE 372 aesopenssl16x8_ctr_t aesopenssl16x8_R(aesopenssl16x8_ctr_t ctr, aesopenssl16x8_key_t key){ 373 aesopenssl16x8_ctr_t ret; 374 AES_encrypt((const unsigned char*)&ctr.v[0], (unsigned char *)&ret.v[0], &key.k); 375 return ret; 376 } 377 378 #define aesopenssl16x8_rounds aesni4x32_rounds 379 #define aesopenssl16x8(c,k) aesopenssl16x8_R(aesopenssl16x8_rounds) 380 381 #ifdef __cplusplus 382 namespace r123{ 383 struct AESOpenSSL16x8{ 384 typedef aesopenssl16x8_ctr_t ctr_type; 385 typedef aesopenssl16x8_key_t key_type; 386 typedef aesopenssl16x8_ukey_t ukey_type; 387 static const unsigned int rounds=10; 388 ctr_type operator()(const ctr_type& in, const key_type& k){ 389 ctr_type out; 390 AES_encrypt((const unsigned char *)&in[0], (unsigned char *)&out[0], &k.k); 391 return out; 392 } 393 }; 394 } // namespace r123 395 #endif /* __cplusplus */ 396 #endif /* R123_USE_AES_OPENSSL */ 397 398 #endif