/src/Botan-3.4.0/src/lib/ffi/ffi_rng.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * (C) 2015,2017 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_PROCESSOR_RNG) |
19 | | #include <botan/processor_rng.h> |
20 | | #endif |
21 | | |
22 | | extern "C" { |
23 | | |
24 | | using namespace Botan_FFI; |
25 | | |
26 | 89.6k | int botan_rng_init(botan_rng_t* rng_out, const char* rng_type) { |
27 | 89.6k | return ffi_guard_thunk(__func__, [=]() -> int { |
28 | 89.6k | if(rng_out == nullptr) { |
29 | 0 | return BOTAN_FFI_ERROR_NULL_POINTER; |
30 | 0 | } |
31 | | |
32 | 89.6k | const std::string rng_type_s(rng_type ? rng_type : "system"); |
33 | | |
34 | 89.6k | std::unique_ptr<Botan::RandomNumberGenerator> rng; |
35 | | |
36 | 89.6k | if(rng_type_s == "system") { |
37 | 0 | rng = std::make_unique<Botan::System_RNG>(); |
38 | 89.6k | } else if(rng_type_s == "user" || rng_type_s == "user-threadsafe") { |
39 | 89.6k | rng = std::make_unique<Botan::AutoSeeded_RNG>(); |
40 | 89.6k | } else if(rng_type_s == "null") { |
41 | 0 | rng = std::make_unique<Botan::Null_RNG>(); |
42 | 0 | } |
43 | | #if defined(BOTAN_HAS_PROCESSOR_RNG) |
44 | | else if((rng_type_s == "rdrand" || rng_type_s == "hwrng") && Botan::Processor_RNG::available()) { |
45 | | rng = std::make_unique<Botan::Processor_RNG>(); |
46 | | } |
47 | | #endif |
48 | | |
49 | 89.6k | if(!rng) { |
50 | 0 | return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; |
51 | 0 | } |
52 | | |
53 | 89.6k | *rng_out = new botan_rng_struct(std::move(rng)); |
54 | 89.6k | return BOTAN_FFI_SUCCESS; |
55 | 89.6k | }); |
56 | 89.6k | } |
57 | | |
58 | | int botan_rng_init_custom(botan_rng_t* rng_out, |
59 | | const char* rng_name, |
60 | | void* context, |
61 | | int (*get_cb)(void* context, uint8_t* out, size_t out_len), |
62 | | int (*add_entropy_cb)(void* context, const uint8_t input[], size_t length), |
63 | 0 | void (*destroy_cb)(void* context)) { |
64 | 0 | return ffi_guard_thunk(__func__, [=]() -> int { |
65 | 0 | if(rng_out == nullptr) { |
66 | 0 | return BOTAN_FFI_ERROR_NULL_POINTER; |
67 | 0 | } |
68 | | |
69 | 0 | if(rng_name == nullptr) { |
70 | 0 | return BOTAN_FFI_ERROR_NULL_POINTER; |
71 | 0 | } |
72 | | |
73 | 0 | if(get_cb == nullptr) { |
74 | 0 | return BOTAN_FFI_ERROR_NULL_POINTER; |
75 | 0 | } |
76 | | |
77 | 0 | class Custom_RNG : public Botan::RandomNumberGenerator { |
78 | 0 | public: |
79 | 0 | Custom_RNG(std::string_view name, |
80 | 0 | void* context, |
81 | 0 | int (*get_cb)(void* context, uint8_t* out, size_t out_len), |
82 | 0 | int (*add_entropy_cb)(void* context, const uint8_t input[], size_t length), |
83 | 0 | void (*destroy_cb)(void* context)) : |
84 | 0 | m_name(name) { |
85 | 0 | m_context = context; |
86 | 0 | m_get_cb = get_cb; |
87 | 0 | m_add_entropy_cb = add_entropy_cb; |
88 | 0 | m_destroy_cb = destroy_cb; |
89 | 0 | } |
90 | |
|
91 | 0 | ~Custom_RNG() override { |
92 | 0 | if(m_destroy_cb) { |
93 | 0 | m_destroy_cb(m_context); |
94 | 0 | } |
95 | 0 | } |
96 | |
|
97 | 0 | Custom_RNG(const Custom_RNG& other) = delete; |
98 | 0 | Custom_RNG(Custom_RNG&& other) = delete; |
99 | 0 | Custom_RNG& operator=(const Custom_RNG& other) = delete; |
100 | 0 | Custom_RNG& operator=(Custom_RNG&& other) = delete; |
101 | |
|
102 | 0 | protected: |
103 | 0 | void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> input) override { |
104 | 0 | if(accepts_input() && !input.empty()) { |
105 | 0 | int rc = m_add_entropy_cb(m_context, input.data(), input.size()); |
106 | 0 | if(rc) { |
107 | 0 | throw Botan::Invalid_State("Failed to add entropy via C callback, rc=" + std::to_string(rc)); |
108 | 0 | } |
109 | 0 | } |
110 | | |
111 | 0 | if(!output.empty()) { |
112 | 0 | int rc = m_get_cb(m_context, output.data(), output.size()); |
113 | 0 | if(rc) { |
114 | 0 | throw Botan::Invalid_State("Failed to get random from C callback, rc=" + std::to_string(rc)); |
115 | 0 | } |
116 | 0 | } |
117 | 0 | } |
118 | |
|
119 | 0 | public: |
120 | 0 | bool accepts_input() const override { return m_add_entropy_cb != nullptr; } |
121 | |
|
122 | 0 | std::string name() const override { return m_name; } |
123 | |
|
124 | 0 | void clear() override {} |
125 | |
|
126 | 0 | bool is_seeded() const override { return true; } |
127 | |
|
128 | 0 | private: |
129 | 0 | std::string m_name; |
130 | 0 | void* m_context; |
131 | 0 | std::function<int(void* context, uint8_t* out, size_t out_len)> m_get_cb; |
132 | 0 | std::function<int(void* context, const uint8_t input[], size_t length)> m_add_entropy_cb; |
133 | 0 | std::function<void(void* context)> m_destroy_cb; |
134 | 0 | }; |
135 | |
|
136 | 0 | auto rng = std::make_unique<Custom_RNG>(rng_name, context, get_cb, add_entropy_cb, destroy_cb); |
137 | |
|
138 | 0 | *rng_out = new botan_rng_struct(std::move(rng)); |
139 | 0 | return BOTAN_FFI_SUCCESS; |
140 | 0 | }); |
141 | 0 | } |
142 | | |
143 | 89.6k | int botan_rng_destroy(botan_rng_t rng) { |
144 | 89.6k | return BOTAN_FFI_CHECKED_DELETE(rng); |
145 | 89.6k | } |
146 | | |
147 | 0 | int botan_rng_get(botan_rng_t rng, uint8_t* out, size_t out_len) { |
148 | 0 | return BOTAN_FFI_VISIT(rng, [=](auto& r) { r.randomize(out, out_len); }); |
149 | 0 | } |
150 | | |
151 | 0 | int botan_system_rng_get(uint8_t* out, size_t out_len) { |
152 | 0 | return ffi_guard_thunk(__func__, [=]() -> int { |
153 | 0 | Botan::system_rng().randomize(out, out_len); |
154 | 0 | return BOTAN_FFI_SUCCESS; |
155 | 0 | }); |
156 | 0 | } |
157 | | |
158 | 0 | int botan_rng_reseed(botan_rng_t rng, size_t bits) { |
159 | 0 | return BOTAN_FFI_VISIT(rng, [=](auto& r) { r.reseed_from_rng(Botan::system_rng(), bits); }); |
160 | 0 | } |
161 | | |
162 | 0 | int botan_rng_add_entropy(botan_rng_t rng, const uint8_t* input, size_t len) { |
163 | 0 | return BOTAN_FFI_VISIT(rng, [=](auto& r) { r.add_entropy(input, len); }); |
164 | 0 | } |
165 | | |
166 | 0 | int botan_rng_reseed_from_rng(botan_rng_t rng, botan_rng_t source_rng, size_t bits) { |
167 | 0 | return BOTAN_FFI_VISIT(rng, [=](auto& r) { r.reseed_from_rng(safe_get(source_rng), bits); }); |
168 | 0 | } |
169 | | } |