From 26de77618eb2191db6d74df97841b00a4fd30bb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Thu, 4 Aug 2022 20:23:52 +0200 Subject: [PATCH] Handle all-zero state in Xoshiro256** - Retry if the CSPRNG generates a zero state. - Throw ValueError if the user passes a zero state. Fixes GH-9249 --- NEWS | 2 ++ ext/random/engine_xoshiro256starstar.c | 16 ++++++++++++---- .../tests/02_engine/xoshiro256starstar_seed.phpt | 7 +++++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 1a81ed2da6e3d..874967cad9ea5 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,8 @@ PHP NEWS PcgOneseq128XslRr64::__construct()). (timwolla) . Fixed bug GH-9190, GH-9191 (undefined behavior for MT_RAND_PHP when handling large ranges). (timwolla) + . Fixed bug GH-9249 (Xoshiro256StarStar does not reject the invalid + all-zero state). (timwolla) . Removed redundant RuntimeExceptions from Randomizer methods. The exceptions thrown by the engines will be exposed directly. (timwolla) . Added extension specific Exceptions/Errors (RandomException, RandomError, diff --git a/ext/random/engine_xoshiro256starstar.c b/ext/random/engine_xoshiro256starstar.c index 1e48f3470da13..8d842143dbd0c 100644 --- a/ext/random/engine_xoshiro256starstar.c +++ b/ext/random/engine_xoshiro256starstar.c @@ -205,10 +205,12 @@ PHP_METHOD(Random_Engine_Xoshiro256StarStar, __construct) ZEND_PARSE_PARAMETERS_END(); if (seed_is_null) { - if (php_random_bytes_throw(&state->state, 32) == FAILURE) { - zend_throw_exception(random_ce_Random_RandomException, "Failed to generate a random seed", 0); - RETURN_THROWS(); - } + do { + if (php_random_bytes_throw(&state->state, 32) == FAILURE) { + zend_throw_exception(random_ce_Random_RandomException, "Failed to generate a random seed", 0); + RETURN_THROWS(); + } + } while (UNEXPECTED(state->state[0] == 0 && state->state[1] == 0 && state->state[2] == 0 && state->state[3] == 0)); } else { if (str_seed) { /* char (byte: 8 bit) * 32 = 256 bits */ @@ -222,6 +224,12 @@ PHP_METHOD(Random_Engine_Xoshiro256StarStar, __construct) t[i] += ((uint64_t) (unsigned char) ZSTR_VAL(str_seed)[(i * 8) + j]) << (j * 8); } } + + if (UNEXPECTED(t[0] == 0 && t[1] == 0 && t[2] == 0 && t[3] == 0)) { + zend_argument_value_error(1, "must not consist entirely of NUL bytes"); + RETURN_THROWS(); + } + seed256(engine->status, t[0], t[1], t[2], t[3]); } else { zend_argument_value_error(1, "must be a 32 byte (256 bit) string"); diff --git a/ext/random/tests/02_engine/xoshiro256starstar_seed.phpt b/ext/random/tests/02_engine/xoshiro256starstar_seed.phpt index 2bf107dd5da85..74bcf7331d9fe 100644 --- a/ext/random/tests/02_engine/xoshiro256starstar_seed.phpt +++ b/ext/random/tests/02_engine/xoshiro256starstar_seed.phpt @@ -18,6 +18,12 @@ try { echo $e->getMessage() . PHP_EOL; } +try { + $engine = new Random\Engine\Xoshiro256StarStar(\str_repeat("\x00", 32)); +} catch (\Throwable $e) { + echo $e->getMessage() . PHP_EOL; +} + $engine = new \Random\Engine\Xoshiro256StarStar("\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08"); \var_dump($engine); @@ -31,6 +37,7 @@ for ($i = 0; $i < 1000; $i++) { --EXPECTF-- Random\Engine\Xoshiro256StarStar::__construct(): Argument #1 ($seed) must be of type string|int|null, float given Random\Engine\Xoshiro256StarStar::__construct(): Argument #1 ($seed) must be a 32 byte (256 bit) string +Random\Engine\Xoshiro256StarStar::__construct(): Argument #1 ($seed) must not consist entirely of NUL bytes object(Random\Engine\Xoshiro256StarStar)#%d (%d) { ["__states"]=> array(4) {