1 /*
2 * Global PRNG
3 * (C) 2008-2010 Jack Lloyd
4 *
5 * Distributed under the terms of the Botan license
6 */
7 
8 #include <botan/libstate.h>
9 #include <botan/internal/mutex.h>
10 
11 #if defined(BOTAN_HAS_RANDPOOL)
12   #include <botan/randpool.h>
13 #endif
14 
15 #if defined(BOTAN_HAS_HMAC_RNG)
16   #include <botan/hmac_rng.h>
17 #endif
18 
19 #if defined(BOTAN_HAS_X931_RNG)
20   #include <botan/x931_rng.h>
21 #endif
22 
23 #if defined(BOTAN_HAS_ENTROPY_SRC_HIGH_RESOLUTION_TIMER)
24   #include <botan/internal/hres_timer.h>
25 #endif
26 
27 #if defined(BOTAN_HAS_ENTROPY_SRC_RDRAND)
28   #include <botan/internal/rdrand.h>
29 #endif
30 
31 #if defined(BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM)
32   #include <botan/internal/dev_random.h>
33 #endif
34 
35 #if defined(BOTAN_HAS_ENTROPY_SRC_EGD)
36   #include <botan/internal/es_egd.h>
37 #endif
38 
39 #if defined(BOTAN_HAS_ENTROPY_SRC_UNIX)
40   #include <botan/internal/es_unix.h>
41 #endif
42 
43 #if defined(BOTAN_HAS_ENTROPY_SRC_BEOS)
44   #include <botan/internal/es_beos.h>
45 #endif
46 
47 #if defined(BOTAN_HAS_ENTROPY_SRC_CAPI)
48   #include <botan/internal/es_capi.h>
49 #endif
50 
51 #if defined(BOTAN_HAS_ENTROPY_SRC_WIN32)
52   #include <botan/internal/es_win32.h>
53 #endif
54 
55 #if defined(BOTAN_HAS_ENTROPY_SRC_FTW)
56   #include <botan/internal/es_ftw.h>
57 #endif
58 
59 namespace Botan {
60 
61 namespace {
62 
63 /**
64 * Add any known entropy sources to this RNG
65 */
add_entropy_sources(RandomNumberGenerator * rng)66 void add_entropy_sources(RandomNumberGenerator* rng)
67    {
68 #if defined(BOTAN_HAS_ENTROPY_SRC_HIGH_RESOLUTION_TIMER)
69    rng->add_entropy_source(new High_Resolution_Timestamp);
70 #endif
71 
72 #if defined(BOTAN_HAS_ENTROPY_SRC_RDRAND)
73    rng->add_entropy_source(new Intel_Rdrand);
74 #endif
75 
76 #if defined(BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM)
77    rng->add_entropy_source(
78       new Device_EntropySource(
79          split_on("/dev/urandom:/dev/srandom:/dev/random", ':')
80          )
81       );
82 #endif
83 
84 #if defined(BOTAN_HAS_ENTROPY_SRC_EGD)
85    rng->add_entropy_source(
86       new EGD_EntropySource(split_on("/var/run/egd-pool:/dev/egd-pool", ':'))
87       );
88 #endif
89 
90 #if defined(BOTAN_HAS_ENTROPY_SRC_CAPI)
91    rng->add_entropy_source(new Win32_CAPI_EntropySource);
92 #endif
93 
94 #if defined(BOTAN_HAS_ENTROPY_SRC_FTW)
95    rng->add_entropy_source(new FTW_EntropySource("/proc"));
96 #endif
97 
98 #if defined(BOTAN_HAS_ENTROPY_SRC_WIN32)
99    rng->add_entropy_source(new Win32_EntropySource);
100 #endif
101 
102 #if defined(BOTAN_HAS_ENTROPY_SRC_BEOS)
103    rng->add_entropy_source(new BeOS_EntropySource);
104 #endif
105 
106 #if defined(BOTAN_HAS_ENTROPY_SRC_UNIX)
107    rng->add_entropy_source(
108       new Unix_EntropySource(split_on("/bin:/sbin:/usr/bin:/usr/sbin", ':'))
109       );
110 #endif
111    }
112 
113 class Serialized_PRNG : public RandomNumberGenerator
114    {
115    public:
randomize(byte out[],size_t len)116       void randomize(byte out[], size_t len)
117          {
118          Mutex_Holder lock(mutex);
119          rng->randomize(out, len);
120          }
121 
is_seeded() const122       bool is_seeded() const
123          {
124          Mutex_Holder lock(mutex);
125          return rng->is_seeded();
126          }
127 
clear()128       void clear()
129          {
130          Mutex_Holder lock(mutex);
131          rng->clear();
132          }
133 
name() const134       std::string name() const
135          {
136          Mutex_Holder lock(mutex);
137          return rng->name();
138          }
139 
reseed(size_t poll_bits)140       void reseed(size_t poll_bits)
141          {
142          Mutex_Holder lock(mutex);
143          rng->reseed(poll_bits);
144          }
145 
add_entropy_source(EntropySource * es)146       void add_entropy_source(EntropySource* es)
147          {
148          Mutex_Holder lock(mutex);
149          rng->add_entropy_source(es);
150          }
151 
add_entropy(const byte in[],size_t len)152       void add_entropy(const byte in[], size_t len)
153          {
154          Mutex_Holder lock(mutex);
155          rng->add_entropy(in, len);
156          }
157 
158       // We do not own the mutex; Library_State does
Serialized_PRNG(RandomNumberGenerator * r,Mutex * m)159       Serialized_PRNG(RandomNumberGenerator* r, Mutex* m) :
160          mutex(m), rng(r) {}
161 
~Serialized_PRNG()162       ~Serialized_PRNG() { delete rng; }
163    private:
164       Mutex* mutex;
165       RandomNumberGenerator* rng;
166    };
167 
168 }
169 
make_global_rng(Algorithm_Factory & af,Mutex * mutex)170 RandomNumberGenerator* Library_State::make_global_rng(Algorithm_Factory& af,
171                                                       Mutex* mutex)
172    {
173    RandomNumberGenerator* rng = 0;
174 
175 #if defined(BOTAN_HAS_HMAC_RNG)
176 
177    rng = new HMAC_RNG(af.make_mac("HMAC(SHA-512)"),
178                       af.make_mac("HMAC(SHA-256)"));
179 
180 #elif defined(BOTAN_HAS_RANDPOOL)
181 
182    rng = new Randpool(af.make_block_cipher("AES-256"),
183                       af.make_mac("HMAC(SHA-256)"));
184 
185 #endif
186 
187    if(!rng)
188       throw Internal_Error("No usable RNG found enabled in build");
189 
190    /* If X9.31 is available, use it to wrap the other RNG as a failsafe */
191 #if defined(BOTAN_HAS_X931_RNG)
192 
193    rng = new ANSI_X931_RNG(af.make_block_cipher("AES-256"), rng);
194 
195 #endif
196 
197    add_entropy_sources(rng);
198 
199    rng->reseed(256);
200 
201    return new Serialized_PRNG(rng, mutex);
202    }
203 
204 }
205