-
Notifications
You must be signed in to change notification settings - Fork 403
/
randapi.hpp
253 lines (230 loc) · 6.87 KB
/
randapi.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012- OpenVPN Inc.
//
// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
//
/**
* @file randapi.hpp
* @brief Implementation of the base classes for random number generators
*/
#pragma once
#include <string>
#include <cstdint>
#include <type_traits>
#include <openvpn/common/size.hpp>
#include <openvpn/common/rc.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/random/randistrib.hpp>
namespace openvpn {
/**
* @class RandomAPI
* @brief Abstract base class for random number generators
*
* This class cannot be inherited from directly, use \ref StrongRandomAPI
* or \ref WeakRandomAPI to implement random number generators.
*/
class RandomAPI : public RC<thread_unsafe_refcount>
{
public:
/**
* @typedef RCPtr<RandomAPI> Ptr
* @brief Smart pointer type for managing the ownership of RandomAPI objects
*/
typedef RCPtr<RandomAPI> Ptr;
/**
* @brief Get the name of the random number generation algorithm
* @return The name of the algorithm
*/
virtual std::string name() const = 0;
/**
* @brief Fill a buffer with random bytes
* @param buf Pointer to the buffer
* @param size Number of bytes to generate
*/
virtual void rand_bytes(unsigned char *buf, size_t size) = 0;
/**
* @brief Fill a buffer with random bytes without throwing exceptions
* @param buf Pointer to the buffer
* @param size Number of bytes to generate
* @return true on success
* @return false on failure
*/
virtual bool rand_bytes_noexcept(unsigned char *buf, size_t size) = 0;
/**
* @brief Fill a data object with random bytes
* @tparam T Type of the object
* @param obj Reference to the object to be filled
*/
template <typename T>
void rand_fill(T &obj)
{
rand_bytes(reinterpret_cast<unsigned char *>(&obj), sizeof(T));
}
/**
* @brief Create a data object filled with random bytes
* @tparam T Type of the object
* @return The generated object
*/
template <typename T>
T rand_get()
{
T ret;
rand_fill(ret);
return ret;
}
/**
* @brief Create a data object filled with random bytes, always >= 0 for signed types
* @tparam T Type of the object
* @return The generated data object
*/
template <typename T>
T rand_get_positive()
{
T ret = rand_get<T>();
if constexpr (std::is_signed_v<T>)
{
// maps (T:min, -1) to (0, T:max) which is fine for random generation
ret &= std::numeric_limits<T>::max();
}
return ret;
}
/**
* @brief Return a uniformly distributed random number in the range [0, end)
* @tparam T Type of the object
* @param end The upper bound (exclusive)
* @return The generated random number
*/
template <typename T>
T randrange(const T end)
{
return rand_get_positive<T>() % end;
}
/**
* @brief Return a uniformly distributed random number in the range [start, end]
* @tparam T Type of the object
* @param start The lower bound
* @param end The upper bound
* @return The generated random number
*/
template <typename T>
T randrange(const T start, const T end)
{
if (start >= end)
return start;
else
return start + rand_get_positive<T>() % (end - start + 1);
}
/**
* @brief Return a uniformly distributed random number in the range [0, end)
* @param end The upper bound (exclusive)
* @return The generated random number
*
* If end==0 or end==1, will always return 0.
* This version is strictly 32-bit only and optimizes by avoiding
* integer division.
*/
std::uint32_t randrange32(const std::uint32_t end)
{
std::uint32_t r;
rand_fill(r);
return rand32_distribute(r, end);
}
/**
* @brief Return a uniformly distributed random number in the range [start, end]
* @param start The lower bound
* @param end The upper bound
* @return The generated random number
*
* This version is strictly 32-bit only and optimizes by avoiding
* integer division.
*/
std::uint32_t randrange32(const std::uint32_t start, const std::uint32_t end)
{
if (start >= end)
return start;
else
return start + randrange32(end - start + 1);
}
/**
* @brief Return a random byte
* @return The generated random byte
*/
std::uint8_t randbyte()
{
std::uint8_t byte;
rand_fill(byte);
return byte;
}
/**
* @brief Return a random boolean
* @return The generated random boolean
*/
bool randbool()
{
return bool(randbyte() & 1);
}
/**
* @name UniformRandomBitGenerator members
*
* These members implement the C++11 UniformRandomBitGenerator requirements
* so that RandomAPI instances can be used with std::shuffle (and others).
* See https://en.cppreference.com/w/cpp/named_req/UniformRandomBitGenerator
*/
///@{
typedef unsigned int result_type;
static constexpr result_type min()
{
return result_type(0);
}
static constexpr result_type max()
{
return ~result_type(0);
}
result_type operator()()
{
return rand_get<result_type>();
}
///@}
private:
friend class StrongRandomAPI;
friend class WeakRandomAPI;
RandomAPI() = default;
};
/**
* @class StrongRandomAPI
* @brief Abstract base class for cryptographically strong random number generators
*
* Inherit from this class if your random number generator produces cryptographically
* strong random numbers.
*/
class StrongRandomAPI : public RandomAPI
{
public:
/**
* @typedef RCPtr<StrongRandomAPI> Ptr
* @brief Smart pointer type for managing the ownership of StrongRandomAPI objects
*/
typedef RCPtr<StrongRandomAPI> Ptr;
};
/**
* @class WeakRandomAPI
* @brief Abstract base class for pseudo random number generators
*
* Inherit from this class if your random number generator produces pseudo random numbers
* which are deterministic and should not be used for operations requiring true randomness.
*/
class WeakRandomAPI : public RandomAPI
{
public:
/**
* @typedef RCPtr<WeakRandomAPI> Ptr
* @brief Smart pointer type for managing the ownership of WeakRandomAPI objects
*/
typedef RCPtr<WeakRandomAPI> Ptr;
};
} // namespace openvpn