Coverage Report

Created: 2025-07-11 06:15

/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
}