Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

515 lines
14 KiB

  1. // rdrand.cpp - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
  2. // Copyright assigned to Crypto++ project.
  3. #include "pch.h"
  4. #include "config.h"
  5. #include "cryptlib.h"
  6. #include "secblock.h"
  7. #include "rdrand.h"
  8. #include "cpu.h"
  9. #if CRYPTOPP_MSC_VERSION
  10. # pragma warning(disable: 4100)
  11. #endif
  12. // This file (and friends) provides both RDRAND and RDSEED, but its somewhat
  13. // experimental. They were added at Crypto++ 5.6.3. At compile time, it
  14. // indirectly uses CRYPTOPP_BOOL_{X86|X32|X64} (via CRYPTOPP_CPUID_AVAILABLE)
  15. // to select an implementation or "throw NotImplemented". At runtime, the
  16. // class uses the result of CPUID to determine if RDRAND or RDSEED are
  17. // available. A lazy throw strategy is used in case the CPU does not support
  18. // the instruction. I.e., the throw is deferred until GenerateBlock is called.
  19. // Here's the naming convention for the functions....
  20. // MSC = Microsoft Compiler (and compatibles)
  21. // GCC = GNU Compiler (and compatibles)
  22. // ALL = MSC and GCC (and compatibles)
  23. // RRA = RDRAND, Assembly
  24. // RSA = RDSEED, Assembly
  25. // RRI = RDRAND, Intrinsic
  26. // RSA = RDSEED, Intrinsic
  27. /////////////////////////////////////////////////////////////////////
  28. /////////////////////////////////////////////////////////////////////
  29. // For Linux, install NASM, run rdrand-nasm.asm, add the apppropriate
  30. // object file to the Makefile's LIBOBJS (rdrand-x{86|32|64}.o). After
  31. // that, define these. They are not enabled by default because they
  32. // are not easy to cut-in in the Makefile.
  33. #if 0
  34. #define NASM_RDRAND_ASM_AVAILABLE 1
  35. #define NASM_RDSEED_ASM_AVAILABLE 1
  36. #endif
  37. /////////////////////////////////////////////////////////////////////
  38. /////////////////////////////////////////////////////////////////////
  39. // According to Wei, CRYPTOPP_DISABLE_ASM is a failsafe due to the assembler.
  40. // We sidestep it because it does not limit us. The assembler does not limit
  41. // us because we emit out own byte codes as needed. To diasble RDRAND or
  42. // RDSEED, set CRYPTOPP_BOOL_RDRAND_ASM or CRYPTOPP_BOOL_RDSEED_ASM to 0.
  43. #ifndef CRYPTOPP_CPUID_AVAILABLE
  44. # if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
  45. # define CRYPTOPP_CPUID_AVAILABLE
  46. # endif
  47. #endif
  48. #if defined(CRYPTOPP_CPUID_AVAILABLE) && !defined(CRYPTOPP_BOOL_RDRAND_ASM)
  49. # define CRYPTOPP_BOOL_RDRAND_ASM 1
  50. #else
  51. # define CRYPTOPP_BOOL_RDRAND_ASM 0
  52. #endif
  53. #if defined(CRYPTOPP_CPUID_AVAILABLE) && !defined(CRYPTOPP_BOOL_RDSEED_ASM)
  54. # define CRYPTOPP_BOOL_RDSEED_ASM 1
  55. #else
  56. # define CRYPTOPP_BOOL_RDSEED_ASM 0
  57. #endif
  58. #if defined(CRYPTOPP_CPUID_AVAILABLE)
  59. # define MSC_INTRIN_COMPILER ((CRYPTOPP_MSC_VERSION >= 1700) || (CRYPTOPP_CLANG_VERSION >= 30200) || (_INTEL_COMPILER >= 1210))
  60. # define GCC_INTRIN_COMPILER ((CRYPTOPP_GCC_VERSION >= 40600) || (CRYPTOPP_CLANG_VERSION >= 30200) || (_INTEL_COMPILER >= 1210))
  61. #else
  62. # define MSC_INTRIN_COMPILER 0
  63. # define GCC_INTRIN_COMPILER 0
  64. #endif
  65. // In general, the library's ASM code is best on Windows, and Intrinsics is
  66. // the best code under GCC and compatibles. We favor them accordingly.
  67. // The NASM code is optimized well on Linux, but its not easy to cut-in.
  68. #if defined(CRYPTOPP_CPUID_AVAILABLE) && (CRYPTOPP_MSC_VERSION >= 1200)
  69. # if CRYPTOPP_BOOL_RDRAND_ASM
  70. # define MASM_RDRAND_ASM_AVAILABLE 1
  71. # elif MSC_INTRIN_COMPILER
  72. # define ALL_RDRAND_INTRIN_AVAILABLE 1
  73. # endif
  74. # if CRYPTOPP_BOOL_RDSEED_ASM
  75. # define MASM_RDSEED_ASM_AVAILABLE 1
  76. # elif MSC_INTRIN_COMPILER
  77. # define ALL_RDSEED_INTRIN_AVAILABLE 1
  78. # endif
  79. #elif defined(CRYPTOPP_CPUID_AVAILABLE) && (CRYPTOPP_GCC_VERSION >= 30200)
  80. # if GCC_INTRIN_COMPILER && defined(__RDRND__)
  81. # define ALL_RDRAND_INTRIN_AVAILABLE 1
  82. # elif CRYPTOPP_BOOL_RDRAND_ASM
  83. # define GCC_RDRAND_ASM_AVAILABLE 1
  84. # endif
  85. # if GCC_INTRIN_COMPILER && defined(__RDSEED__)
  86. # define ALL_RDSEED_INTRIN_AVAILABLE 1
  87. # elif CRYPTOPP_BOOL_RDSEED_ASM
  88. # define GCC_RDSEED_ASM_AVAILABLE 1
  89. # endif
  90. #endif
  91. // Debug diagnostics
  92. #if 0
  93. # if MASM_RDRAND_ASM_AVAILABLE
  94. # pragma message ("MASM_RDRAND_ASM_AVAILABLE is 1")
  95. # elif NASM_RDRAND_ASM_AVAILABLE
  96. # pragma message ("NASM_RDRAND_ASM_AVAILABLE is 1")
  97. # elif GCC_RDRAND_ASM_AVAILABLE
  98. # pragma message ("GCC_RDRAND_ASM_AVAILABLE is 1")
  99. # elif ALL_RDRAND_INTRIN_AVAILABLE
  100. # pragma message ("ALL_RDRAND_INTRIN_AVAILABLE is 1")
  101. # else
  102. # pragma message ("RDRAND is not available")
  103. # endif
  104. # if MASM_RDSEED_ASM_AVAILABLE
  105. # pragma message ("MASM_RDSEED_ASM_AVAILABLE is 1")
  106. # elif NASM_RDSEED_ASM_AVAILABLE
  107. # pragma message ("NASM_RDSEED_ASM_AVAILABLE is 1")
  108. # elif GCC_RDSEED_ASM_AVAILABLE
  109. # pragma message ("GCC_RDSEED_ASM_AVAILABLE is 1")
  110. # elif ALL_RDSEED_INTRIN_AVAILABLE
  111. # pragma message ("ALL_RDSEED_INTRIN_AVAILABLE is 1")
  112. # else
  113. # pragma message ("RDSEED is not available")
  114. # endif
  115. #endif
  116. /////////////////////////////////////////////////////////////////////
  117. /////////////////////////////////////////////////////////////////////
  118. #if (ALL_RDRAND_INTRIN_AVAILABLE || ALL_RDSEED_INTRIN_AVAILABLE)
  119. # include <immintrin.h> // rdrand, MSC, ICC, and GCC
  120. # if defined(__has_include)
  121. # if __has_include(<x86intrin.h>)
  122. # include <x86intrin.h> // rdseed for some compilers, like GCC
  123. # endif
  124. # endif
  125. #endif
  126. #if MASM_RDRAND_ASM_AVAILABLE
  127. # ifdef _M_X64
  128. extern "C" int CRYPTOPP_FASTCALL MASM_RRA_GenerateBlock(byte*, size_t, unsigned int);
  129. // # pragma comment(lib, "rdrand-x64.lib")
  130. # else
  131. extern "C" int MASM_RRA_GenerateBlock(byte*, size_t, unsigned int);
  132. // # pragma comment(lib, "rdrand-x86.lib")
  133. # endif
  134. #endif
  135. #if MASM_RDSEED_ASM_AVAILABLE
  136. # ifdef _M_X64
  137. extern "C" int CRYPTOPP_FASTCALL MASM_RSA_GenerateBlock(byte*, size_t, unsigned int);
  138. // # pragma comment(lib, "rdrand-x64.lib")
  139. # else
  140. extern "C" int MASM_RSA_GenerateBlock(byte*, size_t, unsigned int);
  141. // # pragma comment(lib, "rdrand-x86.lib")
  142. # endif
  143. #endif
  144. #if NASM_RDRAND_ASM_AVAILABLE
  145. extern "C" int NASM_RRA_GenerateBlock(byte*, size_t, unsigned int);
  146. #endif
  147. #if NASM_RDSEED_ASM_AVAILABLE
  148. extern "C" int NASM_RSA_GenerateBlock(byte*, size_t, unsigned int);
  149. #endif
  150. /////////////////////////////////////////////////////////////////////
  151. /////////////////////////////////////////////////////////////////////
  152. NAMESPACE_BEGIN(CryptoPP)
  153. #if ALL_RDRAND_INTRIN_AVAILABLE
  154. static int ALL_RRI_GenerateBlock(byte *output, size_t size, unsigned int safety)
  155. {
  156. assert((output && size) || !(output || size));
  157. #if CRYPTOPP_BOOL_X64 || CRYTPOPP_BOOL_X32
  158. word64 val;
  159. #else
  160. word32 val;
  161. #endif
  162. while (size >= sizeof(val))
  163. {
  164. #if CRYPTOPP_BOOL_X64 || CRYTPOPP_BOOL_X32
  165. if (_rdrand64_step((word64*)output))
  166. #else
  167. if (_rdrand32_step((word32*)output))
  168. #endif
  169. {
  170. output += sizeof(val);
  171. size -= sizeof(val);
  172. }
  173. else
  174. {
  175. if (!safety--)
  176. return 0;
  177. }
  178. }
  179. if (size)
  180. {
  181. #if CRYPTOPP_BOOL_X64 || CRYTPOPP_BOOL_X32
  182. if (_rdrand64_step(&val))
  183. #else
  184. if (_rdrand32_step(&val))
  185. #endif
  186. {
  187. memcpy(output, &val, size);
  188. size = 0;
  189. }
  190. else
  191. {
  192. if (!safety--)
  193. return 0;
  194. }
  195. }
  196. #if CRYPTOPP_BOOL_X64 || CRYTPOPP_BOOL_X32
  197. *((volatile word64*)&val) = 0;
  198. #else
  199. *((volatile word32*)&val) = 0;
  200. #endif
  201. return int(size == 0);
  202. }
  203. #endif // ALL_RDRAND_INTRINSIC_AVAILABLE
  204. #if GCC_RDRAND_ASM_AVAILABLE
  205. static int GCC_RRA_GenerateBlock(byte *output, size_t size, unsigned int safety)
  206. {
  207. assert((output && size) || !(output || size));
  208. #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
  209. word64 val;
  210. #else
  211. word32 val;
  212. #endif
  213. char rc;
  214. while (size)
  215. {
  216. __asm__ volatile(
  217. #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
  218. ".byte 0x48, 0x0f, 0xc7, 0xf0;\n" // rdrand rax
  219. #else
  220. ".byte 0x0f, 0xc7, 0xf0;\n" // rdrand eax
  221. #endif
  222. "setc %1; "
  223. : "=a" (val), "=qm" (rc)
  224. :
  225. : "cc"
  226. );
  227. if (rc)
  228. {
  229. if (size >= sizeof(val))
  230. {
  231. #if defined(CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS) && (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32)
  232. *((word64*)output) = val;
  233. #elif defined(CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS) && (CRYPTOPP_BOOL_X86)
  234. *((word32*)output) = val;
  235. #else
  236. memcpy(output, &val, sizeof(val));
  237. #endif
  238. output += sizeof(val);
  239. size -= sizeof(val);
  240. }
  241. else
  242. {
  243. memcpy(output, &val, size);
  244. size = 0;
  245. }
  246. }
  247. else
  248. {
  249. if (!safety--)
  250. break;
  251. }
  252. }
  253. #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
  254. *((volatile word64*)&val) = 0;
  255. #else
  256. *((volatile word32*)&val) = 0;
  257. #endif
  258. return int(size == 0);
  259. }
  260. #endif // GCC_RDRAND_ASM_AVAILABLE
  261. #if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
  262. void RDRAND::GenerateBlock(byte *output, size_t size)
  263. {
  264. CRYPTOPP_UNUSED(output), CRYPTOPP_UNUSED(size);
  265. assert((output && size) || !(output || size));
  266. if(!HasRDRAND())
  267. throw NotImplemented("RDRAND: rdrand is not available on this platform");
  268. int rc; CRYPTOPP_UNUSED(rc);
  269. #if MASM_RDRAND_ASM_AVAILABLE
  270. rc = MASM_RRA_GenerateBlock(output, size, m_retries);
  271. if (!rc) { throw RDRAND_Err("MASM_RRA_GenerateBlock"); }
  272. #elif NASM_RDRAND_ASM_AVAILABLE
  273. rc = NASM_RRA_GenerateBlock(output, size, m_retries);
  274. if (!rc) { throw RDRAND_Err("NASM_RRA_GenerateBlock"); }
  275. #elif ALL_RDRAND_INTRIN_AVAILABLE
  276. rc = ALL_RRI_GenerateBlock(output, size, m_retries);
  277. if (!rc) { throw RDRAND_Err("ALL_RRI_GenerateBlock"); }
  278. #elif GCC_RDRAND_ASM_AVAILABLE
  279. rc = GCC_RRA_GenerateBlock(output, size, m_retries);
  280. if (!rc) { throw RDRAND_Err("GCC_RRA_GenerateBlock"); }
  281. #else
  282. // RDRAND not detected at compile time, and no suitable compiler found
  283. throw NotImplemented("RDRAND: failed to find a suitable implementation???");
  284. #endif // CRYPTOPP_CPUID_AVAILABLE
  285. }
  286. void RDRAND::DiscardBytes(size_t n)
  287. {
  288. // RoundUpToMultipleOf is used because a full word is read, and its cheaper
  289. // to discard full words. There's no sense in dealing with tail bytes.
  290. assert(HasRDRAND());
  291. #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
  292. FixedSizeSecBlock<word64, 16> discard;
  293. n = RoundUpToMultipleOf(n, sizeof(word64));
  294. #else
  295. FixedSizeSecBlock<word32, 16> discard;
  296. n = RoundUpToMultipleOf(n, sizeof(word32));
  297. #endif
  298. size_t count = STDMIN(n, discard.SizeInBytes());
  299. while (count)
  300. {
  301. GenerateBlock(discard.BytePtr(), count);
  302. n -= count;
  303. count = STDMIN(n, discard.SizeInBytes());
  304. }
  305. }
  306. #endif // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64
  307. /////////////////////////////////////////////////////////////////////
  308. /////////////////////////////////////////////////////////////////////
  309. #if ALL_RDSEED_INTRIN_AVAILABLE
  310. static int ALL_RSI_GenerateBlock(byte *output, size_t size, unsigned int safety)
  311. {
  312. assert((output && size) || !(output || size));
  313. #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
  314. word64 val;
  315. #else
  316. word32 val;
  317. #endif
  318. while (size >= sizeof(val))
  319. {
  320. #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
  321. if (_rdseed64_step((word64*)output))
  322. #else
  323. if (_rdseed32_step((word32*)output))
  324. #endif
  325. {
  326. output += sizeof(val);
  327. size -= sizeof(val);
  328. }
  329. else
  330. {
  331. if (!safety--)
  332. return 0;
  333. }
  334. }
  335. if (size)
  336. {
  337. #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
  338. if (_rdseed64_step(&val))
  339. #else
  340. if (_rdseed32_step(&val))
  341. #endif
  342. {
  343. memcpy(output, &val, size);
  344. size = 0;
  345. }
  346. else
  347. {
  348. if (!safety--)
  349. return 0;
  350. }
  351. }
  352. #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
  353. *((volatile word64*)&val) = 0;
  354. #else
  355. *((volatile word32*)&val) = 0;
  356. #endif
  357. return int(size == 0);
  358. }
  359. #endif // ALL_RDSEED_INTRIN_AVAILABLE
  360. #if GCC_RDSEED_ASM_AVAILABLE
  361. static int GCC_RSA_GenerateBlock(byte *output, size_t size, unsigned int safety)
  362. {
  363. assert((output && size) || !(output || size));
  364. #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
  365. word64 val;
  366. #else
  367. word32 val;
  368. #endif
  369. char rc;
  370. while (size)
  371. {
  372. __asm__ volatile(
  373. #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
  374. ".byte 0x48, 0x0f, 0xc7, 0xf8;\n" // rdseed rax
  375. #else
  376. ".byte 0x0f, 0xc7, 0xf8;\n" // rdseed eax
  377. #endif
  378. "setc %1; "
  379. : "=a" (val), "=qm" (rc)
  380. :
  381. : "cc"
  382. );
  383. if (rc)
  384. {
  385. if (size >= sizeof(val))
  386. {
  387. #if defined(CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS) && (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32)
  388. *((word64*)output) = val;
  389. #elif defined(CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS) && (CRYPTOPP_BOOL_X86)
  390. *((word32*)output) = val;
  391. #else
  392. memcpy(output, &val, sizeof(val));
  393. #endif
  394. output += sizeof(val);
  395. size -= sizeof(val);
  396. }
  397. else
  398. {
  399. memcpy(output, &val, size);
  400. size = 0;
  401. }
  402. }
  403. else
  404. {
  405. if (!safety--)
  406. break;
  407. }
  408. }
  409. #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
  410. *((volatile word64*)&val) = 0;
  411. #else
  412. *((volatile word32*)&val) = 0;
  413. #endif
  414. return int(size == 0);
  415. }
  416. #endif // GCC_RDSEED_ASM_AVAILABLE
  417. #if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
  418. void RDSEED::GenerateBlock(byte *output, size_t size)
  419. {
  420. CRYPTOPP_UNUSED(output), CRYPTOPP_UNUSED(size);
  421. assert((output && size) || !(output || size));
  422. if(!HasRDSEED())
  423. throw NotImplemented("RDSEED: rdseed is not available on this platform");
  424. int rc; CRYPTOPP_UNUSED(rc);
  425. #if MASM_RDSEED_ASM_AVAILABLE
  426. rc = MASM_RSA_GenerateBlock(output, size, m_retries);
  427. if (!rc) { throw RDSEED_Err("MASM_RSA_GenerateBlock"); }
  428. #elif NASM_RDSEED_ASM_AVAILABLE
  429. rc = NASM_RSA_GenerateBlock(output, size, m_retries);
  430. if (!rc) { throw RDRAND_Err("NASM_RSA_GenerateBlock"); }
  431. #elif ALL_RDSEED_INTRIN_AVAILABLE
  432. rc = ALL_RSI_GenerateBlock(output, size, m_retries);
  433. if (!rc) { throw RDSEED_Err("ALL_RSI_GenerateBlock"); }
  434. #elif GCC_RDSEED_ASM_AVAILABLE
  435. rc = GCC_RSA_GenerateBlock(output, size, m_retries);
  436. if (!rc) { throw RDSEED_Err("GCC_RSA_GenerateBlock"); }
  437. #else
  438. // RDSEED not detected at compile time, and no suitable compiler found
  439. throw NotImplemented("RDSEED: failed to find a suitable implementation???");
  440. #endif
  441. }
  442. void RDSEED::DiscardBytes(size_t n)
  443. {
  444. // RoundUpToMultipleOf is used because a full word is read, and its cheaper
  445. // to discard full words. There's no sense in dealing with tail bytes.
  446. assert(HasRDSEED());
  447. #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
  448. FixedSizeSecBlock<word64, 16> discard;
  449. n = RoundUpToMultipleOf(n, sizeof(word64));
  450. #else
  451. FixedSizeSecBlock<word32, 16> discard;
  452. n = RoundUpToMultipleOf(n, sizeof(word32));
  453. #endif
  454. size_t count = STDMIN(n, discard.SizeInBytes());
  455. while (count)
  456. {
  457. GenerateBlock(discard.BytePtr(), count);
  458. n -= count;
  459. count = STDMIN(n, discard.SizeInBytes());
  460. }
  461. }
  462. #endif // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64
  463. NAMESPACE_END