Botan 3.13.0
Crypto and TLS for C&
jitter_rng.cpp
Go to the documentation of this file.
1/*
2* CPU Jitter Random Number Generator
3* (C) 2024 Planck Security S.A.
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/jitter_rng.h>
9
10#include <botan/assert.h>
11#include <botan/exceptn.h>
12#include <botan/mutex.h>
13
14#include <jitterentropy.h>
15
16namespace Botan {
17
18class Jitter_RNG_Internal final {
19 public:
20 Jitter_RNG_Internal();
21 ~Jitter_RNG_Internal();
22 void collect_into_buffer(std::span<uint8_t> buf);
23
24 Jitter_RNG_Internal(const Jitter_RNG_Internal& other) = delete;
25 Jitter_RNG_Internal(Jitter_RNG_Internal&& other) = delete;
26 Jitter_RNG_Internal& operator=(const Jitter_RNG_Internal& other) = delete;
27 Jitter_RNG_Internal& operator=(Jitter_RNG_Internal&& other) = delete;
28
29 private:
30 mutex_type m_mutex;
31 rand_data* m_rand_data;
32};
33
34Jitter_RNG_Internal::Jitter_RNG_Internal() {
35 constexpr unsigned int oversampling_rate = 0; // use default oversampling
36 constexpr unsigned int flags = JENT_FORCE_FIPS; // enable health tests
37
38 // if flags and osr are used, use the same values for init and alloc
39 static const int result = jent_entropy_init_ex(oversampling_rate, flags);
40
41 // no further details documented regarding the return value
42 if(result != 0) {
43 throw Internal_Error("Jitter_RNG_Internal initialization failed");
44 }
45
46 m_rand_data = jent_entropy_collector_alloc(oversampling_rate, flags);
47 if(m_rand_data == nullptr) {
48 throw Internal_Error("Jitter_RNG_Internal collector allocation failed");
49 }
50}
51
52Jitter_RNG_Internal::~Jitter_RNG_Internal() {
53 const lock_guard_type<mutex_type> lock(m_mutex);
54 if(m_rand_data != nullptr) {
55 jent_entropy_collector_free(m_rand_data);
56 m_rand_data = nullptr;
57 }
58}
59
60void Jitter_RNG_Internal::collect_into_buffer(std::span<uint8_t> buf) {
61 if(buf.empty()) {
62 return;
63 }
64
65 const lock_guard_type<mutex_type> lock(m_mutex);
66 BOTAN_STATE_CHECK(m_rand_data != nullptr);
67
68 ssize_t num_bytes = jent_read_entropy_safe(&m_rand_data, reinterpret_cast<char*>(buf.data()), buf.size());
69 if(num_bytes < 0) {
70 const auto error_msg = [&]() -> std::string_view {
71 switch(num_bytes) {
72 case -1: // should never happen because of the check above
73 return "JitterRNG: Uninitilialized";
74 case -2:
75 return "JitterRNG: SP800-90B repetition count online health test failed";
76 case -3:
77 return "JitterRNG: SP800-90B adaptive proportion online health test failed";
78 case -4:
79 return "JitterRNG: Internal timer generator could not be initialized";
80 case -5:
81 return "JitterRNG: LAG predictor health test failed";
82 case -6:
83 return "JitterRNG: Repetitive count test (RCT) failed permanently";
84 case -7:
85 return "JitterRNG: Adaptive proportion test (APT) failed permanently";
86 case -8:
87 return "JitterRNG: LAG prediction test failed permanently";
88 default:
89 return "JitterRNG: Error reading entropy";
90 }
91 }();
92 throw Internal_Error(error_msg);
93 }
94
95 // According to the docs, `jent_read_entropy` itself runs its logic as often
96 // as necessary to gather the requested number of bytes,
97 // so this should actually never happen.
98 BOTAN_ASSERT(static_cast<size_t>(num_bytes) == buf.size(), "JitterRNG produced the expected number of bytes");
99}
100
101Jitter_RNG::Jitter_RNG() : m_jitter{std::make_unique<Jitter_RNG_Internal>()} {}
102
103Jitter_RNG::~Jitter_RNG() = default;
104
106 /* ignored - jitterentropy library does not support this */
107}
108
109void Jitter_RNG::fill_bytes_with_input(std::span<uint8_t> out, std::span<const uint8_t> in) {
110 BOTAN_UNUSED(in);
111
112 m_jitter->collect_into_buffer(out);
113}
114
115} // namespace Botan
#define BOTAN_UNUSED
Definition assert.h:144
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:49
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:62
~Jitter_RNG() override
void clear() override
Flags flags(Flag flags)
Definition p11.h:1235
noop_mutex mutex_type
Definition mutex.h:40
secure_vector< T > lock(const std::vector< T > &in)
Definition secmem.h:145
lock_guard< T > lock_guard_type
Definition mutex.h:58