Skip to content

Commit 1cd2d73

Browse files
authored
Handle all-zero state in Xoshiro256** (#9250)
- Retry if the CSPRNG generates a zero state. - Throw ValueError if the user passes a zero state. Fixes GH-9249
1 parent f51fbf9 commit 1cd2d73

File tree

3 files changed

+21
-4
lines changed

3 files changed

+21
-4
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ PHP NEWS
1212
PcgOneseq128XslRr64::__construct()). (timwolla)
1313
. Fixed bug GH-9190, GH-9191 (undefined behavior for MT_RAND_PHP when
1414
handling large ranges). (timwolla)
15+
. Fixed bug GH-9249 (Xoshiro256StarStar does not reject the invalid
16+
all-zero state). (timwolla)
1517
. Removed redundant RuntimeExceptions from Randomizer methods. The
1618
exceptions thrown by the engines will be exposed directly. (timwolla)
1719
. Added extension specific Exceptions/Errors (RandomException, RandomError,

ext/random/engine_xoshiro256starstar.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,10 +205,12 @@ PHP_METHOD(Random_Engine_Xoshiro256StarStar, __construct)
205205
ZEND_PARSE_PARAMETERS_END();
206206

207207
if (seed_is_null) {
208-
if (php_random_bytes_throw(&state->state, 32) == FAILURE) {
209-
zend_throw_exception(random_ce_Random_RandomException, "Failed to generate a random seed", 0);
210-
RETURN_THROWS();
211-
}
208+
do {
209+
if (php_random_bytes_throw(&state->state, 32) == FAILURE) {
210+
zend_throw_exception(random_ce_Random_RandomException, "Failed to generate a random seed", 0);
211+
RETURN_THROWS();
212+
}
213+
} while (UNEXPECTED(state->state[0] == 0 && state->state[1] == 0 && state->state[2] == 0 && state->state[3] == 0));
212214
} else {
213215
if (str_seed) {
214216
/* char (byte: 8 bit) * 32 = 256 bits */
@@ -222,6 +224,12 @@ PHP_METHOD(Random_Engine_Xoshiro256StarStar, __construct)
222224
t[i] += ((uint64_t) (unsigned char) ZSTR_VAL(str_seed)[(i * 8) + j]) << (j * 8);
223225
}
224226
}
227+
228+
if (UNEXPECTED(t[0] == 0 && t[1] == 0 && t[2] == 0 && t[3] == 0)) {
229+
zend_argument_value_error(1, "must not consist entirely of NUL bytes");
230+
RETURN_THROWS();
231+
}
232+
225233
seed256(engine->status, t[0], t[1], t[2], t[3]);
226234
} else {
227235
zend_argument_value_error(1, "must be a 32 byte (256 bit) string");

ext/random/tests/02_engine/xoshiro256starstar_seed.phpt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ try {
1818
echo $e->getMessage() . PHP_EOL;
1919
}
2020

21+
try {
22+
$engine = new Random\Engine\Xoshiro256StarStar(\str_repeat("\x00", 32));
23+
} catch (\Throwable $e) {
24+
echo $e->getMessage() . PHP_EOL;
25+
}
26+
2127
$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");
2228

2329
\var_dump($engine);
@@ -31,6 +37,7 @@ for ($i = 0; $i < 1000; $i++) {
3137
--EXPECTF--
3238
Random\Engine\Xoshiro256StarStar::__construct(): Argument #1 ($seed) must be of type string|int|null, float given
3339
Random\Engine\Xoshiro256StarStar::__construct(): Argument #1 ($seed) must be a 32 byte (256 bit) string
40+
Random\Engine\Xoshiro256StarStar::__construct(): Argument #1 ($seed) must not consist entirely of NUL bytes
3441
object(Random\Engine\Xoshiro256StarStar)#%d (%d) {
3542
["__states"]=>
3643
array(4) {

0 commit comments

Comments
 (0)