1 /*
2 * (C) 2014,2015,2017 Jack Lloyd
3 * (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include "tests.h"
9 #include "test_rng.h"
10 
11 #if defined(BOTAN_HAS_STATEFUL_RNG)
12    #include <botan/stateful_rng.h>
13 #endif
14 
15 #if defined(BOTAN_HAS_HMAC_DRBG)
16    #include <botan/hmac_drbg.h>
17 #endif
18 
19 #if defined(BOTAN_HAS_AUTO_RNG)
20    #include <botan/auto_rng.h>
21 #endif
22 
23 #if defined(BOTAN_HAS_CHACHA_RNG)
24    #include <botan/chacha_rng.h>
25 #endif
26 
27 #if defined(BOTAN_HAS_SYSTEM_RNG)
28    #include <botan/system_rng.h>
29 #endif
30 
31 #if defined(BOTAN_HAS_PROCESSOR_RNG)
32    #include <botan/processor_rng.h>
33 #endif
34 
35 #if defined(BOTAN_HAS_ENTROPY_SOURCE)
36    #include <botan/entropy_src.h>
37 #endif
38 
39 #if defined(BOTAN_TARGET_OS_HAS_POSIX1)
40    #include <unistd.h>
41    #include <sys/wait.h>
42 #endif
43 
44 namespace Botan_Tests {
45 
46 namespace {
47 
48 #if defined(BOTAN_HAS_STATEFUL_RNG)
49 
50 class Stateful_RNG_Tests : public Test
51    {
52    public:
run()53       std::vector<Test::Result> run() override
54          {
55          std::vector<Test::Result> results;
56          results.push_back(test_reseed_kat());
57          results.push_back(test_reseed());
58          results.push_back(test_reseed_interval_limits());
59          results.push_back(test_max_number_of_bytes_per_request());
60          results.push_back(test_broken_entropy_input());
61          results.push_back(test_check_nonce());
62          results.push_back(test_prediction_resistance());
63          results.push_back(test_randomize_with_ts_input());
64          results.push_back(test_security_level());
65 
66          /*
67          * This test uses the library in both parent and child processes. But
68          * this causes a race with other threads, where if any other test thread
69          * is holding the mlock pool mutex, it is killed after the fork. Then,
70          * in the child, any attempt to allocate or free memory will cause a
71          * deadlock.
72          */
73          if(Test::options().test_threads() == 1)
74             results.push_back(test_fork_safety());
75 
76          return results;
77          }
78 
79    protected:
80       virtual std::string rng_name() const = 0;
81 
82       virtual std::unique_ptr<Botan::Stateful_RNG> create_rng(
83          Botan::RandomNumberGenerator* underlying_rng,
84          Botan::Entropy_Sources* underlying_es,
85          size_t reseed_interval) = 0;
86 
make_rng(Botan::RandomNumberGenerator & underlying_rng,size_t reseed_interval=1024)87       std::unique_ptr<Botan::Stateful_RNG> make_rng(Botan::RandomNumberGenerator& underlying_rng,
88                                                     size_t reseed_interval = 1024)
89          {
90          return create_rng(&underlying_rng, nullptr, reseed_interval);
91          }
92 
make_rng(Botan::Entropy_Sources & underlying_srcs,size_t reseed_interval=1024)93       std::unique_ptr<Botan::Stateful_RNG> make_rng(Botan::Entropy_Sources& underlying_srcs,
94                                                     size_t reseed_interval = 1024)
95          {
96          return create_rng(nullptr, &underlying_srcs, reseed_interval);
97          }
98 
make_rng(Botan::RandomNumberGenerator & underlying_rng,Botan::Entropy_Sources & underlying_srcs,size_t reseed_interval=1024)99       std::unique_ptr<Botan::Stateful_RNG> make_rng(Botan::RandomNumberGenerator& underlying_rng,
100                                                     Botan::Entropy_Sources& underlying_srcs,
101                                                     size_t reseed_interval = 1024)
102          {
103          return create_rng(&underlying_rng, &underlying_srcs, reseed_interval);
104          }
105 
106       virtual Test::Result test_reseed_kat() = 0;
107 
108       virtual Test::Result test_security_level() = 0;
109 
110       virtual Test::Result test_max_number_of_bytes_per_request() = 0;
111 
112       virtual Test::Result test_reseed_interval_limits() = 0;
113    private:
test_reseed()114       Test::Result test_reseed()
115          {
116          Test::Result result(rng_name() + " Reseed");
117 
118          // test reseed_interval is enforced
119          Request_Counting_RNG counting_rng;
120 
121          std::unique_ptr<Botan::Stateful_RNG> rng = make_rng(counting_rng, 2);
122 
123          rng->random_vec(7);
124          result.test_eq("initial seeding", counting_rng.randomize_count(), 1);
125          rng->random_vec(9);
126          result.test_eq("still initial seed", counting_rng.randomize_count(), 1);
127 
128          rng->random_vec(1);
129          result.test_eq("first reseed", counting_rng.randomize_count(), 2);
130          rng->random_vec(15);
131          result.test_eq("still first reseed", counting_rng.randomize_count(), 2);
132 
133          rng->random_vec(15);
134          result.test_eq("second reseed", counting_rng.randomize_count(), 3);
135          rng->random_vec(1);
136          result.test_eq("still second reseed", counting_rng.randomize_count(), 3);
137 
138          if(rng->max_number_of_bytes_per_request() > 0)
139             {
140             // request > max_number_of_bytes_per_request, do reseeds occur?
141             rng->random_vec(64 * 1024 + 1);
142             result.test_eq("request exceeds output limit", counting_rng.randomize_count(), 4);
143 
144             rng->random_vec(9 * 64 * 1024 + 1);
145             result.test_eq("request exceeds output limit", counting_rng.randomize_count(), 9);
146             }
147 
148          return result;
149          }
150 
test_broken_entropy_input()151       Test::Result test_broken_entropy_input()
152          {
153          Test::Result result(rng_name() + " Broken Entropy Input");
154 
155          class Broken_Entropy_Source final : public Botan::Entropy_Source
156             {
157             public:
158                std::string name() const override
159                   {
160                   return "Broken Entropy Source";
161                   }
162 
163                size_t poll(Botan::RandomNumberGenerator&) override
164                   {
165                   throw Botan::Not_Implemented("polling not available");
166                   }
167             };
168 
169          class Insufficient_Entropy_Source final : public Botan::Entropy_Source
170             {
171             public:
172                std::string name() const override
173                   {
174                   return "Insufficient Entropy Source";
175                   }
176 
177                size_t poll(Botan::RandomNumberGenerator&) override
178                   {
179                   return 0;
180                   }
181             };
182 
183          // make sure no output is generated when the entropy input source is broken
184 
185          // underlying_rng throws exception
186          Botan::Null_RNG broken_entropy_input_rng;
187          result.test_eq("Null_RNG not seeded", broken_entropy_input_rng.is_seeded(), false);
188          std::unique_ptr<Botan::Stateful_RNG> rng_with_broken_rng = make_rng(broken_entropy_input_rng);
189 
190          result.test_throws("broken underlying rng", [&rng_with_broken_rng]() { rng_with_broken_rng->random_vec(16); });
191 
192          // entropy_sources throw exception
193          std::unique_ptr<Broken_Entropy_Source> broken_entropy_source_1(new Broken_Entropy_Source());
194          std::unique_ptr<Broken_Entropy_Source> broken_entropy_source_2(new Broken_Entropy_Source());
195 
196          Botan::Entropy_Sources broken_entropy_sources;
197          broken_entropy_sources.add_source(std::move(broken_entropy_source_1));
198          broken_entropy_sources.add_source(std::move(broken_entropy_source_2));
199 
200          std::unique_ptr<Botan::Stateful_RNG> rng_with_broken_es = make_rng(broken_entropy_sources);
201          result.test_throws("broken entropy sources", [&rng_with_broken_es]() { rng_with_broken_es->random_vec(16); });
202 
203          // entropy source returns insufficient entropy
204          Botan::Entropy_Sources insufficient_entropy_sources;
205          std::unique_ptr<Insufficient_Entropy_Source> insufficient_entropy_source(new Insufficient_Entropy_Source());
206          insufficient_entropy_sources.add_source(std::move(insufficient_entropy_source));
207 
208          std::unique_ptr<Botan::Stateful_RNG> rng_with_insufficient_es = make_rng(insufficient_entropy_sources);
209          result.test_throws("insufficient entropy source", [&rng_with_insufficient_es]() { rng_with_insufficient_es->random_vec(16); });
210 
211          // one of or both underlying_rng and entropy_sources throw exception
212 
213          std::unique_ptr<Botan::Stateful_RNG> rng_with_broken_rng_and_good_es =
214             make_rng(broken_entropy_input_rng, Botan::Entropy_Sources::global_sources());
215 
216          result.test_throws("broken underlying rng but good entropy sources", [&rng_with_broken_rng_and_good_es]()
217             { rng_with_broken_rng_and_good_es->random_vec(16); });
218 
219          std::unique_ptr<Botan::Stateful_RNG> rng_with_good_rng_and_broken_es =
220             make_rng(Test::rng(), broken_entropy_sources);
221 
222          result.test_throws("good underlying rng but broken entropy sources", [&rng_with_good_rng_and_broken_es]()
223             { rng_with_good_rng_and_broken_es->random_vec(16); });
224 
225          std::unique_ptr<Botan::Stateful_RNG> rng_with_broken_rng_and_broken_es =
226             make_rng(broken_entropy_input_rng, broken_entropy_sources);
227 
228          result.test_throws("underlying rng and entropy sources broken", [&rng_with_broken_rng_and_broken_es]()
229             { rng_with_broken_rng_and_broken_es->random_vec(16); });
230 
231          return result;
232          }
233 
test_check_nonce()234       Test::Result test_check_nonce()
235          {
236          Test::Result result(rng_name() + " Nonce Check");
237 
238          // make sure the nonce has at least security_strength bits
239          std::unique_ptr<Botan::Stateful_RNG> rng = create_rng(nullptr, nullptr, 0);
240 
241          for(size_t nonce_size : { 0, 4, 8, 16, 31, 32, 34, 64 })
242             {
243             rng->clear();
244             result.test_eq("not seeded", rng->is_seeded(), false);
245 
246             const std::vector<uint8_t> nonce(nonce_size);
247             rng->initialize_with(nonce.data(), nonce.size());
248 
249             if(nonce_size < rng->security_level() / 8)
250                {
251                result.test_eq("not seeded", rng->is_seeded(), false);
252                result.test_throws("invalid nonce size", [&rng]() { rng->random_vec(32); });
253                }
254             else
255                {
256                result.test_eq("is seeded", rng->is_seeded(), true);
257                rng->random_vec(32);
258                }
259             }
260 
261          return result;
262          }
263 
test_prediction_resistance()264       Test::Result test_prediction_resistance()
265          {
266          Test::Result result(rng_name() + " Prediction Resistance");
267 
268          // set reseed_interval = 1, forcing a reseed for every RNG request
269          Request_Counting_RNG counting_rng;
270          std::unique_ptr<Botan::Stateful_RNG> rng = make_rng(counting_rng, 1);
271 
272          rng->random_vec(16);
273          result.test_eq("first request", counting_rng.randomize_count(), size_t(1));
274 
275          rng->random_vec(16);
276          result.test_eq("second request", counting_rng.randomize_count(), size_t(2));
277 
278          rng->random_vec(16);
279          result.test_eq("third request", counting_rng.randomize_count(), size_t(3));
280 
281          return result;
282          }
283 
test_fork_safety()284       Test::Result test_fork_safety()
285          {
286          Test::Result result(rng_name() + " Fork Safety");
287 
288 #if defined(BOTAN_TARGET_OS_HAS_POSIX1)
289          const size_t reseed_interval = 1024;
290 
291          // make sure rng is reseeded after every fork
292          Request_Counting_RNG counting_rng;
293          std::unique_ptr<Botan::Stateful_RNG> rng = make_rng(counting_rng, reseed_interval);
294 
295          rng->random_vec(16);
296          result.test_eq("first request", counting_rng.randomize_count(), size_t(1));
297 
298          // fork and request from parent and child, both should output different sequences
299          size_t count = counting_rng.randomize_count();
300          Botan::secure_vector<uint8_t> parent_bytes(16), child_bytes(16);
301          int fd[2];
302          int rc = ::pipe(fd);
303          if(rc != 0)
304             {
305             result.test_failure("failed to create pipe");
306             }
307 
308          pid_t pid = ::fork();
309          if(pid == -1)
310             {
311 #if defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN)
312             result.test_note("failed to fork process");
313 #else
314             result.test_failure("failed to fork process");
315 #endif
316             return result;
317             }
318          else if(pid != 0)
319             {
320             // parent process, wait for randomize_count from child's rng
321             ::close(fd[1]); // close write end in parent
322             ssize_t got = ::read(fd[0], &count, sizeof(count));
323 
324             if(got > 0)
325                {
326                result.test_eq("expected bytes from child", got, sizeof(count));
327                result.test_eq("parent not reseeded",  counting_rng.randomize_count(), 1);
328                result.test_eq("child reseed occurred", count, 2);
329                }
330             else
331                {
332                result.test_failure("Failed to read count size from child process");
333                }
334 
335             parent_bytes = rng->random_vec(16);
336             got = ::read(fd[0], &child_bytes[0], child_bytes.size());
337 
338             if(got > 0)
339                {
340                result.test_eq("expected bytes from child", got, child_bytes.size());
341                result.test_ne("parent and child output sequences differ", parent_bytes, child_bytes);
342                }
343             else
344                {
345                result.test_failure("Failed to read RNG bytes from child process");
346                }
347             ::close(fd[0]); // close read end in parent
348 
349             // wait for the child to exit
350             int status = 0;
351             ::waitpid(pid, &status, 0);
352             }
353          else
354             {
355             // child process, send randomize_count and first output sequence back to parent
356             ::close(fd[0]); // close read end in child
357             rng->randomize(&child_bytes[0], child_bytes.size());
358             count = counting_rng.randomize_count();
359             ssize_t written = ::write(fd[1], &count, sizeof(count));
360             try
361                {
362                rng->randomize(&child_bytes[0], child_bytes.size());
363                }
364             catch(std::exception& e)
365                {
366                fprintf(stderr, "%s", e.what());
367                }
368             written = ::write(fd[1], &child_bytes[0], child_bytes.size());
369             BOTAN_UNUSED(written);
370             ::close(fd[1]); // close write end in child
371 
372             /*
373             * We can't call exit because it causes the mlock pool to be freed (#602)
374             * We can't call _exit because it makes valgrind think we leaked memory.
375             * So instead we execute something that will return 0 for us.
376             */
377             ::execl("/bin/true", "true", NULL);
378             ::_exit(0); // just in case /bin/true isn't available (sandbox?)
379             }
380 #endif
381          return result;
382          }
383 
test_randomize_with_ts_input()384       Test::Result test_randomize_with_ts_input()
385          {
386          Test::Result result(rng_name() + " Randomize With Timestamp Input");
387 
388          const size_t request_bytes = 64;
389          const std::vector<uint8_t> seed(128);
390 
391          // check that randomize_with_ts_input() creates different output based on a timestamp
392          // and possibly additional data, such as process id even with identical seeds
393          Fixed_Output_RNG fixed_output_rng1(seed);
394          Fixed_Output_RNG fixed_output_rng2(seed);
395 
396          std::unique_ptr<Botan::Stateful_RNG> rng1 = make_rng(fixed_output_rng1);
397          std::unique_ptr<Botan::Stateful_RNG> rng2 = make_rng(fixed_output_rng2);
398 
399          Botan::secure_vector<uint8_t> output1(request_bytes);
400          Botan::secure_vector<uint8_t> output2(request_bytes);
401 
402          rng1->randomize(output1.data(), output1.size());
403          rng2->randomize(output2.data(), output2.size());
404 
405          result.test_eq("equal output due to same seed", output1, output2);
406 
407          rng1->randomize_with_ts_input(output1.data(), output1.size());
408          rng2->randomize_with_ts_input(output2.data(), output2.size());
409 
410          result.test_ne("output differs due to different timestamp", output1, output2);
411 
412          return result;
413          }
414 
415    };
416 
417 #endif
418 
419 #if defined(BOTAN_HAS_HMAC_DRBG) && defined(BOTAN_HAS_SHA2_32)
420 
421 class HMAC_DRBG_Unit_Tests final : public Stateful_RNG_Tests
422    {
423    public:
rng_name() const424       std::string rng_name() const override { return "HMAC_DRBG"; }
425 
create_rng(Botan::RandomNumberGenerator * underlying_rng,Botan::Entropy_Sources * underlying_es,size_t reseed_interval)426       std::unique_ptr<Botan::Stateful_RNG> create_rng(Botan::RandomNumberGenerator* underlying_rng,
427                                                       Botan::Entropy_Sources* underlying_es,
428                                                       size_t reseed_interval) override
429          {
430          std::unique_ptr<Botan::MessageAuthenticationCode> mac =
431             Botan::MessageAuthenticationCode::create("HMAC(SHA-256)");
432 
433          if(underlying_rng && underlying_es)
434             return std::unique_ptr<Botan::Stateful_RNG>(new Botan::HMAC_DRBG(std::move(mac), *underlying_rng, *underlying_es, reseed_interval));
435          else if(underlying_rng)
436             return std::unique_ptr<Botan::Stateful_RNG>(new Botan::HMAC_DRBG(std::move(mac), *underlying_rng, reseed_interval));
437          else if(underlying_es)
438             return std::unique_ptr<Botan::Stateful_RNG>(new Botan::HMAC_DRBG(std::move(mac), *underlying_es, reseed_interval));
439          else if(reseed_interval == 0)
440             return std::unique_ptr<Botan::Stateful_RNG>(new Botan::HMAC_DRBG(std::move(mac)));
441          else
442             throw Test_Error("Invalid reseed interval in HMAC_DRBG unit test");
443          }
444 
test_max_number_of_bytes_per_request()445       Test::Result test_max_number_of_bytes_per_request() override
446          {
447          Test::Result result("HMAC_DRBG max_number_of_bytes_per_request");
448 
449          const std::string mac_string = "HMAC(SHA-256)";
450 
451          Request_Counting_RNG counting_rng;
452 
453          result.test_throws("HMAC_DRBG does not accept 0 for max_number_of_bytes_per_request",
454                             [&mac_string, &counting_rng]()
455             {
456             Botan::HMAC_DRBG failing_rng(Botan::MessageAuthenticationCode::create(mac_string), counting_rng, 2, 0);
457             });
458 
459          result.test_throws("HMAC_DRBG does not accept values higher than 64KB for max_number_of_bytes_per_request",
460                             [&mac_string, &counting_rng]()
461             {
462             Botan::HMAC_DRBG failing_rng(Botan::MessageAuthenticationCode::create(mac_string), counting_rng, 2, 64 * 1024 + 1);
463             });
464 
465          // set reseed_interval to 1 so we can test that a long request is split
466          // into multiple, max_number_of_bytes_per_request long requests
467          // for each smaller request, reseed_check() calls counting_rng::randomize(),
468          // which we can compare with
469          Botan::HMAC_DRBG rng(Botan::MessageAuthenticationCode::create(mac_string), counting_rng, 1, 64);
470 
471          rng.random_vec(63);
472          result.test_eq("one request", counting_rng.randomize_count(), 1);
473 
474          rng.clear();
475          counting_rng.clear();
476 
477          rng.random_vec(64);
478          result.test_eq("one request", counting_rng.randomize_count(), 1);
479 
480          rng.clear();
481          counting_rng.clear();
482 
483          rng.random_vec(65);
484          result.test_eq("two requests", counting_rng.randomize_count(), 2);
485 
486          rng.clear();
487          counting_rng.clear();
488 
489          rng.random_vec(1025);
490          result.test_eq("17 requests", counting_rng.randomize_count(), 17);
491 
492          return result;
493          }
494 
test_reseed_interval_limits()495       Test::Result test_reseed_interval_limits() override
496          {
497          Test::Result result("HMAC_DRBG reseed_interval limits");
498 
499          const std::string mac_string = "HMAC(SHA-256)";
500 
501          Request_Counting_RNG counting_rng;
502 
503          result.test_throws("HMAC_DRBG does not accept 0 for reseed_interval",
504                             [&mac_string, &counting_rng]()
505             {
506             Botan::HMAC_DRBG failing_rng(Botan::MessageAuthenticationCode::create(mac_string), counting_rng, 0);
507             });
508 
509          result.test_throws("HMAC_DRBG does not accept values higher than 2^24 for reseed_interval",
510                             [&mac_string, &counting_rng]()
511             {
512             Botan::HMAC_DRBG failing_rng(Botan::MessageAuthenticationCode::create(mac_string), counting_rng, (static_cast<size_t>(1) << 24) + 1);
513             });
514 
515          return result;
516          }
517 
test_security_level()518       Test::Result test_security_level() override
519          {
520          Test::Result result("HMAC_DRBG Security Level");
521 
522          std::vector<std::string> approved_hash_fns { "SHA-160", "SHA-224", "SHA-256", "SHA-512/256", "SHA-384", "SHA-512" };
523          std::vector<uint32_t> security_strengths { 128, 192, 256, 256, 256, 256 };
524 
525          for(size_t i = 0; i < approved_hash_fns.size(); ++i)
526             {
527             std::string hash_fn = approved_hash_fns[i];
528             std::string mac_name = "HMAC(" + hash_fn + ")";
529             auto mac = Botan::MessageAuthenticationCode::create(mac_name);
530             if(!mac)
531                {
532                result.note_missing(mac_name);
533                continue;
534                }
535 
536             Botan::HMAC_DRBG rng(std::move(mac));
537             result.test_eq(hash_fn + " security level", rng.security_level(), security_strengths[i]);
538             }
539 
540          return result;
541          }
542 
test_reseed_kat()543       Test::Result test_reseed_kat() override
544          {
545          Test::Result result("HMAC_DRBG Reseed KAT");
546 
547          Request_Counting_RNG counting_rng;
548          std::unique_ptr<Botan::Stateful_RNG> rng = make_rng(counting_rng, 2);
549 
550          const Botan::secure_vector<uint8_t> seed_input(
551             {
552             0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
553             0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
554             });
555 
556          result.test_eq("is_seeded", rng->is_seeded(), false);
557 
558          rng->initialize_with(seed_input.data(), seed_input.size());
559 
560          Botan::secure_vector<uint8_t> out(32);
561 
562          rng->randomize(out.data(), out.size());
563          result.test_eq("underlying RNG calls", counting_rng.randomize_count(), size_t(0));
564          result.test_eq("out before reseed", out, "48D3B45AAB65EF92CCFCB9427EF20C90297065ECC1B8A525BFE4DC6FF36D0E38");
565 
566          // reseed must happen here
567          rng->randomize(out.data(), out.size());
568          result.test_eq("underlying RNG calls", counting_rng.randomize_count(), size_t(1));
569          result.test_eq("out after reseed", out, "2F8FCA696832C984781123FD64F4B20C7379A25C87AB29A21C9BF468B0081CE2");
570 
571          return result;
572          }
573 
574    };
575 
576 BOTAN_REGISTER_TEST("rng", "hmac_drbg_unit", HMAC_DRBG_Unit_Tests);
577 
578 #endif
579 
580 #if defined(BOTAN_HAS_CHACHA_RNG)
581 
582 class ChaCha_RNG_Unit_Tests final : public Stateful_RNG_Tests
583    {
584    public:
585 
rng_name() const586       std::string rng_name() const override { return "ChaCha_RNG"; }
587 
create_rng(Botan::RandomNumberGenerator * underlying_rng,Botan::Entropy_Sources * underlying_es,size_t reseed_interval)588       std::unique_ptr<Botan::Stateful_RNG> create_rng(Botan::RandomNumberGenerator* underlying_rng,
589                                                       Botan::Entropy_Sources* underlying_es,
590                                                       size_t reseed_interval) override
591          {
592          if(underlying_rng && underlying_es)
593             return std::unique_ptr<Botan::Stateful_RNG>(new Botan::ChaCha_RNG(*underlying_rng, *underlying_es, reseed_interval));
594          else if(underlying_rng)
595             return std::unique_ptr<Botan::Stateful_RNG>(new Botan::ChaCha_RNG(*underlying_rng, reseed_interval));
596          else if(underlying_es)
597             return std::unique_ptr<Botan::Stateful_RNG>(new Botan::ChaCha_RNG(*underlying_es, reseed_interval));
598          else if(reseed_interval == 0)
599             return std::unique_ptr<Botan::Stateful_RNG>(new Botan::ChaCha_RNG());
600          else
601             throw Test_Error("Invalid reseed interval in ChaCha_RNG unit test");
602          }
603 
test_security_level()604       Test::Result test_security_level() override
605          {
606          Test::Result result("ChaCha_RNG Security Level");
607          Botan::ChaCha_RNG rng;
608          result.test_eq("Expected security level", rng.security_level(), size_t(256));
609          return result;
610          }
611 
test_max_number_of_bytes_per_request()612       Test::Result test_max_number_of_bytes_per_request() override
613          {
614          Test::Result result("ChaCha_RNG max_number_of_bytes_per_request");
615          // ChaCha_RNG doesn't have this notion
616          return result;
617          }
618 
test_reseed_interval_limits()619       Test::Result test_reseed_interval_limits() override
620          {
621          Test::Result result("ChaCha_RNG reseed_interval limits");
622          // ChaCha_RNG doesn't apply any limits to reseed_interval
623          return result;
624          }
625 
test_reseed_kat()626       Test::Result test_reseed_kat() override
627          {
628          Test::Result result("ChaCha_RNG Reseed KAT");
629 
630          Request_Counting_RNG counting_rng;
631          std::unique_ptr<Botan::Stateful_RNG> rng = make_rng(counting_rng, 2);
632 
633          const Botan::secure_vector<uint8_t> seed_input(32);
634 
635          result.test_eq("is_seeded", rng->is_seeded(), false);
636 
637          rng->initialize_with(seed_input.data(), seed_input.size());
638 
639          Botan::secure_vector<uint8_t> out(32);
640 
641          rng->randomize(out.data(), out.size());
642          result.test_eq("underlying RNG calls", counting_rng.randomize_count(), size_t(0));
643          result.test_eq("out before reseed", out, "1F0E6F13429D5073B59C057C37CBE9587740A0A894D247E2596C393CE91DDC6F");
644 
645          // reseed must happen here
646          rng->randomize(out.data(), out.size());
647          result.test_eq("underlying RNG calls", counting_rng.randomize_count(), size_t(1));
648          result.test_eq("out after reseed", out, "F2CAE73F22684D5D773290B48FDCDA0E6C0661EBA0A854AFEC922832BDBB9C49");
649 
650          return result;
651          }
652 
653    };
654 
655 BOTAN_REGISTER_TEST("rng", "chacha_rng_unit", ChaCha_RNG_Unit_Tests);
656 
657 #endif
658 
659 #if defined(BOTAN_HAS_AUTO_RNG)
660 
661 class AutoSeeded_RNG_Tests final : public Test
662    {
663    private:
auto_rng_tests()664       Test::Result auto_rng_tests()
665          {
666          Test::Result result("AutoSeeded_RNG");
667 
668          Botan::Entropy_Sources no_entropy_for_you;
669          Botan::Null_RNG null_rng;
670 
671          result.test_eq("Null_RNG is null", null_rng.is_seeded(), false);
672 
673          try
674             {
675             Botan::AutoSeeded_RNG rng(no_entropy_for_you);
676             result.test_failure("AutoSeeded_RNG should have rejected useless entropy source");
677             }
678          catch(Botan::PRNG_Unseeded&)
679             {
680             result.test_success("AutoSeeded_RNG rejected empty entropy source");
681             }
682 
683          try
684             {
685             Botan::AutoSeeded_RNG rng(null_rng);
686             }
687          catch(Botan::PRNG_Unseeded&)
688             {
689             result.test_success("AutoSeeded_RNG rejected useless RNG");
690             }
691 
692          try
693             {
694             Botan::AutoSeeded_RNG rng(null_rng,
695                                       no_entropy_for_you);
696             }
697          catch(Botan::PRNG_Unseeded&)
698             {
699             result.test_success("AutoSeeded_RNG rejected useless RNG+entropy sources");
700             }
701 
702          Botan::AutoSeeded_RNG rng;
703 
704          result.test_eq("AutoSeeded_RNG::name", rng.name(),
705                         std::string("HMAC_DRBG(") + BOTAN_AUTO_RNG_HMAC + ")");
706 
707          result.confirm("AutoSeeded_RNG starts seeded", rng.is_seeded());
708          rng.random_vec(16); // generate and discard output
709          rng.clear();
710          result.test_eq("AutoSeeded_RNG unseeded after calling clear", rng.is_seeded(), false);
711 
712          // AutoSeeded_RNG automatically reseeds as required:
713          rng.random_vec(16);
714          result.confirm("AutoSeeded_RNG can be reseeded", rng.is_seeded());
715 
716          result.confirm("AutoSeeded_RNG ", rng.is_seeded());
717          rng.random_vec(16); // generate and discard output
718          rng.clear();
719          result.test_eq("AutoSeeded_RNG unseeded after calling clear", rng.is_seeded(), false);
720 
721          const size_t no_entropy_bits = rng.reseed(no_entropy_for_you, 256, std::chrono::milliseconds(300));
722          result.test_eq("AutoSeeded_RNG can't reseed from nothing", no_entropy_bits, 0);
723          result.test_eq("AutoSeeded_RNG still unseeded", rng.is_seeded(), false);
724 
725          rng.random_vec(16); // generate and discard output
726          result.confirm("AutoSeeded_RNG can be reseeded", rng.is_seeded());
727 
728          rng.clear();
729 
730          return result;
731          }
732 
733    public:
run()734       std::vector<Test::Result> run() override
735          {
736          std::vector<Test::Result> results;
737          results.push_back(auto_rng_tests());
738          return results;
739          }
740    };
741 
742 BOTAN_REGISTER_TEST("rng", "auto_rng_unit", AutoSeeded_RNG_Tests);
743 
744 #endif
745 
746 #if defined(BOTAN_HAS_SYSTEM_RNG)
747 
748 class System_RNG_Tests final : public Test
749    {
750    public:
run()751       std::vector<Test::Result> run() override
752          {
753          Test::Result result("System_RNG");
754 
755          Botan::System_RNG rng;
756 
757          result.test_gte("Some non-empty name is returned", rng.name().size(), 1);
758 
759          result.confirm("System RNG always seeded", rng.is_seeded());
760          rng.clear(); // clear is a noop for system rng
761          result.confirm("System RNG always seeded", rng.is_seeded());
762 
763          rng.reseed(Botan::Entropy_Sources::global_sources(),
764                     256,
765                     std::chrono::milliseconds(100));
766 
767          for(size_t i = 0; i != 128; ++i)
768             {
769             std::vector<uint8_t> out_buf(i);
770             rng.randomize(out_buf.data(), out_buf.size());
771             rng.add_entropy(out_buf.data(), out_buf.size());
772             }
773 
774          return std::vector<Test::Result>{result};
775          }
776    };
777 
778 BOTAN_REGISTER_TEST("rng", "system_rng", System_RNG_Tests);
779 
780 #endif
781 
782 #if defined(BOTAN_HAS_PROCESSOR_RNG)
783 
784 class Processor_RNG_Tests final : public Test
785    {
786    public:
run()787       std::vector<Test::Result> run() override
788          {
789          Test::Result result("Processor_RNG");
790 
791          if(Botan::Processor_RNG::available())
792             {
793             Botan::Processor_RNG rng;
794 
795             result.test_ne("Has a name", rng.name(), "");
796             result.confirm("CPU RNG always seeded", rng.is_seeded());
797             rng.clear(); // clear is a noop for rdrand
798             result.confirm("CPU RNG always seeded", rng.is_seeded());
799 
800             size_t reseed_bits = rng.reseed(Botan::Entropy_Sources::global_sources(),
801                                             256,
802                                             std::chrono::seconds(1));
803             result.test_eq("CPU RNG cannot consume inputs", reseed_bits, size_t(0));
804 
805             /*
806             Processor_RNG ignores add_entropy calls - confirm this by passing
807             an invalid ptr/length field to add_entropy. If it examined its
808             arguments, it would crash...
809             */
810             const uint8_t* invalid_ptr = reinterpret_cast<const uint8_t*>(static_cast<uintptr_t>(0xDEADC0DE));
811             const size_t invalid_ptr_len = 64*1024;
812             rng.add_entropy(invalid_ptr, invalid_ptr_len);
813 
814             for(size_t i = 0; i != 128; ++i)
815                {
816                std::vector<uint8_t> out_buf(i);
817                rng.randomize(out_buf.data(), out_buf.size());
818                }
819             }
820          else
821             {
822             result.test_throws("Processor_RNG throws if instruction not available",
823                                []() { Botan::Processor_RNG rng; });
824             }
825 
826 
827          return std::vector<Test::Result>{result};
828          }
829    };
830 
831 BOTAN_REGISTER_TEST("rng", "processor_rng", Processor_RNG_Tests);
832 
833 #endif
834 
835 }
836 
837 }
838