Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Port PHP7 CSPRNG functions random_int() and random_bytes()
Summary: Hello! This PR is a port of the [CSPRNG functions](http://php.net/csprng) `random_*()` which were [added in PHP7](https://wiki.php.net/rfc/easy_userland_csprng). This PR is very much a work in progress and I'll need a lot of help from you smarter kids to get this implemented properly. But it works well on my machine thanks to some one-on-one help from jmikola. The things that I know need to be addressed: 1. The PHP version [checks for sources of random at compile time](https://github.com/php/php-src/blob/97f159d70288ae94f9a05a370121bcbea760ed9a/Zend/Zend.m4#L406-L412). Not sure how to do this in HHVM. 2. PHP [supports Windows with `arc4random_buf()`](https://github.com/php/php-src/blob/cbcacbb2dad4c97ba5653f42729f7956193d9112/ext/standard/random.c#L86). Not sure if we want to support this as well as HHVM gets more Windows friendly... is that a thing? 3. There is [an open PR](php/php-src#1397) to change the behavior of handling the cases when a reliable source of random cann Closes #5498 Closes #5925 Reviewed By: sgolemon Differential Revision: D2342229 Pulled By: jwatzman fb-gh-sync-id: 419d949e3dd06fb1c13ecf86223c1b28eb57bb84
- Loading branch information
Showing
5 changed files
with
153 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
HHVM_EXTENSION(random ext_random.cpp) | ||
HHVM_SYSTEMLIB(random ext_random.php) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
/* | ||
+----------------------------------------------------------------------+ | ||
| HipHop for PHP | | ||
+----------------------------------------------------------------------+ | ||
| Copyright (c) 2010-2015 Facebook, Inc. (http://www.facebook.com) | | ||
| Copyright (c) 1997-2010 The PHP Group | | ||
+----------------------------------------------------------------------+ | ||
| This source file is subject to version 3.01 of the PHP license, | | ||
| that is bundled with this package in the file LICENSE, and is | | ||
| available through the world-wide-web at the following url: | | ||
| http://www.php.net/license/3_01.txt | | ||
| If you did not receive a copy of the PHP license and are unable to | | ||
| obtain it through the world-wide-web, please send a note to | | ||
| license@php.net so we can mail you a copy immediately. | | ||
+----------------------------------------------------------------------+ | ||
*/ | ||
|
||
#include "hphp/runtime/ext/extension.h" | ||
#include "hphp/runtime/base/execution-context.h" | ||
#include "hphp/runtime/vm/runtime.h" | ||
|
||
#include <folly/Random.h> | ||
|
||
namespace HPHP { | ||
/////////////////////////////////////////////////////////////////////////////// | ||
|
||
static bool getRandomBytes(void *bytes, size_t length) { | ||
// TODO fix folly to better detect error cases (currently I think it just | ||
// aborts) and catch them here. | ||
folly::Random::secureRandom(bytes, length); | ||
return true; | ||
} | ||
|
||
String HHVM_FUNCTION(random_bytes, int64_t length) { | ||
if (length < 1) { | ||
// TODO(https://github.com/facebook/hhvm/issues/6012) | ||
// Make this throw PHP 7 `Error` when it's implemented | ||
SystemLib::throwExceptionObject("Length must be greater than 0"); | ||
} | ||
|
||
String ret(length, ReserveString); | ||
if (!getRandomBytes(ret.mutableData(), ret.capacity())) { | ||
SystemLib::throwExceptionObject("Could not gather sufficient random data"); | ||
} | ||
|
||
return ret.setSize(length); | ||
} | ||
|
||
int64_t HHVM_FUNCTION(random_int, int64_t min, int64_t max) { | ||
if (min > max) { | ||
// TODO(https://github.com/facebook/hhvm/issues/6012) | ||
// Make this throw PHP 7 `Error` when it's implemented | ||
SystemLib::throwExceptionObject( | ||
"Minimum value must be less than or equal to the maximum value"); | ||
} | ||
|
||
if (min == max) { | ||
return min; | ||
} | ||
|
||
uint64_t umax = max - min; | ||
uint64_t result; | ||
if (!getRandomBytes(&result, sizeof(result))) { | ||
SystemLib::throwExceptionObject("Could not gather sufficient random data"); | ||
} | ||
|
||
// Special case where no modulus is required | ||
if (umax == std::numeric_limits<uint64_t>::max()) { | ||
return result; | ||
} | ||
|
||
// Increment the max so the range is inclusive of max | ||
umax++; | ||
|
||
// Powers of two are not biased | ||
if ((umax & (umax - 1)) != 0) { | ||
// Ceiling under which std::numeric_limits<uint64_t>::max() % max == 0 | ||
int64_t limit = std::numeric_limits<uint64_t>::max() - | ||
(std::numeric_limits<uint64_t>::max() % umax) - 1; | ||
|
||
// Discard numbers over the limit to avoid modulo bias | ||
while (result > limit) { | ||
if (!getRandomBytes(&result, sizeof(result))) { | ||
SystemLib::throwExceptionObject( | ||
"Could not gather sufficient random data"); | ||
} | ||
} | ||
} | ||
|
||
return (int64_t)((result % umax) + min); | ||
} | ||
|
||
static struct RandomExtension final : public Extension { | ||
RandomExtension() : Extension("random") {} | ||
void moduleInit() override { | ||
HHVM_FE(random_bytes); | ||
HHVM_FE(random_int); | ||
loadSystemlib(); | ||
} | ||
} s_random_extension; | ||
|
||
HHVM_GET_MODULE(random); | ||
|
||
/////////////////////////////////////////////////////////////////////////////// | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<?hh | ||
|
||
/** | ||
* Generates cryptographically secure pseudo-random bytes that are suitable for | ||
* use in cryptography when generating salts, keys and initialization vectors. | ||
* | ||
* @param int $length - The length of the random string in bytes. | ||
* | ||
* @return string - The crypto-secure random bytes in binary format. | ||
* | ||
* @throws Exception - If generating sufficiently random data fails. | ||
* | ||
*/ | ||
<<__Native>> | ||
function random_bytes(int $length): string; | ||
|
||
/** | ||
* Generates cryptographic random integers that are suitable for use where | ||
* unbiased results are critical (e.g. shuffling a Poker deck). | ||
* | ||
* @param int $min - The lowest value to be returned down to PHP_INT_MIN. | ||
* @param int $max - The highest value to be returned up to PHP_INT_MAX. | ||
* | ||
* @return int - The crypto-secure random integer. | ||
* | ||
* @throws Exception - If generating sufficiently random data fails. | ||
* @throws Error - If $min > $max. | ||
* | ||
*/ | ||
<<__Native>> | ||
function random_int(int $min, int $max): int; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?php | ||
|
||
var_dump(strlen(random_bytes(7))); | ||
var_dump(random_int(1, 10)); | ||
|
||
// Astronomically low chance of a false positive here, and making sure we don't | ||
// accidentally return a constant value is worth it. | ||
var_dump(random_bytes(16) === random_bytes(16)); | ||
var_dump( | ||
random_int(PHP_INT_MIN, PHP_INT_MAX) === random_int(PHP_INT_MIN, PHP_INT_MAX) | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
int(7) | ||
int(%d) | ||
bool(false) | ||
bool(false) |