Botan 3.7.1
Crypto and TLS for C&
esdm_rng.cpp
Go to the documentation of this file.
1/*
2* ESDM RNG
3* (C) 2024, Markus Theil <theil.markus@gmail.com>
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/esdm_rng.h>
9
10#include <esdm/esdm_rpc_client.h>
11#include <mutex>
12
13namespace Botan {
14
15namespace {
16/**
17* This helper makes sure that the ESDM service is initialized and
18* finalized as needed in a threadsafe fashion. Finalization happens
19* as soon as all instances of ESDM_RNG are destructed. This may
20* happen multiple times in the lifetime of the process.
21*/
22class ESDM_Context {
23 public:
24 [[nodiscard]] static std::shared_ptr<void> instance() {
25 static ESDM_Context g_instance;
26 return g_instance.acquire();
27 }
28
29 private:
30 ESDM_Context() = default;
31
32 [[nodiscard]] std::shared_ptr<void> acquire() {
33 std::scoped_lock lk(m_mutex);
34 if(m_refs++ == 0) {
35 if(esdm_rpcc_init_unpriv_service(nullptr) != 0) {
36 throw Botan::System_Error("unable to initialize ESDM unprivileged service");
37 }
38 }
39 return std::shared_ptr<void>{nullptr, [this](void*) { this->release(); }};
40 }
41
42 void release() {
43 std::scoped_lock lk(m_mutex);
44 if(m_refs-- == 1) {
45 esdm_rpcc_fini_unpriv_service();
46 }
47 }
48
49 private:
50 std::mutex m_mutex;
51 size_t m_refs = 0;
52};
53} // namespace
54
55ESDM_RNG::ESDM_RNG(bool prediction_resistance) :
56 m_prediction_resistance(prediction_resistance), m_ctx(ESDM_Context::instance()) {}
57
58void ESDM_RNG::fill_bytes_with_input(std::span<uint8_t> out, std::span<const uint8_t> in) {
59 /*
60 * This variable is implicitly set by the "esdm_invoke" macro that comes
61 * with the ESDM library. "esdm_invoke" implements a retry mechanism for
62 * the underlying RPC mechanism of ESDM.
63 */
64 ssize_t ret = 0;
65
66 if(!in.empty()) {
67 ret = 0;
68
69 /*
70 * take additional input, but do not account entropy for it,
71 * as this information is not included in the API
72 */
73 esdm_invoke(esdm_rpcc_write_data(in.data(), in.size()));
74 /*
75 * ret was set by esdm_invoke, as mentioned above
76 */
77 if(ret != 0) {
78 throw Botan::System_Error("Writing additional input to ESDM failed");
79 }
80 }
81
82 if(!out.empty()) {
83 ret = 0;
84
85 if(m_prediction_resistance) {
86 esdm_invoke(esdm_rpcc_get_random_bytes_pr(out.data(), out.size()));
87 } else {
88 esdm_invoke(esdm_rpcc_get_random_bytes_full(out.data(), out.size()));
89 }
90 /*
91 * ret was set by esdm_invoke, as mentioned above
92 */
93 if(ret != static_cast<ssize_t>(out.size())) {
94 throw Botan::System_Error("Fetching random bytes from ESDM failed");
95 }
96 }
97}
98
100 static ESDM_RNG g_esdm_rng;
101 return g_esdm_rng;
102}
103
104} // namespace Botan
void fill_bytes_with_input(std::span< uint8_t > out, std::span< const uint8_t > in) override
Definition esdm_rng.cpp:58
RandomNumberGenerator & esdm_rng()
Definition esdm_rng.cpp:99