Coverage Report

Created: 2024-11-21 07:03

/src/cryptopp/osrng.h
Line
Count
Source (jump to first uncovered line)
1
// osrng.h - originally written and placed in the public domain by Wei Dai
2
3
/// \file osrng.h
4
/// \brief Classes for access to the operating system's random number generators
5
6
#ifndef CRYPTOPP_OSRNG_H
7
#define CRYPTOPP_OSRNG_H
8
9
#include "config.h"
10
11
#if !defined(NO_OS_DEPENDENCE) && defined(OS_RNG_AVAILABLE)
12
13
#include "cryptlib.h"
14
#include "randpool.h"
15
#include "smartptr.h"
16
#include "fips140.h"
17
#include "hkdf.h"
18
#include "rng.h"
19
#include "aes.h"
20
#include "sha.h"
21
22
NAMESPACE_BEGIN(CryptoPP)
23
24
/// \brief Exception thrown when an operating system error is encountered
25
class CRYPTOPP_DLL OS_RNG_Err : public Exception
26
{
27
public:
28
  /// \brief Constructs an OS_RNG_Err
29
  /// \param operation the operation or API call when the error occurs
30
  OS_RNG_Err(const std::string &operation);
31
};
32
33
#ifdef NONBLOCKING_RNG_AVAILABLE
34
35
#ifdef CRYPTOPP_WIN32_AVAILABLE
36
/// \brief Wrapper for Microsoft crypto service provider
37
/// \sa \def USE_MS_CRYPTOAPI, \def USE_MS_CNGAPI
38
class CRYPTOPP_DLL MicrosoftCryptoProvider
39
{
40
public:
41
  /// \brief Construct a MicrosoftCryptoProvider
42
  MicrosoftCryptoProvider();
43
  ~MicrosoftCryptoProvider();
44
45
// type HCRYPTPROV and BCRYPT_ALG_HANDLE, avoid #include <windows.h>
46
#if defined(USE_MS_CRYPTOAPI)
47
# if defined(__CYGWIN__) && defined(__x86_64__)
48
  typedef unsigned long long ProviderHandle;
49
# elif defined(WIN64) || defined(_WIN64)
50
  typedef unsigned __int64 ProviderHandle;
51
# else
52
  typedef unsigned long ProviderHandle;
53
# endif
54
#elif defined(USE_MS_CNGAPI)
55
  typedef void *PVOID;
56
  typedef PVOID ProviderHandle;
57
#endif // USE_MS_CRYPTOAPI or USE_MS_CNGAPI
58
59
  /// \brief Retrieves the provider handle
60
  /// \return CryptoAPI provider handle
61
  /// \details If USE_MS_CRYPTOAPI is in effect, then CryptAcquireContext()
62
  ///  acquires then handle and CryptReleaseContext() releases the handle
63
  ///  upon destruction. If USE_MS_CNGAPI is in effect, then
64
  ///  BCryptOpenAlgorithmProvider() acquires then handle and
65
  ///  BCryptCloseAlgorithmProvider() releases the handle upon destruction.
66
  ProviderHandle GetProviderHandle() const {return m_hProvider;}
67
68
private:
69
  ProviderHandle m_hProvider;
70
};
71
72
#if defined(CRYPTOPP_MSC_VERSION) && defined(USE_MS_CRYPTOAPI)
73
# pragma comment(lib, "advapi32.lib")
74
#endif
75
76
#if defined(CRYPTOPP_MSC_VERSION) && defined(USE_MS_CNGAPI)
77
# pragma comment(lib, "bcrypt.lib")
78
#endif
79
80
#endif // CRYPTOPP_WIN32_AVAILABLE
81
82
/// \brief Wrapper class for /dev/random and /dev/srandom
83
/// \details Encapsulates CryptoAPI's CryptGenRandom() or CryptoNG's BCryptGenRandom()
84
///  on Windows, or /dev/urandom on Unix and compatibles.
85
class CRYPTOPP_DLL NonblockingRng : public RandomNumberGenerator
86
{
87
public:
88
0
  CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "NonblockingRng"; }
89
90
  ~NonblockingRng();
91
92
  /// \brief Construct a NonblockingRng
93
  NonblockingRng();
94
95
  /// \brief Generate random array of bytes
96
  /// \param output the byte buffer
97
  /// \param size the length of the buffer, in bytes
98
  /// \details GenerateIntoBufferedTransformation() calls are routed to GenerateBlock().
99
  void GenerateBlock(byte *output, size_t size);
100
101
protected:
102
#ifdef CRYPTOPP_WIN32_AVAILABLE
103
  MicrosoftCryptoProvider m_Provider;
104
#else
105
  int m_fd;
106
#endif
107
};
108
109
#endif
110
111
#if defined(BLOCKING_RNG_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING)
112
113
/// \brief Wrapper class for /dev/random and /dev/srandom
114
/// \details Encapsulates /dev/random on Linux, OS X and Unix; and /dev/srandom on the BSDs.
115
/// \note On Linux the /dev/random interface is effectively deprecated. According to the
116
///  Kernel Crypto developers, /dev/urandom or getrandom(2) should be used instead. Also
117
///  see <A HREF="https://lkml.org/lkml/2017/7/20/993">[RFC PATCH v12 3/4] Linux Random
118
///  Number Generator</A> on the kernel-crypto mailing list.
119
class CRYPTOPP_DLL BlockingRng : public RandomNumberGenerator
120
{
121
public:
122
0
  CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "BlockingRng"; }
123
124
  ~BlockingRng();
125
126
  /// \brief Construct a BlockingRng
127
  BlockingRng();
128
129
  /// \brief Generate random array of bytes
130
  /// \param output the byte buffer
131
  /// \param size the length of the buffer, in bytes
132
  /// \details GenerateIntoBufferedTransformation() calls are routed to GenerateBlock().
133
  void GenerateBlock(byte *output, size_t size);
134
135
protected:
136
  int m_fd;
137
};
138
139
#endif
140
141
/// OS_GenerateRandomBlock
142
/// \brief Generate random array of bytes
143
/// \param blocking specifies whether a blocking or non-blocking generator should be used
144
/// \param output the byte buffer
145
/// \param size the length of the buffer, in bytes
146
/// \details OS_GenerateRandomBlock() uses the underlying operating system's
147
///  random number generator. On Windows, CryptGenRandom() is called using NonblockingRng.
148
/// \details On Unix and compatibles, /dev/urandom is called if blocking is false using
149
///  NonblockingRng. If blocking is true, then either /dev/randomd or /dev/srandom is used
150
///  by way of BlockingRng, if available.
151
CRYPTOPP_DLL void CRYPTOPP_API OS_GenerateRandomBlock(bool blocking, byte *output, size_t size);
152
153
/// \brief Automatically Seeded Randomness Pool
154
/// \details This class seeds itself using an operating system provided RNG.
155
///  AutoSeededRandomPool was suggested by Leonard Janke.
156
/// \details You should reseed the generator after a fork() to avoid multiple generators
157
///  with the same internal state.
158
class CRYPTOPP_DLL AutoSeededRandomPool : public RandomPool
159
{
160
public:
161
0
  CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "AutoSeededRandomPool"; }
162
163
0
  ~AutoSeededRandomPool() {}
164
165
  /// \brief Construct an AutoSeededRandomPool
166
  /// \param blocking controls seeding with BlockingRng or NonblockingRng
167
  /// \param seedSize the size of the seed, in bytes
168
  /// \details Use blocking to choose seeding with BlockingRng or NonblockingRng.
169
  ///  The parameter is ignored if only one of these is available.
170
  explicit AutoSeededRandomPool(bool blocking = false, unsigned int seedSize = 32)
171
28
    {Reseed(blocking, seedSize);}
172
173
  /// \brief Reseed an AutoSeededRandomPool
174
  /// \param blocking controls seeding with BlockingRng or NonblockingRng
175
  /// \param seedSize the size of the seed, in bytes
176
  void Reseed(bool blocking = false, unsigned int seedSize = 32);
177
};
178
179
/// \tparam BLOCK_CIPHER a block cipher
180
/// \brief Automatically Seeded X9.17 RNG
181
/// \details AutoSeededX917RNG is from ANSI X9.17 Appendix C, seeded using an OS provided RNG.
182
///  If 3-key TripleDES (DES_EDE3) is used, then its a X9.17 conforming generator. If AES is
183
///  used, then its a X9.31 conforming generator.
184
/// \details Though ANSI X9 prescribes 3-key TripleDES, the template parameter BLOCK_CIPHER
185
///  can be any BlockTransformation derived class.
186
/// \details You should reseed the generator after a fork() to avoid multiple generators
187
///  with the same internal state.
188
/// \sa X917RNG, DefaultAutoSeededRNG
189
template <class BLOCK_CIPHER>
190
class AutoSeededX917RNG : public RandomNumberGenerator, public NotCopyable
191
{
192
public:
193
0
  static std::string StaticAlgorithmName() {
194
0
    return std::string("AutoSeededX917RNG(") + BLOCK_CIPHER::StaticAlgorithmName() + std::string(")");
195
0
  }
196
197
0
  ~AutoSeededX917RNG() {}
198
199
  /// \brief Construct an AutoSeededX917RNG
200
  /// \param blocking controls seeding with BlockingRng or NonblockingRng
201
  /// \param autoSeed controls auto seeding of the generator
202
  /// \details Use blocking to choose seeding with BlockingRng or NonblockingRng.
203
  ///  The parameter is ignored if only one of these is available.
204
  /// \sa X917RNG
205
  explicit AutoSeededX917RNG(bool blocking = false, bool autoSeed = true)
206
0
    {if (autoSeed) Reseed(blocking);}
207
208
  /// \brief Reseed an AutoSeededX917RNG
209
  /// \param blocking controls seeding with BlockingRng or NonblockingRng
210
  /// \param input additional entropy to add to the generator
211
  /// \param length the size of the additional entropy, in bytes
212
  /// \details Internally, the generator uses SHA256 to extract the entropy from
213
  ///  from the seed and then stretch the material for the block cipher's key
214
  ///  and initialization vector.
215
  void Reseed(bool blocking = false, const byte *input = NULLPTR, size_t length = 0);
216
217
  /// \brief Deterministically reseed an AutoSeededX917RNG for testing
218
  /// \param key the key to use for the deterministic reseeding
219
  /// \param keylength the size of the key, in bytes
220
  /// \param seed the seed to use for the deterministic reseeding
221
  /// \param timeVector a time vector to use for deterministic reseeding
222
  /// \details This is a testing interface for testing purposes, and should \a NOT
223
  ///  be used in production.
224
  void Reseed(const byte *key, size_t keylength, const byte *seed, const byte *timeVector);
225
226
0
  bool CanIncorporateEntropy() const {return true;}
227
0
  void IncorporateEntropy(const byte *input, size_t length) {Reseed(false, input, length);}
228
  void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword length)
229
0
    {m_rng->GenerateIntoBufferedTransformation(target, channel, length);}
230
231
  std::string AlgorithmProvider() const;
232
233
private:
234
  member_ptr<RandomNumberGenerator> m_rng;
235
};
236
237
template <class BLOCK_CIPHER>
238
void AutoSeededX917RNG<BLOCK_CIPHER>::Reseed(const byte *key, size_t keylength, const byte *seed, const byte *timeVector)
239
0
{
240
0
  m_rng.reset(new X917RNG(new typename BLOCK_CIPHER::Encryption(key, keylength), seed, timeVector));
241
0
}
242
243
template <class BLOCK_CIPHER>
244
void AutoSeededX917RNG<BLOCK_CIPHER>::Reseed(bool blocking, const byte *input, size_t length)
245
0
{
246
0
  enum {BlockSize=BLOCK_CIPHER::BLOCKSIZE};
247
0
  enum {KeyLength=BLOCK_CIPHER::DEFAULT_KEYLENGTH};
248
0
  enum {SeedSize=EnumToInt(BlockSize)+EnumToInt(KeyLength)};
249
250
0
  SecByteBlock seed(SeedSize), temp(SeedSize);
251
0
  const byte label[] = "X9.17 key generation";
252
0
  const byte *key=NULLPTR;
253
254
0
  do
255
0
  {
256
0
    OS_GenerateRandomBlock(blocking, temp, temp.size());
257
258
0
    HKDF<SHA256> hkdf;
259
0
    hkdf.DeriveKey(
260
0
      seed, seed.size(),  // derived secret
261
0
      temp, temp.size(),  // instance secret
262
0
      input, length,      // user secret
263
0
      label, 20           // unique label
264
0
    );
265
266
0
    key = seed + BlockSize;
267
0
  } // check that seed and key don't have same value
268
0
  while (std::memcmp(key, seed, STDMIN((size_t)BlockSize, (size_t)KeyLength)) == 0);
269
270
0
  Reseed(key, KeyLength, seed, NULLPTR);
271
0
}
272
273
template <class BLOCK_CIPHER>
274
std::string AutoSeededX917RNG<BLOCK_CIPHER>::AlgorithmProvider() const
275
0
{
276
  // Hack for now... We need to instantiate one
277
0
  typename BLOCK_CIPHER::Encryption bc;
278
0
  return bc.AlgorithmProvider();
279
0
}
280
281
CRYPTOPP_DLL_TEMPLATE_CLASS AutoSeededX917RNG<AES>;
282
283
#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
284
/// \brief A typedef providing a default generator
285
/// \details DefaultAutoSeededRNG is a typedef of either AutoSeededX917RNG<AES> or AutoSeededRandomPool.
286
///  If CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 is defined, then DefaultAutoSeededRNG is
287
///  AutoSeededX917RNG<AES>. Otherwise, DefaultAutoSeededRNG is AutoSeededRandomPool.
288
/// \details You should reseed the generator after a fork() to avoid multiple generators
289
///  with the same internal state.
290
class DefaultAutoSeededRNG {}
291
#else
292
// AutoSeededX917RNG<AES> in FIPS mode, otherwise it's AutoSeededRandomPool
293
#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2
294
typedef AutoSeededX917RNG<AES> DefaultAutoSeededRNG;
295
#else
296
typedef AutoSeededRandomPool DefaultAutoSeededRNG;
297
#endif
298
#endif // CRYPTOPP_DOXYGEN_PROCESSING
299
300
NAMESPACE_END
301
302
#endif
303
304
#endif