• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 5123321399

30 May 2023 04:06PM UTC coverage: 92.213% (+0.004%) from 92.209%
5123321399

Pull #3558

github

web-flow
Merge dd72f7389 into 057bcbc35
Pull Request #3558: Add braces around all if/else statements

75602 of 81986 relevant lines covered (92.21%)

11859779.3 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.74
/src/lib/rng/processor_rng/processor_rng.cpp
1
/*
2
* (C) 2016,2019,2020 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include <botan/processor_rng.h>
8

9
#include <botan/internal/cpuid.h>
10
#include <botan/internal/loadstor.h>
11

12
#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) && !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_CPU_IS_X86_FAMILY)
21
/*
22
   * According to Intel, RDRAND is guaranteed to generate a random
23
   * number within 10 retries on a working CPU
24
   */
25
const size_t HWRNG_RETRIES = 10;
26

27
#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
28
/**
29
    * PowerISA 3.0 p.78:
30
    *    When the error value is obtained, software is expected to repeat the
31
    *    operation. [...] The recommended number of attempts may be
32
    *    implementation specific. In the absence of other guidance, ten attempts
33
    *    should be adequate.
34
    */
35
const size_t HWRNG_RETRIES = 10;
36

37
#else
38
/*
39
   * Lacking specific guidance we give the CPU quite a bit of leeway
40
   */
41
const size_t HWRNG_RETRIES = 512;
42
#endif
43

44
#if defined(BOTAN_TARGET_ARCH_IS_X86_32)
45
typedef uint32_t hwrng_output;
46
#else
47
typedef uint64_t hwrng_output;
48
#endif
49

50
hwrng_output read_hwrng(bool& success) {
13,492✔
51
   hwrng_output output = 0;
13,492✔
52
   success = false;
13,492✔
53

54
#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
55
   int cf = 0;
13,492✔
56
   #if defined(BOTAN_USE_GCC_INLINE_ASM)
57
   // same asm seq works for 32 and 64 bit
58
   asm volatile("rdrand %0; adcl $0,%1" : "=r"(output), "=r"(cf) : "0"(output), "1"(cf) : "cc");
26,984✔
59
   #elif defined(BOTAN_TARGET_ARCH_IS_X86_32)
60
   cf = _rdrand32_step(&output);
61
   #else
62
   cf = _rdrand64_step(&output);
63
   #endif
64
   success = (1 == cf);
13,492✔
65

66
#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
67

68
   /*
69
   DARN indicates error by returning 0xFF..FF, ie is biased. Which is crazy.
70
   Avoid the bias by invoking it twice and, assuming both succeed, returning the
71
   XOR of the two results, which should unbias the output.
72
   */
73
   uint64_t output2 = 0;
74
   // DARN codes are 0: 32-bit conditioned, 1: 64-bit conditioned, 2: 64-bit raw (ala RDSEED)
75
   asm volatile("darn %0, 1" : "=r"(output));
76
   asm volatile("darn %0, 1" : "=r"(output2));
77

78
   if((~output) != 0 && (~output2) != 0) {
79
      output ^= output2;
80
      success = true;
81
   }
82

83
#endif
84

85
   if(success) {
13,492✔
86
      return output;
13,492✔
87
   }
88

89
   return 0;
90
}
91

92
hwrng_output read_hwrng() {
13,492✔
93
   for(size_t i = 0; i < HWRNG_RETRIES; ++i) {
13,492✔
94
      bool success = false;
13,492✔
95
      hwrng_output output = read_hwrng(success);
13,492✔
96

97
      if(success) {
13,492✔
98
         return output;
13,492✔
99
      }
100
   }
101

102
   throw PRNG_Unseeded("Processor RNG instruction failed to produce output within expected iterations");
×
103
}
104

105
}  // namespace
106

107
//static
108
bool Processor_RNG::available() {
14✔
109
#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
110
   return CPUID::has_rdrand();
14✔
111
#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
112
   return CPUID::has_darn_rng();
113
#else
114
   return false;
115
#endif
116
}
117

118
std::string Processor_RNG::name() const {
19✔
119
#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
120
   return "rdrand";
19✔
121
#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
122
   return "darn";
123
#else
124
   return "hwrng";
125
#endif
126
}
127

128
void Processor_RNG::fill_bytes_with_input(std::span<uint8_t> out, std::span<const uint8_t> in) {
185✔
129
   // No way to provide entropy to processor-specific generator, ignore...
130
   BOTAN_UNUSED(in);
185✔
131

132
   while(out.size() >= sizeof(hwrng_output)) {
13,565✔
133
      const hwrng_output r = read_hwrng();
13,380✔
134
      store_le(r, out.data());
13,380✔
135
      out = out.subspan(sizeof(hwrng_output));
13,380✔
136
   }
137

138
   if(!out.empty())  // at most sizeof(hwrng_output)-1
185✔
139
   {
140
      const hwrng_output r = read_hwrng();
112✔
141
      uint8_t hwrng_bytes[sizeof(hwrng_output)];
112✔
142
      store_le(r, hwrng_bytes);
112✔
143

144
      for(size_t i = 0; i != out.size(); ++i) {
560✔
145
         out[i] = hwrng_bytes[i];
448✔
146
      }
147
   }
148
}
185✔
149

150
Processor_RNG::Processor_RNG() {
7✔
151
   if(!Processor_RNG::available()) {
7✔
152
      throw Invalid_State("Current CPU does not support RNG instruction");
×
153
   }
154
}
7✔
155

156
size_t Processor_RNG::reseed(Entropy_Sources& /*srcs*/,
1✔
157
                             size_t /*poll_bits*/,
158
                             std::chrono::milliseconds /*poll_timeout*/) {
159
   /* no way to add entropy */
160
   return 0;
1✔
161
}
162

163
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc