1 /** 2 * Entropy Source Using Intel's rdrand instruction 3 * 4 * Copyright: 5 * (C) 2012 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 8 * License: 9 * Botan is released under the Simplified BSD License (see LICENSE.md) 10 */ 11 module botan.entropy.rdrand; 12 13 import botan.constants; 14 static if (BOTAN_HAS_ENTROPY_SRC_RDRAND): 15 16 import botan.entropy.entropy_src; 17 import botan.utils.cpuid; 18 19 //import botan.utils.simd.immintrin; 20 21 /** 22 * Entropy source using the rdrand instruction first introduced on 23 * Intel's Ivy Bridge architecture. 24 */ 25 final class IntelRdrand : EntropySource 26 { 27 public: 28 @property string name() const { return "Intel Rdrand"; } 29 /* 30 * Get the timestamp 31 */ 32 void poll(ref EntropyAccumulator accum) 33 { 34 if (!CPUID.hasRdrand()) 35 return; 36 37 /* 38 * Put an upper bound on the total entropy we're willing to claim 39 * for any one polling of rdrand to prevent it from swamping our 40 * poll. Internally, the rdrand system is a DRGB that reseeds at a 41 * somewhat unpredictable rate (the current conditions are 42 * documented, but that might not be true for different 43 * implementations, eg on Haswell or a future AMD chip, so I don't 44 * want to assume). This limit ensures we're going to poll at least 45 * one other source so we have some diversity in our inputs. 46 */ 47 48 __gshared immutable size_t POLL_UPPER_BOUND = 96; 49 __gshared immutable size_t RDRAND_POLLS = 32; 50 __gshared immutable double ENTROPY_PER_POLL = cast(double)(POLL_UPPER_BOUND) / (RDRAND_POLLS * 4); 51 52 foreach (size_t i; 0 .. RDRAND_POLLS) 53 { 54 uint r = 0; 55 int cf = _rdrand32_step(&r); 56 57 if (cf == 1) 58 accum.add(r, ENTROPY_PER_POLL); 59 } 60 } 61 } 62 63 version(D_InlineAsm_X86) { 64 65 // todo: move this to another module 66 int _rdrand32_step(uint* r) { 67 int ret; 68 69 asm 70 { 71 mov EAX, ret; 72 rdrand EAX; 73 mov ret, EAX; 74 } 75 if (ret != 0) 76 *r = ret; 77 else 78 return 0; 79 return 1; 80 } 81 82 } 83 version(GDC) { 84 static import gcc.attribute; 85 import gcc.builtins; 86 enum inline = gcc.attribute.attribute("forceinline"); 87 88 @inline 89 int _rdrand32_step(uint* i) { 90 return __builtin_ia32_rdrand32_step(i); 91 } 92 93 } 94 95 version(none) { 96 pragma(LDC_intrinsic, "llvm.x86.rdrand.32") 97 int _rdrand32_step(uint*); 98 } 99 100 version(D_InlineAsm_X86_64) { 101 102 // todo: move this to another module 103 int _rdrand32_step(uint* r) { 104 int ret; 105 //(for LDC) rdrand EAX => db 0x0F, 0xC7, 0xF0 106 asm 107 { 108 mov EAX, ret; 109 db 0x0F, 0xC7, 0xF0; 110 mov ret, EAX; 111 } 112 if (ret != 0) 113 *r = ret; 114 else 115 return 0; 116 return 1; 117 } 118 119 }