Crypto++  5.6.5
Free C++ class library of cryptographic schemes
cpu.cpp
1 // cpu.cpp - originally written and placed in the public domain by Wei Dai
2 
3 #include "pch.h"
4 #include "config.h"
5 
6 #ifndef EXCEPTION_EXECUTE_HANDLER
7 # define EXCEPTION_EXECUTE_HANDLER 1
8 #endif
9 
10 #ifndef CRYPTOPP_IMPORTS
11 
12 #include "cpu.h"
13 #include "misc.h"
14 #include <algorithm>
15 
16 #ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
17 #include <signal.h>
18 #include <setjmp.h>
19 #endif
20 
21 NAMESPACE_BEGIN(CryptoPP)
22 
23 #ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
24 extern "C" {
25  typedef void (*SigHandler)(int);
26 };
27 #endif // Not CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
28 
29 #ifdef CRYPTOPP_CPUID_AVAILABLE
30 
31 #if _MSC_VER >= 1400 && CRYPTOPP_X64
32 
33 bool CpuId(word32 input, word32 output[4])
34 {
35  __cpuid((int *)output, input);
36  return true;
37 }
38 
39 #else
40 
41 #ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
42 extern "C"
43 {
44  static jmp_buf s_jmpNoCPUID;
45  static void SigIllHandlerCPUID(int)
46  {
47  longjmp(s_jmpNoCPUID, 1);
48  }
49 
50  static jmp_buf s_jmpNoSSE2;
51  static void SigIllHandlerSSE2(int)
52  {
53  longjmp(s_jmpNoSSE2, 2);
54  }
55 }
56 #endif
57 
58 bool CpuId(word32 input, word32 output[4])
59 {
60 #if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
61  __try
62  {
63  __asm
64  {
65  mov eax, input
66  mov ecx, 0
67  cpuid
68  mov edi, output
69  mov [edi], eax
70  mov [edi+4], ebx
71  mov [edi+8], ecx
72  mov [edi+12], edx
73  }
74  }
75  // GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION
76  __except (EXCEPTION_EXECUTE_HANDLER)
77  {
78  return false;
79  }
80 
81  // function 0 returns the highest basic function understood in EAX
82  if(input == 0)
83  return !!output[0];
84 
85  return true;
86 #else
87  // longjmp and clobber warnings. Volatile is required.
88  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
89  volatile bool result = true;
90 
91  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandlerCPUID);
92  if (oldHandler == SIG_ERR)
93  return false;
94 
95 # ifndef __MINGW32__
96  volatile sigset_t oldMask;
97  if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
98  return false;
99 # endif
100 
101  if (setjmp(s_jmpNoCPUID))
102  result = false;
103  else
104  {
105  asm volatile
106  (
107  // save ebx in case -fPIC is being used
108  // TODO: this might need an early clobber on EDI.
109 # if CRYPTOPP_X32 || CRYPTOPP_X64
110  "pushq %%rbx; cpuid; mov %%ebx, %%edi; popq %%rbx"
111 # else
112  "push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx"
113 # endif
114  : "=a" (output[0]), "=D" (output[1]), "=c" (output[2]), "=d" (output[3])
115  : "a" (input), "c" (0)
116  : "cc"
117  );
118  }
119 
120 # ifndef __MINGW32__
121  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
122 # endif
123 
124  signal(SIGILL, oldHandler);
125  return result;
126 #endif
127 }
128 
129 #endif
130 
131 static bool TrySSE2()
132 {
133 #if CRYPTOPP_X64
134  return true;
135 #elif defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
136  __try
137  {
138 #if CRYPTOPP_SSE2_ASM_AVAILABLE
139  AS2(por xmm0, xmm0) // executing SSE2 instruction
140 #elif CRYPTOPP_SSE2_INTRINSICS_AVAILABLE
141  __m128i x = _mm_setzero_si128();
142  return _mm_cvtsi128_si32(x) == 0;
143 #endif
144  }
145  // GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION
146  __except (EXCEPTION_EXECUTE_HANDLER)
147  {
148  return false;
149  }
150  return true;
151 #else
152  // longjmp and clobber warnings. Volatile is required.
153  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
154  volatile bool result = true;
155 
156  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandlerSSE2);
157  if (oldHandler == SIG_ERR)
158  return false;
159 
160 # ifndef __MINGW32__
161  volatile sigset_t oldMask;
162  if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
163  return false;
164 # endif
165 
166  if (setjmp(s_jmpNoSSE2))
167  result = false;
168  else
169  {
170 #if CRYPTOPP_SSE2_ASM_AVAILABLE
171  __asm __volatile ("por %xmm0, %xmm0");
172 #elif CRYPTOPP_SSE2_INTRINSICS_AVAILABLE
173  __m128i x = _mm_setzero_si128();
174  result = _mm_cvtsi128_si32(x) == 0;
175 #endif
176  }
177 
178 # ifndef __MINGW32__
179  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
180 # endif
181 
182  signal(SIGILL, oldHandler);
183  return result;
184 #endif
185 }
186 
187 bool CRYPTOPP_SECTION_INIT g_x86DetectionDone = false;
188 bool CRYPTOPP_SECTION_INIT g_hasMMX = false, CRYPTOPP_SECTION_INIT g_hasISSE = false, CRYPTOPP_SECTION_INIT g_hasSSE2 = false, CRYPTOPP_SECTION_INIT g_hasSSSE3 = false;
189 bool CRYPTOPP_SECTION_INIT g_hasSSE4 = false, CRYPTOPP_SECTION_INIT g_hasAESNI = false, CRYPTOPP_SECTION_INIT g_hasCLMUL = false, CRYPTOPP_SECTION_INIT g_hasSHA = false;
190 bool CRYPTOPP_SECTION_INIT g_hasRDRAND = false, CRYPTOPP_SECTION_INIT g_hasRDSEED = false, CRYPTOPP_SECTION_INIT g_isP4 = false;
191 bool CRYPTOPP_SECTION_INIT g_hasPadlockRNG = false, CRYPTOPP_SECTION_INIT g_hasPadlockACE = false, CRYPTOPP_SECTION_INIT g_hasPadlockACE2 = false;
192 bool CRYPTOPP_SECTION_INIT g_hasPadlockPHE = false, CRYPTOPP_SECTION_INIT g_hasPadlockPMM = false;
193 word32 CRYPTOPP_SECTION_INIT g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
194 
195 static inline bool IsIntel(const word32 output[4])
196 {
197  // This is the "GenuineIntel" string
198  return (output[1] /*EBX*/ == 0x756e6547) &&
199  (output[2] /*ECX*/ == 0x6c65746e) &&
200  (output[3] /*EDX*/ == 0x49656e69);
201 }
202 
203 static inline bool IsAMD(const word32 output[4])
204 {
205  // This is the "AuthenticAMD" string. Some early K5's can return "AMDisbetter!"
206  return (output[1] /*EBX*/ == 0x68747541) &&
207  (output[2] /*ECX*/ == 0x444D4163) &&
208  (output[3] /*EDX*/ == 0x69746E65);
209 }
210 
211 static inline bool IsVIA(const word32 output[4])
212 {
213  // This is the "CentaurHauls" string. Some non-PadLock's can return "VIA VIA VIA "
214  return (output[1] /*EBX*/ == 0x746e6543) &&
215  (output[2] /*ECX*/ == 0x736c7561) &&
216  (output[3] /*EDX*/ == 0x48727561);
217 }
218 
219 void DetectX86Features()
220 {
221  // Coverity finding CID 171239...
222  word32 cpuid1[4]={0}, cpuid2[4]={0}, cpuid3[4]={0};
223  if (!CpuId(0, cpuid1))
224  return;
225  if (!CpuId(1, cpuid2))
226  return;
227 
228  g_hasMMX = (cpuid2[3] & (1 << 23)) != 0;
229  if ((cpuid2[3] & (1 << 26)) != 0)
230  g_hasSSE2 = TrySSE2();
231  g_hasSSSE3 = g_hasSSE2 && (cpuid2[2] & (1<<9));
232  g_hasSSE4 = g_hasSSE2 && ((cpuid2[2] & (1<<19)) && (cpuid2[2] & (1<<20)));
233  g_hasAESNI = g_hasSSE2 && (cpuid2[2] & (1<<25));
234  g_hasCLMUL = g_hasSSE2 && (cpuid2[2] & (1<<1));
235 
236  if ((cpuid2[3] & (1 << 25)) != 0)
237  g_hasISSE = true;
238  else
239  {
240  CpuId(0x080000000, cpuid3);
241  if (cpuid3[0] >= 0x080000001)
242  {
243  CpuId(0x080000001, cpuid3);
244  g_hasISSE = (cpuid3[3] & (1 << 22)) != 0;
245  }
246  }
247 
248  if (IsIntel(cpuid1))
249  {
250  static const unsigned int RDRAND_FLAG = (1 << 30);
251  static const unsigned int RDSEED_FLAG = (1 << 18);
252  static const unsigned int SHA_FLAG = (1 << 29);
253 
254  g_isP4 = ((cpuid2[0] >> 8) & 0xf) == 0xf;
255  g_cacheLineSize = 8 * GETBYTE(cpuid2[1], 1);
256  g_hasRDRAND = !!(cpuid2[2] /*ECX*/ & RDRAND_FLAG);
257 
258  if (cpuid1[0] /*EAX*/ >= 7)
259  {
260  if (CpuId(7, cpuid3))
261  {
262  g_hasRDSEED = !!(cpuid3[1] /*EBX*/ & RDSEED_FLAG);
263  g_hasSHA = !!(cpuid3[1] /*EBX*/ & SHA_FLAG);
264  }
265  }
266  }
267  else if (IsAMD(cpuid1))
268  {
269  static const unsigned int RDRAND_FLAG = (1 << 30);
270 
271  CpuId(0x01, cpuid1);
272  g_hasRDRAND = !!(cpuid1[2] /*ECX*/ & RDRAND_FLAG);
273 
274  CpuId(0x80000005, cpuid1);
275  g_cacheLineSize = GETBYTE(cpuid1[2], 0);
276  }
277  else if (IsVIA(cpuid1))
278  {
279  static const unsigned int RNG_FLAGS = (0x3 << 2);
280  static const unsigned int ACE_FLAGS = (0x3 << 6);
281  static const unsigned int ACE2_FLAGS = (0x3 << 8);
282  static const unsigned int PHE_FLAGS = (0x3 << 10);
283  static const unsigned int PMM_FLAGS = (0x3 << 12);
284 
285  CpuId(0xC0000000, cpuid1);
286  if (cpuid1[0] >= 0xC0000001)
287  {
288  // Extended features available
289  CpuId(0xC0000001, cpuid1);
290  g_hasPadlockRNG = !!(cpuid1[3] /*EDX*/ & RNG_FLAGS);
291  g_hasPadlockACE = !!(cpuid1[3] /*EDX*/ & ACE_FLAGS);
292  g_hasPadlockACE2 = !!(cpuid1[3] /*EDX*/ & ACE2_FLAGS);
293  g_hasPadlockPHE = !!(cpuid1[3] /*EDX*/ & PHE_FLAGS);
294  g_hasPadlockPMM = !!(cpuid1[3] /*EDX*/ & PMM_FLAGS);
295  }
296  }
297 
298  if (!g_cacheLineSize)
299  g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
300 
301  g_x86DetectionDone = true;
302 }
303 
304 #elif (CRYPTOPP_ARM32 || CRYPTOPP_ARM64)
305 
306 // The ARM equivalent of CPUID probing is reading a MSR. The code requires Exception Level 1 (EL1) and above, but user space runs at EL0.
307 // Attempting to run the code results in a SIGILL and termination.
308 //
309 // #if defined(__arm64__) || defined(__aarch64__)
310 // word64 caps = 0; // Read ID_AA64ISAR0_EL1
311 // __asm __volatile("mrs %0, " "id_aa64isar0_el1" : "=r" (caps));
312 // #elif defined(__arm__) || defined(__aarch32__)
313 // word32 caps = 0; // Read ID_ISAR5_EL1
314 // __asm __volatile("mrs %0, " "id_isar5_el1" : "=r" (caps));
315 // #endif
316 //
317 // The following does not work well either. Its appears to be missing constants, and it does not detect Aarch32 execution environments on Aarch64
318 // http://community.arm.com/groups/android-community/blog/2014/10/10/runtime-detection-of-cpu-features-on-an-armv8-a-cpu
319 //
320 bool CRYPTOPP_SECTION_INIT g_ArmDetectionDone = false;
321 bool CRYPTOPP_SECTION_INIT g_hasNEON = false, CRYPTOPP_SECTION_INIT g_hasPMULL = false, CRYPTOPP_SECTION_INIT g_hasCRC32 = false;
322 bool CRYPTOPP_SECTION_INIT g_hasAES = false, CRYPTOPP_SECTION_INIT g_hasSHA1 = false, CRYPTOPP_SECTION_INIT g_hasSHA2 = false;
323 word32 CRYPTOPP_SECTION_INIT g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
324 
325 #ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
326 extern "C"
327 {
328  static jmp_buf s_jmpNoNEON;
329  static void SigIllHandlerNEON(int)
330  {
331  longjmp(s_jmpNoNEON, 1);
332  }
333 
334  static jmp_buf s_jmpNoPMULL;
335  static void SigIllHandlerPMULL(int)
336  {
337  longjmp(s_jmpNoPMULL, 1);
338  }
339 
340  static jmp_buf s_jmpNoCRC32;
341  static void SigIllHandlerCRC32(int)
342  {
343  longjmp(s_jmpNoCRC32, 1);
344  }
345 
346  static jmp_buf s_jmpNoAES;
347  static void SigIllHandlerAES(int)
348  {
349  longjmp(s_jmpNoAES, 1);
350  }
351 
352  static jmp_buf s_jmpNoSHA1;
353  static void SigIllHandlerSHA1(int)
354  {
355  longjmp(s_jmpNoSHA1, 1);
356  }
357 
358  static jmp_buf s_jmpNoSHA2;
359  static void SigIllHandlerSHA2(int)
360  {
361  longjmp(s_jmpNoSHA2, 1);
362  }
363 };
364 #endif // Not CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
365 
366 static bool TryNEON()
367 {
368 #if (CRYPTOPP_NEON_AVAILABLE)
369 # if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
370  volatile bool result = true;
371  __try
372  {
373  uint32_t v1[4] = {1,1,1,1};
374  uint32x4_t x1 = vld1q_u32(v1);
375  uint64_t v2[2] = {1,1};
376  uint64x2_t x2 = vld1q_u64(v2);
377 
378  uint32x4_t x3 = vdupq_n_u32(2);
379  x3 = vsetq_lane_u32(vgetq_lane_u32(x1,0),x3,0);
380  x3 = vsetq_lane_u32(vgetq_lane_u32(x1,3),x3,3);
381  uint64x2_t x4 = vdupq_n_u64(2);
382  x4 = vsetq_lane_u64(vgetq_lane_u64(x2,0),x4,0);
383  x4 = vsetq_lane_u64(vgetq_lane_u64(x2,1),x4,1);
384 
385  result = !!(vgetq_lane_u32(x3,0) | vgetq_lane_u64(x4,1));
386  }
387  __except (EXCEPTION_EXECUTE_HANDLER)
388  {
389  return false;
390  }
391  return result;
392 # else
393  // longjmp and clobber warnings. Volatile is required.
394  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
395  volatile bool result = true;
396 
397  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandlerNEON);
398  if (oldHandler == SIG_ERR)
399  return false;
400 
401  volatile sigset_t oldMask;
402  if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
403  return false;
404 
405  if (setjmp(s_jmpNoNEON))
406  result = false;
407  else
408  {
409  uint32_t v1[4] = {1,1,1,1};
410  uint32x4_t x1 = vld1q_u32(v1);
411  uint64_t v2[2] = {1,1};
412  uint64x2_t x2 = vld1q_u64(v2);
413 
414  uint32x4_t x3 = {0,0,0,0};
415  x3 = vsetq_lane_u32(vgetq_lane_u32(x1,0),x3,0);
416  x3 = vsetq_lane_u32(vgetq_lane_u32(x1,3),x3,3);
417  uint64x2_t x4 = {0,0};
418  x4 = vsetq_lane_u64(vgetq_lane_u64(x2,0),x4,0);
419  x4 = vsetq_lane_u64(vgetq_lane_u64(x2,1),x4,1);
420 
421  // Hack... GCC optimizes away the code and returns true
422  result = !!(vgetq_lane_u32(x3,0) | vgetq_lane_u64(x4,1));
423  }
424 
425  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
426  signal(SIGILL, oldHandler);
427  return result;
428 # endif
429 #else
430  return false;
431 #endif // CRYPTOPP_NEON_AVAILABLE
432 }
433 
434 static bool TryPMULL()
435 {
436 #if (CRYPTOPP_ARM_PMULL_AVAILABLE)
437 # if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
438  volatile bool result = true;
439  __try
440  {
441  const poly64_t a1={0x9090909090909090}, b1={0xb0b0b0b0b0b0b0b0};
442  const poly8x16_t a2={0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0},
443  b2={0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0};
444 
445  const poly128_t r1 = vmull_p64(a1, b1);
446  const poly128_t r2 = vmull_high_p64((poly64x2_t)(a2), (poly64x2_t)(b2));
447 
448  // Linaro is missing vreinterpretq_u64_p128. Also see http://github.com/weidai11/cryptopp/issues/233.
449  const uint64x2_t& t1 = (uint64x2_t)(r1); // {bignum,bignum}
450  const uint64x2_t& t2 = (uint64x2_t)(r2); // {bignum,bignum}
451 
452  result = !!(vgetq_lane_u64(t1,0) == 0x5300530053005300 && vgetq_lane_u64(t1,1) == 0x5300530053005300 &&
453  vgetq_lane_u64(t2,0) == 0x6c006c006c006c00 && vgetq_lane_u64(t2,1) == 0x6c006c006c006c00);
454  }
455  __except (EXCEPTION_EXECUTE_HANDLER)
456  {
457  return false;
458  }
459  return result;
460 # else
461  // longjmp and clobber warnings. Volatile is required.
462  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
463  volatile bool result = true;
464 
465  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandlerPMULL);
466  if (oldHandler == SIG_ERR)
467  return false;
468 
469  volatile sigset_t oldMask;
470  if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
471  return false;
472 
473  if (setjmp(s_jmpNoPMULL))
474  result = false;
475  else
476  {
477  const poly64_t a1={0x9090909090909090}, b1={0xb0b0b0b0b0b0b0b0};
478  const poly8x16_t a2={0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0},
479  b2={0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0};
480 
481  const poly128_t r1 = vmull_p64(a1, b1);
482  const poly128_t r2 = vmull_high_p64((poly64x2_t)(a2), (poly64x2_t)(b2));
483 
484  // Linaro is missing vreinterpretq_u64_p128. Also see http://github.com/weidai11/cryptopp/issues/233.
485  const uint64x2_t& t1 = (uint64x2_t)(r1); // {bignum,bignum}
486  const uint64x2_t& t2 = (uint64x2_t)(r2); // {bignum,bignum}
487 
488  result = !!(vgetq_lane_u64(t1,0) == 0x5300530053005300 && vgetq_lane_u64(t1,1) == 0x5300530053005300 &&
489  vgetq_lane_u64(t2,0) == 0x6c006c006c006c00 && vgetq_lane_u64(t2,1) == 0x6c006c006c006c00);
490  }
491 
492  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
493  signal(SIGILL, oldHandler);
494  return result;
495 # endif
496 #else
497  return false;
498 #endif // CRYPTOPP_ARM_CRYPTO_AVAILABLE
499 }
500 
501 static bool TryCRC32()
502 {
503 #if (CRYPTOPP_ARM_CRC32_AVAILABLE)
504 # if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
505  volatile bool result = true;
506  __try
507  {
508  word32 w=1, x=2; word16 y=3; byte z=4;
509  w = CRC32W(w,x);
510  w = CRC32H(w,y);
511  w = CRC32B(w,z);
512 
513  w = CRC32CW(w,x);
514  w = CRC32CH(w,y);
515  w = CRC32CB(w,z);
516 
517  result = (w != 0);
518  }
519  __except (EXCEPTION_EXECUTE_HANDLER)
520  {
521  return false;
522  }
523  return result;
524 # else
525  // longjmp and clobber warnings. Volatile is required.
526  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
527  volatile bool result = true;
528 
529  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandlerCRC32);
530  if (oldHandler == SIG_ERR)
531  return false;
532 
533  volatile sigset_t oldMask;
534  if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
535  return false;
536 
537  if (setjmp(s_jmpNoCRC32))
538  result = false;
539  else
540  {
541  word32 w=1, x=2; word16 y=3; byte z=4;
542  w = CRC32W(w,x);
543  w = CRC32H(w,y);
544  w = CRC32B(w,z);
545 
546  w = CRC32CW(w,x);
547  w = CRC32CH(w,y);
548  w = CRC32CB(w,z);
549 
550  result = (w != 0);
551  }
552 
553  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
554  signal(SIGILL, oldHandler);
555  return result;
556 # endif
557 #else
558  return false;
559 #endif // CRYPTOPP_ARM_CRC32_AVAILABLE
560 }
561 
562 static bool TryAES()
563 {
564 #if (CRYPTOPP_ARM_CRYPTO_AVAILABLE)
565 # if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
566  volatile bool result = true;
567  __try
568  {
569  // AES encrypt and decrypt
570  uint8x16_t data = vdupq_n_u8(0), key = vdupq_n_u8(0);
571  uint8x16_t r1 = vaeseq_u8(data, key);
572  uint8x16_t r2 = vaesdq_u8(data, key);
573 
574  result = !!(vgetq_lane_u8(r1,0) | vgetq_lane_u8(r2,7));
575  }
576  __except (EXCEPTION_EXECUTE_HANDLER)
577  {
578  return false;
579  }
580  return result;
581 # else
582  // longjmp and clobber warnings. Volatile is required.
583  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
584  volatile bool result = true;
585 
586  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandlerAES);
587  if (oldHandler == SIG_ERR)
588  return false;
589 
590  volatile sigset_t oldMask;
591  if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
592  return false;
593 
594  if (setjmp(s_jmpNoAES))
595  result = false;
596  else
597  {
598  uint8x16_t data = vdupq_n_u8(0), key = vdupq_n_u8(0);
599  uint8x16_t r1 = vaeseq_u8(data, key);
600  uint8x16_t r2 = vaesdq_u8(data, key);
601 
602  // Hack... GCC optimizes away the code and returns true
603  result = !!(vgetq_lane_u8(r1,0) | vgetq_lane_u8(r2,7));
604  }
605 
606  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
607  signal(SIGILL, oldHandler);
608  return result;
609 # endif
610 #else
611  return false;
612 #endif // CRYPTOPP_ARM_CRYPTO_AVAILABLE
613 }
614 
615 static bool TrySHA1()
616 {
617 #if (CRYPTOPP_ARM_CRYPTO_AVAILABLE)
618 # if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
619  volatile bool result = true;
620  __try
621  {
622  uint32x4_t data1 = {1,2,3,4}, data2 = {5,6,7,8}, data3 = {9,10,11,12};
623 
624  uint32x4_t r1 = vsha1cq_u32 (data1, 0, data2);
625  uint32x4_t r2 = vsha1mq_u32 (data1, 0, data2);
626  uint32x4_t r3 = vsha1pq_u32 (data1, 0, data2);
627  uint32x4_t r4 = vsha1su0q_u32 (data1, data2, data3);
628  uint32x4_t r5 = vsha1su1q_u32 (data1, data2);
629 
630  result = !!(vgetq_lane_u32(r1,0) | vgetq_lane_u32(r2,1) | vgetq_lane_u32(r3,2) | vgetq_lane_u32(r4,3) | vgetq_lane_u32(r5,0));
631  }
632  __except (EXCEPTION_EXECUTE_HANDLER)
633  {
634  return false;
635  }
636  return result;
637 # else
638  // longjmp and clobber warnings. Volatile is required.
639  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
640  volatile bool result = true;
641 
642  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandlerSHA1);
643  if (oldHandler == SIG_ERR)
644  return false;
645 
646  volatile sigset_t oldMask;
647  if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
648  return false;
649 
650  if (setjmp(s_jmpNoSHA1))
651  result = false;
652  else
653  {
654  uint32x4_t data1 = {1,2,3,4}, data2 = {5,6,7,8}, data3 = {9,10,11,12};
655 
656  uint32x4_t r1 = vsha1cq_u32 (data1, 0, data2);
657  uint32x4_t r2 = vsha1mq_u32 (data1, 0, data2);
658  uint32x4_t r3 = vsha1pq_u32 (data1, 0, data2);
659  uint32x4_t r4 = vsha1su0q_u32 (data1, data2, data3);
660  uint32x4_t r5 = vsha1su1q_u32 (data1, data2);
661 
662  // Hack... GCC optimizes away the code and returns true
663  result = !!(vgetq_lane_u32(r1,0) | vgetq_lane_u32(r2,1) | vgetq_lane_u32(r3,2) | vgetq_lane_u32(r4,3) | vgetq_lane_u32(r5,0));
664  }
665 
666  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
667  signal(SIGILL, oldHandler);
668  return result;
669 # endif
670 #else
671  return false;
672 #endif // CRYPTOPP_ARM_CRYPTO_AVAILABLE
673 }
674 
675 static bool TrySHA2()
676 {
677 #if (CRYPTOPP_ARM_CRYPTO_AVAILABLE)
678 # if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
679  volatile bool result = true;
680  __try
681  {
682  uint32x4_t data1 = {1,2,3,4}, data2 = {5,6,7,8}, data3 = {9,10,11,12};
683 
684  uint32x4_t r1 = vsha256hq_u32 (data1, data2, data3);
685  uint32x4_t r2 = vsha256h2q_u32 (data1, data2, data3);
686  uint32x4_t r3 = vsha256su0q_u32 (data1, data2);
687  uint32x4_t r4 = vsha256su1q_u32 (data1, data2, data3);
688 
689  result = !!(vgetq_lane_u32(r1,0) | vgetq_lane_u32(r2,1) | vgetq_lane_u32(r3,2) | vgetq_lane_u32(r4,3));
690  }
691  __except (EXCEPTION_EXECUTE_HANDLER)
692  {
693  return false;
694  }
695  return result;
696 # else
697  // longjmp and clobber warnings. Volatile is required.
698  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
699  volatile bool result = true;
700 
701  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandlerSHA2);
702  if (oldHandler == SIG_ERR)
703  return false;
704 
705  volatile sigset_t oldMask;
706  if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
707  return false;
708 
709  if (setjmp(s_jmpNoSHA2))
710  result = false;
711  else
712  {
713  uint32x4_t data1 = {1,2,3,4}, data2 = {5,6,7,8}, data3 = {9,10,11,12};
714 
715  uint32x4_t r1 = vsha256hq_u32 (data1, data2, data3);
716  uint32x4_t r2 = vsha256h2q_u32 (data1, data2, data3);
717  uint32x4_t r3 = vsha256su0q_u32 (data1, data2);
718  uint32x4_t r4 = vsha256su1q_u32 (data1, data2, data3);
719 
720  // Hack... GCC optimizes away the code and returns true
721  result = !!(vgetq_lane_u32(r1,0) | vgetq_lane_u32(r2,1) | vgetq_lane_u32(r3,2) | vgetq_lane_u32(r4,3));
722  }
723 
724  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
725  signal(SIGILL, oldHandler);
726  return result;
727 # endif
728 #else
729  return false;
730 #endif // CRYPTOPP_ARM_CRYPTO_AVAILABLE
731 }
732 
733 void DetectArmFeatures()
734 {
735  g_hasNEON = TryNEON();
736  g_hasPMULL = TryPMULL();
737  g_hasCRC32 = TryCRC32();
738  g_hasAES = TryAES();
739  g_hasSHA1 = TrySHA1();
740  g_hasSHA2 = TrySHA2();
741 
742  g_ArmDetectionDone = true;
743 }
744 
745 #endif
746 NAMESPACE_END
747 
748 // ***************** C++ Static Initialization ********************
749 
750 ANONYMOUS_NAMESPACE_BEGIN
751 struct InitializeCpu
752 {
753  InitializeCpu()
754  {
755 #if CRYPTOPP_X86 || CRYPTOPP_X32 || CRYPTOPP_X64
756  CryptoPP::DetectX86Features();
757 #elif CRYPTOPP_ARM32 || CRYPTOPP_ARM64
758  CryptoPP::DetectArmFeatures();
759 #endif
760  }
761 };
762 
763 #if HAVE_GCC_INIT_PRIORITY
764 const InitializeCpu s_init __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 20))) = InitializeCpu();
765 #elif HAVE_MSC_INIT_PRIORITY
766 #pragma warning(disable: 4075)
767 #pragma init_seg(".CRT$XCU-020")
768 const InitializeCpu s_init;
769 #pragma warning(default: 4075)
770 #else
771 const InitializeCpu& s_init = CryptoPP::Singleton<InitializeCpu>().Ref();
772 #endif
773 ANONYMOUS_NAMESPACE_END
774 
775 #endif // CRYPTOPP_IMPORTS
Utility functions for the Crypto++ library.
Library configuration file.
Functions for CPU features and intrinsics.
Crypto++ library namespace.