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