rdrand.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. /* Copyright © 2012, Intel Corporation. All rights reserved.
  2. Redistribution and use in source and binary forms, with or without
  3. modification, are permitted provided that the following conditions are met:
  4. - Redistributions of source code must retain the above copyright notice,
  5. this list of conditions and the following disclaimer.
  6. - Redistributions in binary form must reproduce the above copyright
  7. notice, this list of conditions and the following disclaimer in the
  8. documentation and/or other materials provided with the distribution.
  9. - Neither the name of Intel Corporation nor the names of its contributors
  10. may be used to endorse or promote products derived from this software
  11. without specific prior written permission.
  12. THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY EXPRESS OR
  13. IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  14. MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
  15. EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  16. SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  17. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  18. BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  19. IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  20. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  21. POSSIBILITY OF SUCH DAMAGE. */
  22. #include "rdrand.h"
  23. #ifdef __INTEL_COMPILER
  24. # include <immintrin.h>
  25. #endif
  26. #include <string.h>
  27. #include <stdint.h>
  28. /*! \def RDRAND_MASK
  29. * The bit mask used to examine the ecx register returned by cpuid. The
  30. * 30th bit is set.
  31. */
  32. #define RDRAND_MASK 0x40000000
  33. #define RETRY_LIMIT 10
  34. #if defined(_WIN64)||defined(_LP64)
  35. # define _IS64BIT
  36. #endif
  37. #ifdef _IS64BIT
  38. typedef uint64_t _wordlen_t;
  39. #else
  40. typedef uint32_t _wordlen_t;
  41. #endif
  42. /* Mimic the Intel compiler's intrinsics as best we can if we are using gcc */
  43. #ifdef __GNUC__
  44. # define __cpuid(x,y) asm volatile("cpuid":"=a"(x[0]),"=b"(x[1]),"=c"(x[2]),"=d"(x[3]):"a"(y))
  45. /* RDRAND isn't a supported instruction until gcc 4.6 */
  46. # ifdef HAVE_RDRAND_IN_GCC
  47. # define _rdrand_step(x) ({ unsigned char err; asm volatile("rdrand %0; setc %1":"=r"(*x), "=qm"(err)); err; })
  48. # define _rdrand16_step(x) _rdrand_step(x)
  49. # define _rdrand32_step(x) _rdrand_step(x)
  50. # else
  51. /* Our version of gcc is too old, so we need to use byte code */
  52. # define _rdrand16_step(x) ({ unsigned char err; asm volatile(".byte 0x66; .byte 0x0f; .byte 0xc7; .byte 0xf0; setc %1":"=a"(*x), "=qm"(err)); err; })
  53. # define _rdrand32_step(x) ({ unsigned char err; asm volatile(".byte 0x0f; .byte 0xc7; .byte 0xf0; setc %1":"=a"(*x), "=qm"(err)); err; })
  54. # endif
  55. #ifdef _IS64BIT
  56. # ifdef HAVE_RDRAND_IN_GCC
  57. # define _rdrand64_step(x) _rdrand_step(x)
  58. # else
  59. /* Our version of gcc is too old, so we need to use byte code */
  60. # define _rdrand64_step(x) ({ unsigned char err; asm volatile(".byte 0x48; .byte 0x0f; .byte 0xc7; .byte 0xf0; setc %1":"=a"(*x), "=qm"(err)); err; })
  61. # endif
  62. #else
  63. /*
  64. * The Intel compiler intrinsic for generating a 64-bit rand on a 32-bit
  65. * system maps to two 32-bit RDRAND instructions. Because of the way
  66. * the way the DRNG is implemented you can do this up to a 128-bit value
  67. * (for crypto purposes) before you no longer have multiplicative
  68. * prediction resistance.
  69. *
  70. * Note that this isn't very efficient. If you need 64-bit values
  71. * you should really be on a 64-bit system.
  72. */
  73. int _rdrand64_step (uint64_t *x);
  74. int _rdrand64_step (uint64_t *x)
  75. {
  76. uint32_t xlow, xhigh;
  77. int rv;
  78. if ( (rv= _rdrand32_step(&xlow)) != RDRAND_SUCCESS ) return rv;
  79. if ( (rv= _rdrand32_step(&xhigh)) != RDRAND_SUCCESS ) return rv;
  80. *x= (uint64_t) xlow | ((uint64_t)xhigh<<32);
  81. return RDRAND_SUCCESS;
  82. }
  83. # endif
  84. #endif
  85. /*! \brief Queries cpuid to see if rdrand is supported
  86. *
  87. * rdrand support in a CPU is determined by examining the 30th bit of the ecx
  88. * register after calling cpuid.
  89. *
  90. * \return bool of whether or not rdrand is supported
  91. */
  92. int RdRand_cpuid()
  93. {
  94. int info[4] = {-1, -1, -1, -1};
  95. /* Are we on an Intel processor? */
  96. __cpuid(info, 0);
  97. if ( memcmp((void *) &info[1], (void *) "Genu", 4) != 0 ||
  98. memcmp((void *) &info[3], (void *) "ineI", 4) != 0 ||
  99. memcmp((void *) &info[2], (void *) "ntel", 4) != 0 ) {
  100. return 0;
  101. }
  102. /* Do we have RDRAND? */
  103. __cpuid(info, /*feature bits*/1);
  104. int ecx = info[2];
  105. if ((ecx & RDRAND_MASK) == RDRAND_MASK)
  106. return 1;
  107. else
  108. return 0;
  109. }
  110. /*! \brief Determines whether or not rdrand is supported by the CPU
  111. *
  112. * This function simply serves as a cache of the result provided by cpuid,
  113. * since calling cpuid is so expensive. The result is stored in a static
  114. * variable to save from calling cpuid on each invocation of rdrand.
  115. *
  116. * \return bool/int of whether or not rdrand is supported
  117. */
  118. int RdRand_isSupported()
  119. {
  120. static int supported = RDRAND_SUPPORT_UNKNOWN;
  121. if (supported == RDRAND_SUPPORT_UNKNOWN)
  122. {
  123. if (RdRand_cpuid())
  124. supported = RDRAND_SUPPORTED;
  125. else
  126. supported = RDRAND_UNSUPPORTED;
  127. }
  128. return (supported == RDRAND_SUPPORTED) ? 1 : 0;
  129. }
  130. int rdrand_16(uint16_t* x, int retry)
  131. {
  132. if (RdRand_isSupported())
  133. {
  134. if (retry)
  135. {
  136. int i;
  137. for (i = 0; i < RETRY_LIMIT; i++)
  138. {
  139. if (_rdrand16_step(x))
  140. return RDRAND_SUCCESS;
  141. }
  142. return RDRAND_NOT_READY;
  143. }
  144. else
  145. {
  146. if (_rdrand16_step(x))
  147. return RDRAND_SUCCESS;
  148. else
  149. return RDRAND_NOT_READY;
  150. }
  151. }
  152. else
  153. {
  154. return RDRAND_UNSUPPORTED;
  155. }
  156. }
  157. int rdrand_32(uint32_t* x, int retry)
  158. {
  159. if (RdRand_isSupported())
  160. {
  161. if (retry)
  162. {
  163. int i;
  164. for (i= 0; i < RETRY_LIMIT; i++)
  165. {
  166. if (_rdrand32_step(x))
  167. return RDRAND_SUCCESS;
  168. }
  169. return RDRAND_NOT_READY;
  170. }
  171. else
  172. {
  173. if (_rdrand32_step(x))
  174. return RDRAND_SUCCESS;
  175. else
  176. return RDRAND_NOT_READY;
  177. }
  178. }
  179. else
  180. {
  181. return RDRAND_UNSUPPORTED;
  182. }
  183. }
  184. int rdrand_64(uint64_t* x, int retry)
  185. {
  186. if (RdRand_isSupported())
  187. {
  188. if (retry)
  189. {
  190. int i;
  191. for (i= 0; i < RETRY_LIMIT; i++)
  192. {
  193. if (_rdrand64_step(x))
  194. return RDRAND_SUCCESS;
  195. }
  196. return RDRAND_NOT_READY;
  197. }
  198. else
  199. {
  200. if (_rdrand64_step(x))
  201. return RDRAND_SUCCESS;
  202. else
  203. return RDRAND_NOT_READY;
  204. }
  205. }
  206. else
  207. {
  208. return RDRAND_UNSUPPORTED;
  209. }
  210. }
  211. int rdrand_get_n_64(unsigned int n, uint64_t *dest)
  212. {
  213. int success;
  214. int count;
  215. unsigned int i;
  216. for (i=0; i<n; i++)
  217. {
  218. count = 0;
  219. do
  220. {
  221. success= rdrand_64(dest, 1);
  222. } while((success == 0) && (count++ < RETRY_LIMIT));
  223. if (success != RDRAND_SUCCESS) return success;
  224. dest= &(dest[1]);
  225. }
  226. return RDRAND_SUCCESS;
  227. }
  228. int rdrand_get_n_32(unsigned int n, uint32_t *dest)
  229. {
  230. int success;
  231. int count;
  232. unsigned int i;
  233. for (i=0; i<n; i++)
  234. {
  235. count = 0;
  236. do
  237. {
  238. success= rdrand_32(dest, 1);
  239. } while((success == 0) && (count++ < RETRY_LIMIT));
  240. if (success != RDRAND_SUCCESS) return success;
  241. dest= &(dest[1]);
  242. }
  243. return RDRAND_SUCCESS;
  244. }
  245. int rdrand_get_bytes(unsigned int n, unsigned char *dest)
  246. {
  247. unsigned char *start;
  248. unsigned char *residualstart;
  249. _wordlen_t *blockstart;
  250. _wordlen_t i, temprand;
  251. unsigned int count;
  252. unsigned int residual;
  253. unsigned int startlen;
  254. unsigned int length;
  255. int success;
  256. /* Compute the address of the first 32- or 64- bit aligned block in the destination buffer, depending on whether we are in 32- or 64-bit mode */
  257. start = dest;
  258. if (((_wordlen_t) start % (_wordlen_t) sizeof(_wordlen_t)) == 0)
  259. {
  260. blockstart = (_wordlen_t *)start;
  261. count = n;
  262. startlen = 0;
  263. }
  264. else
  265. {
  266. blockstart = (_wordlen_t *)(((_wordlen_t)start & ~(_wordlen_t) (sizeof(_wordlen_t)-1) )+(_wordlen_t)sizeof(_wordlen_t));
  267. count = n - (sizeof(_wordlen_t) - (unsigned int)((_wordlen_t)start % sizeof(_wordlen_t)));
  268. startlen = (unsigned int)((_wordlen_t)blockstart - (_wordlen_t)start);
  269. }
  270. /* Compute the number of 32- or 64- bit blocks and the remaining number of bytes */
  271. residual = count % sizeof(_wordlen_t);
  272. length = count/sizeof(_wordlen_t);
  273. if (residual != 0)
  274. {
  275. residualstart = (unsigned char *)(blockstart + length);
  276. }
  277. /* Get a temporary random number for use in the residuals. Failout if retry fails */
  278. if (startlen > 0)
  279. {
  280. #ifdef _IS64BIT
  281. if ( (success= rdrand_64((uint64_t *) &temprand, 1)) != RDRAND_SUCCESS) return success;
  282. #else
  283. if ( (success= rdrand_32((uint32_t *) &temprand, 1)) != RDRAND_SUCCESS) return success;
  284. #endif
  285. }
  286. /* populate the starting misaligned block */
  287. for (i = 0; i<startlen; i++)
  288. {
  289. start[i] = (unsigned char)(temprand & 0xff);
  290. temprand = temprand >> 8;
  291. }
  292. /* populate the central aligned block. Fail out if retry fails */
  293. #ifdef _IS64BIT
  294. if ( (success= rdrand_get_n_64(length, (uint64_t *)(blockstart))) != RDRAND_SUCCESS) return success;
  295. #else
  296. if ( (success= rdrand_get_n_32(length, (uint32_t *)(blockstart))) != RDRAND_SUCCESS) return success;
  297. #endif
  298. /* populate the final misaligned block */
  299. if (residual > 0)
  300. {
  301. #ifdef _IS64BIT
  302. if ((success= rdrand_64((uint64_t *)&temprand, 1)) != RDRAND_SUCCESS) return success;
  303. #else
  304. if ((success= rdrand_32((uint32_t *)&temprand, 1)) != RDRAND_SUCCESS) return success;
  305. #endif
  306. for (i = 0; i<residual; i++)
  307. {
  308. residualstart[i] = (unsigned char)(temprand & 0xff);
  309. temprand = temprand >> 8;
  310. }
  311. }
  312. return RDRAND_SUCCESS;
  313. }