Coverage Report

Created: 2020-03-26 13:53

/src/botan/src/lib/rng/rdrand_rng/rdrand_rng.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* RDRAND RNG
3
* (C) 2016,2019 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#include <botan/rdrand_rng.h>
9
#include <botan/loadstor.h>
10
#include <botan/cpuid.h>
11
12
#if !defined(BOTAN_USE_GCC_INLINE_ASM)
13
  #include <immintrin.h>
14
#endif
15
16
namespace Botan {
17
18
namespace {
19
20
#if defined(BOTAN_TARGET_ARCH_IS_X86_64)
21
   typedef uint64_t rdrand_output;
22
#else
23
   typedef uint32_t rdrand_output;
24
#endif
25
26
#if !defined(BOTAN_USE_GCC_INLINE_ASM)
27
BOTAN_FUNC_ISA("rdrnd")
28
#endif
29
rdrand_output read_rdrand()
30
0
   {
31
0
   /*
32
0
   * According to Intel, RDRAND is guaranteed to generate a random
33
0
   * number within 10 retries on a working CPU
34
0
   */
35
0
   const size_t RDRAND_RETRIES = 10;
36
0
37
0
   for(size_t i = 0; i < RDRAND_RETRIES; ++i)
38
0
      {
39
0
      rdrand_output r = 0;
40
0
      int cf = 0;
41
0
42
0
#if defined(BOTAN_USE_GCC_INLINE_ASM)
43
0
      // same asm seq works for 32 and 64 bit
44
0
      asm("rdrand %0; adcl $0,%1" :
45
0
          "=r" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc");
46
#elif defined(BOTAN_TARGET_ARCH_IS_X86_64)
47
      cf = _rdrand64_step(&r);
48
#else
49
      cf = _rdrand32_step(&r);
50
#endif
51
0
      if(1 == cf)
52
0
         {
53
0
         return r;
54
0
         }
55
0
      }
56
0
57
0
   throw PRNG_Unseeded("RDRAND read failed");
58
0
   }
59
60
}
61
62
void RDRAND_RNG::randomize(uint8_t out[], size_t out_len)
63
0
   {
64
0
   while(out_len >= sizeof(rdrand_output))
65
0
      {
66
0
      const rdrand_output r = read_rdrand();
67
0
      store_le(r, out);
68
0
      out += sizeof(rdrand_output);
69
0
      out_len -= sizeof(rdrand_output);
70
0
      }
71
0
72
0
   if(out_len > 0) // at most sizeof(rdrand_output)-1
73
0
      {
74
0
      const rdrand_output r = read_rdrand();
75
0
      for(size_t i = 0; i != out_len; ++i)
76
0
         out[i] = get_byte(i, r);
77
0
      }
78
0
   }
79
80
RDRAND_RNG::RDRAND_RNG()
81
0
   {
82
0
   if(!RDRAND_RNG::available())
83
0
      throw Invalid_State("Current CPU does not support RDRAND instruction");
84
0
   }
85
86
//static
87
bool RDRAND_RNG::available()
88
0
   {
89
0
   return CPUID::has_rdrand();
90
0
   }
91
92
//static
93
uint32_t RDRAND_RNG::rdrand()
94
0
   {
95
0
   return static_cast<uint32_t>(read_rdrand());
96
0
   }
97
98
//static
99
BOTAN_FUNC_ISA("rdrnd")
100
uint32_t RDRAND_RNG::rdrand_status(bool& ok)
101
0
   {
102
0
   ok = false;
103
0
104
0
   try
105
0
      {
106
0
      const uint32_t r = static_cast<uint32_t>(read_rdrand());
107
0
      ok = true;
108
0
      return r;
109
0
      }
110
0
   catch(PRNG_Unseeded&) {}
111
0
112
0
   return 0;
113
0
   }
114
115
}