Botan 3.12.0
Crypto and TLS for C&
ffi_rng.cpp
Go to the documentation of this file.
1/*
2* (C) 2015,2017,2026 Jack Lloyd
3* (C) 2021 René Fischer
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/ffi.h>
9
10#include <botan/auto_rng.h>
11#include <botan/system_rng.h>
12#include <botan/internal/ffi_rng.h>
13#include <botan/internal/ffi_util.h>
14
15#include <functional>
16#include <memory>
17
18#if defined(BOTAN_HAS_HMAC_DRBG)
19 #include <botan/hmac_drbg.h>
20#endif
21
22#if defined(BOTAN_HAS_PROCESSOR_RNG)
23 #include <botan/processor_rng.h>
24#endif
25
26#if defined(BOTAN_HAS_JITTER_RNG)
27 #include <botan/jitter_rng.h>
28#endif
29
30#if defined(BOTAN_HAS_ESDM_RNG)
31 #include <botan/esdm_rng.h>
32#endif
33
34extern "C" {
35
36using namespace Botan_FFI;
37
38int botan_rng_init(botan_rng_t* rng_out, const char* rng_type) {
39 return ffi_guard_thunk(__func__, [=]() -> int {
40 if(rng_out == nullptr) {
42 }
43
44 const std::string rng_type_s(rng_type != nullptr ? rng_type : "system");
45
46 std::unique_ptr<Botan::RandomNumberGenerator> rng;
47
48 if(rng_type_s == "system") {
49 rng = std::make_unique<Botan::System_RNG>();
50 } else if(rng_type_s == "user" || rng_type_s == "user-threadsafe") {
51 rng = std::make_unique<Botan::AutoSeeded_RNG>();
52 } else if(rng_type_s == "null") {
53 rng = std::make_unique<Botan::Null_RNG>();
54 }
55#if defined(BOTAN_HAS_PROCESSOR_RNG)
56 else if((rng_type_s == "rdrand" || rng_type_s == "hwrng") && Botan::Processor_RNG::available()) {
57 rng = std::make_unique<Botan::Processor_RNG>();
58 }
59#endif
60#if defined(BOTAN_HAS_JITTER_RNG)
61 else if(rng_type_s == "jitter") {
62 rng = std::make_unique<Botan::Jitter_RNG>();
63 }
64#endif
65#if defined(BOTAN_HAS_ESDM_RNG)
66 else if(rng_type_s == "esdm-full") {
67 rng = std::make_unique<Botan::ESDM_RNG>(false);
68 } else if(rng_type_s == "esdm-pr") {
69 rng = std::make_unique<Botan::ESDM_RNG>(true);
70 }
71#endif
72
73 if(!rng) {
75 }
76
77 return ffi_new_object(rng_out, std::move(rng));
78 });
79}
80
82 const char* rng_name,
83 void* context,
84 int (*get_cb)(void* context, uint8_t* out, size_t out_len),
85 int (*add_entropy_cb)(void* context, const uint8_t input[], size_t length),
86 void (*destroy_cb)(void* context)) {
87 return ffi_guard_thunk(__func__, [=]() -> int {
88 if(rng_out == nullptr) {
90 }
91
92 if(rng_name == nullptr) {
94 }
95
96 if(get_cb == nullptr) {
98 }
99
100 class Custom_RNG final : public Botan::RandomNumberGenerator {
101 public:
102 Custom_RNG(std::string_view name,
103 void* context,
104 int (*get_cb)(void* context, uint8_t* out, size_t out_len),
105 int (*add_entropy_cb)(void* context, const uint8_t input[], size_t length),
106 void (*destroy_cb)(void* context)) :
107 m_name(name),
108 m_context(context),
109 m_get_cb(get_cb),
110 m_add_entropy_cb(add_entropy_cb),
111 m_destroy_cb(destroy_cb) {}
112
113 ~Custom_RNG() override {
114 if(m_destroy_cb) {
115 m_destroy_cb(m_context);
116 }
117 }
118
119 Custom_RNG(const Custom_RNG& other) = delete;
120 Custom_RNG(Custom_RNG&& other) = delete;
121 Custom_RNG& operator=(const Custom_RNG& other) = delete;
122 Custom_RNG& operator=(Custom_RNG&& other) = delete;
123
124 protected:
125 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> input) override {
126 if(accepts_input() && !input.empty()) {
127 const int rc = m_add_entropy_cb(m_context, input.data(), input.size());
128 if(rc != 0) {
129 throw Botan::Invalid_State("Failed to add entropy via C callback, rc=" + std::to_string(rc));
130 }
131 }
132
133 if(!output.empty()) {
134 const int rc = m_get_cb(m_context, output.data(), output.size());
135 if(rc != 0) {
136 throw Botan::Invalid_State("Failed to get random from C callback, rc=" + std::to_string(rc));
137 }
138 }
139 }
140
141 public:
142 bool accepts_input() const override { return m_add_entropy_cb != nullptr; }
143
144 std::string name() const override { return m_name; }
145
146 void clear() override {}
147
148 bool is_seeded() const override { return true; }
149
150 private:
151 std::string m_name;
152 void* m_context;
153 std::function<int(void* context, uint8_t* out, size_t out_len)> m_get_cb;
154 std::function<int(void* context, const uint8_t input[], size_t length)> m_add_entropy_cb;
155 std::function<void(void* context)> m_destroy_cb;
156 };
157
158 auto rng = std::make_unique<Custom_RNG>(rng_name, context, get_cb, add_entropy_cb, destroy_cb);
159
160 return ffi_new_object(rng_out, std::move(rng));
161 });
162}
163
167
168int botan_rng_get(botan_rng_t rng, uint8_t* out, size_t out_len) {
169 if(out_len > 0 && out == nullptr) {
171 }
172 return BOTAN_FFI_VISIT(rng, [=](auto& r) { r.randomize(out, out_len); });
173}
174
175int botan_system_rng_get(uint8_t* out, size_t out_len) {
176 if(out_len > 0 && out == nullptr) {
178 }
179 return ffi_guard_thunk(__func__, [=]() -> int {
180 Botan::system_rng().randomize(out, out_len);
181 return BOTAN_FFI_SUCCESS;
182 });
183}
184
185int botan_rng_reseed(botan_rng_t rng, size_t bits) {
186 return BOTAN_FFI_VISIT(rng, [=](auto& r) { r.reseed_from_rng(Botan::system_rng(), bits); });
187}
188
189int botan_rng_add_entropy(botan_rng_t rng, const uint8_t* input, size_t len) {
190 if(len > 0 && input == nullptr) {
192 }
193 return BOTAN_FFI_VISIT(rng, [=](auto& r) { r.add_entropy(input, len); });
194}
195
196int botan_rng_reseed_from_rng(botan_rng_t rng, botan_rng_t source_rng, size_t bits) {
197 return BOTAN_FFI_VISIT(rng, [=](auto& r) { r.reseed_from_rng(safe_get(source_rng), bits); });
198}
199
200int botan_rng_init_drbg(botan_rng_t* rng_out, const char* drbg_name, const uint8_t* seed, size_t seed_len) {
201 return ffi_guard_thunk(__func__, [=]() -> int {
202 if(rng_out == nullptr || drbg_name == nullptr) {
204 }
205 if(seed_len > 0 && seed == nullptr) {
207 }
208
209 std::unique_ptr<Botan::Stateful_RNG> drbg;
210 const std::string name(drbg_name);
211
212#if defined(BOTAN_HAS_HMAC_DRBG)
213 if(name.starts_with("HMAC_DRBG(") && name.ends_with(")") && name.size() > 12) {
214 const std::string hash = name.substr(10, name.size() - 11);
215 drbg = std::make_unique<Botan::HMAC_DRBG>(hash);
216 }
217#endif
218
219 if(!drbg) {
221 }
222
223 drbg->initialize_with(std::span(seed, seed_len));
224 // Upcast to RandomNumberGenerator for the FFI object
225 std::unique_ptr<Botan::RandomNumberGenerator> rng(std::move(drbg));
226 return ffi_new_object(rng_out, std::move(rng));
227 });
228}
229
231 botan_rng_t rng, uint8_t* out, size_t out_len, const uint8_t* addl_input, size_t addl_len) {
232 if(out_len > 0 && out == nullptr) {
234 }
235 if(addl_len > 0 && addl_input == nullptr) {
237 }
238 return BOTAN_FFI_VISIT(rng, [=](auto& r) { r.randomize_with_input({out, out_len}, {addl_input, addl_len}); });
239}
240}
void randomize(std::span< uint8_t > output)
Definition rng.h:75
struct botan_rng_struct * botan_rng_t
Definition ffi.h:291
@ BOTAN_FFI_ERROR_NOT_IMPLEMENTED
Definition ffi.h:140
@ BOTAN_FFI_ERROR_NULL_POINTER
Definition ffi.h:133
@ BOTAN_FFI_SUCCESS
Definition ffi.h:116
int botan_rng_reseed_from_rng(botan_rng_t rng, botan_rng_t source_rng, size_t bits)
Definition ffi_rng.cpp:196
int botan_rng_init_drbg(botan_rng_t *rng_out, const char *drbg_name, const uint8_t *seed, size_t seed_len)
Definition ffi_rng.cpp:200
int botan_rng_init_custom(botan_rng_t *rng_out, const char *rng_name, void *context, int(*get_cb)(void *context, uint8_t *out, size_t out_len), int(*add_entropy_cb)(void *context, const uint8_t input[], size_t length), void(*destroy_cb)(void *context))
Definition ffi_rng.cpp:81
int botan_rng_reseed(botan_rng_t rng, size_t bits)
Definition ffi_rng.cpp:185
int botan_rng_add_entropy(botan_rng_t rng, const uint8_t *input, size_t len)
Definition ffi_rng.cpp:189
int botan_rng_init(botan_rng_t *rng_out, const char *rng_type)
Definition ffi_rng.cpp:38
int botan_system_rng_get(uint8_t *out, size_t out_len)
Definition ffi_rng.cpp:175
int botan_rng_get(botan_rng_t rng, uint8_t *out, size_t out_len)
Definition ffi_rng.cpp:168
int botan_rng_destroy(botan_rng_t rng)
Definition ffi_rng.cpp:164
int botan_rng_generate_with_input(botan_rng_t rng, uint8_t *out, size_t out_len, const uint8_t *addl_input, size_t addl_len)
Definition ffi_rng.cpp:230
#define BOTAN_FFI_VISIT(obj, lambda)
Definition ffi_util.h:158
#define BOTAN_FFI_CHECKED_DELETE(o)
Definition ffi_util.h:188
T & safe_get(botan_struct< T, M > *p)
Definition ffi_util.h:79
BOTAN_FFI_ERROR ffi_new_object(T *obj, Args &&... args)
Definition ffi_util.h:178
int ffi_guard_thunk(const char *func_name, T thunk)
Definition ffi_util.h:95
RandomNumberGenerator & system_rng()