Coverage Report

Created: 2019-12-03 15:21

/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
BOTAN_FUNC_ISA("rdrnd")
27
rdrand_output read_rdrand()
28
0
   {
29
0
   /*
30
0
   * According to Intel, RDRAND is guaranteed to generate a random
31
0
   * number within 10 retries on a working CPU
32
0
   */
33
0
   const size_t RDRAND_RETRIES = 10;
34
0
35
0
   for(size_t i = 0; i < RDRAND_RETRIES; ++i)
36
0
      {
37
0
      rdrand_output r = 0;
38
0
      int cf = 0;
39
0
40
0
#if defined(BOTAN_USE_GCC_INLINE_ASM)
41
0
      // same asm seq works for 32 and 64 bit
42
0
      asm("rdrand %0; adcl $0,%1" :
43
0
          "=r" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc");
44
#elif defined(BOTAN_TARGET_ARCH_IS_X86_64)
45
      cf = _rdrand64_step(&r);
46
#else
47
      cf = _rdrand32_step(&r);
48
#endif
49
0
      if(1 == cf)
50
0
         {
51
0
         return r;
52
0
         }
53
0
      }
54
0
55
0
   throw PRNG_Unseeded("RDRAND read failed");
56
0
   }
57
58
}
59
60
void RDRAND_RNG::randomize(uint8_t out[], size_t out_len)
61
0
   {
62
0
   while(out_len >= sizeof(rdrand_output))
63
0
      {
64
0
      const rdrand_output r = read_rdrand();
65
0
      store_le(r, out);
66
0
      out += sizeof(rdrand_output);
67
0
      out_len -= sizeof(rdrand_output);
68
0
      }
69
0
70
0
   if(out_len > 0) // at most sizeof(rdrand_output)-1
71
0
      {
72
0
      const rdrand_output r = read_rdrand();
73
0
      for(size_t i = 0; i != out_len; ++i)
74
0
         out[i] = get_byte(i, r);
75
0
      }
76
0
   }
77
78
RDRAND_RNG::RDRAND_RNG()
79
0
   {
80
0
   if(!RDRAND_RNG::available())
81
0
      throw Invalid_State("Current CPU does not support RDRAND instruction");
82
0
   }
83
84
//static
85
bool RDRAND_RNG::available()
86
0
   {
87
0
   return CPUID::has_rdrand();
88
0
   }
89
90
//static
91
uint32_t RDRAND_RNG::rdrand()
92
0
   {
93
0
   return static_cast<uint32_t>(read_rdrand());
94
0
   }
95
96
//static
97
BOTAN_FUNC_ISA("rdrnd")
98
uint32_t RDRAND_RNG::rdrand_status(bool& ok)
99
0
   {
100
0
   ok = false;
101
0
102
0
   try
103
0
      {
104
0
      const uint32_t r = static_cast<uint32_t>(read_rdrand());
105
0
      ok = true;
106
0
      return r;
107
0
      }
108
0
   catch(PRNG_Unseeded&) {}
109
0
110
0
   return 0;
111
0
   }
112
113
}