Skip to content

Commit

Permalink
Merge pull request #127 from hulet/backport-1788eb2
Browse files Browse the repository at this point in the history
backport 1788eb2
  • Loading branch information
paragonie-scott authored Mar 13, 2017
2 parents 1115ffa + 260f122 commit 572a26a
Show file tree
Hide file tree
Showing 6 changed files with 347 additions and 336 deletions.
100 changes: 51 additions & 49 deletions lib/random_bytes_com_dotnet.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,56 +26,58 @@
* SOFTWARE.
*/

/**
* Windows with PHP < 5.3.0 will not have the function
* openssl_random_pseudo_bytes() available, so let's use
* CAPICOM to work around this deficiency.
*
* @param int $bytes
*
* @throws Exception
*
* @return string
*/
function random_bytes($bytes)
{
try {
$bytes = RandomCompat_intval($bytes);
} catch (TypeError $ex) {
throw new TypeError(
'random_bytes(): $bytes must be an integer'
);
}

if ($bytes < 1) {
throw new Error(
'Length must be greater than 0'
);
}

$buf = '';
$util = new COM('CAPICOM.Utilities.1');
$execCount = 0;

if (!is_callable('random_bytes')) {
/**
* Let's not let it loop forever. If we run N times and fail to
* get N bytes of random data, then CAPICOM has failed us.
* Windows with PHP < 5.3.0 will not have the function
* openssl_random_pseudo_bytes() available, so let's use
* CAPICOM to work around this deficiency.
*
* @param int $bytes
*
* @throws Exception
*
* @return string
*/
do {
$buf .= base64_decode($util->GetRandom($bytes, 0));
if (RandomCompat_strlen($buf) >= $bytes) {
/**
* Return our random entropy buffer here:
*/
return RandomCompat_substr($buf, 0, $bytes);
function random_bytes($bytes)
{
try {
$bytes = RandomCompat_intval($bytes);
} catch (TypeError $ex) {
throw new TypeError(
'random_bytes(): $bytes must be an integer'
);
}
++$execCount;
} while ($execCount < $bytes);

/**
* If we reach here, PHP has failed us.
*/
throw new Exception(
'Could not gather sufficient random data'
);
}
if ($bytes < 1) {
throw new Error(
'Length must be greater than 0'
);
}

$buf = '';
$util = new COM('CAPICOM.Utilities.1');
$execCount = 0;

/**
* Let's not let it loop forever. If we run N times and fail to
* get N bytes of random data, then CAPICOM has failed us.
*/
do {
$buf .= base64_decode($util->GetRandom($bytes, 0));
if (RandomCompat_strlen($buf) >= $bytes) {
/**
* Return our random entropy buffer here:
*/
return RandomCompat_substr($buf, 0, $bytes);
}
++$execCount;
} while ($execCount < $bytes);

/**
* If we reach here, PHP has failed us.
*/
throw new Exception(
'Could not gather sufficient random data'
);
}
}
190 changes: 96 additions & 94 deletions lib/random_bytes_dev_urandom.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,119 +30,121 @@
define('RANDOM_COMPAT_READ_BUFFER', 8);
}

/**
* Unless open_basedir is enabled, use /dev/urandom for
* random numbers in accordance with best practices
*
* Why we use /dev/urandom and not /dev/random
* @ref http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers
*
* @param int $bytes
*
* @throws Exception
*
* @return string
*/
function random_bytes($bytes)
{
static $fp = null;
if (!is_callable('random_bytes')) {
/**
* This block should only be run once
* Unless open_basedir is enabled, use /dev/urandom for
* random numbers in accordance with best practices
*
* Why we use /dev/urandom and not /dev/random
* @ref http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers
*
* @param int $bytes
*
* @throws Exception
*
* @return string
*/
if (empty($fp)) {
function random_bytes($bytes)
{
static $fp = null;
/**
* We use /dev/urandom if it is a char device.
* We never fall back to /dev/random
* This block should only be run once
*/
$fp = fopen('/dev/urandom', 'rb');
if (!empty($fp)) {
$st = fstat($fp);
if (($st['mode'] & 0170000) !== 020000) {
fclose($fp);
$fp = false;
}
}

if (!empty($fp)) {
if (empty($fp)) {
/**
* stream_set_read_buffer() does not exist in HHVM
*
* If we don't set the stream's read buffer to 0, PHP will
* internally buffer 8192 bytes, which can waste entropy
*
* stream_set_read_buffer returns 0 on success
* We use /dev/urandom if it is a char device.
* We never fall back to /dev/random
*/
if (function_exists('stream_set_read_buffer')) {
stream_set_read_buffer($fp, RANDOM_COMPAT_READ_BUFFER);
$fp = fopen('/dev/urandom', 'rb');
if (!empty($fp)) {
$st = fstat($fp);
if (($st['mode'] & 0170000) !== 020000) {
fclose($fp);
$fp = false;
}
}
if (function_exists('stream_set_chunk_size')) {
stream_set_chunk_size($fp, RANDOM_COMPAT_READ_BUFFER);

if (!empty($fp)) {
/**
* stream_set_read_buffer() does not exist in HHVM
*
* If we don't set the stream's read buffer to 0, PHP will
* internally buffer 8192 bytes, which can waste entropy
*
* stream_set_read_buffer returns 0 on success
*/
if (function_exists('stream_set_read_buffer')) {
stream_set_read_buffer($fp, RANDOM_COMPAT_READ_BUFFER);
}
if (function_exists('stream_set_chunk_size')) {
stream_set_chunk_size($fp, RANDOM_COMPAT_READ_BUFFER);
}
}
}
}

try {
$bytes = RandomCompat_intval($bytes);
} catch (TypeError $ex) {
throw new TypeError(
'random_bytes(): $bytes must be an integer'
);
}

if ($bytes < 1) {
throw new Error(
'Length must be greater than 0'
);
}
try {
$bytes = RandomCompat_intval($bytes);
} catch (TypeError $ex) {
throw new TypeError(
'random_bytes(): $bytes must be an integer'
);
}

/**
* This if() block only runs if we managed to open a file handle
*
* It does not belong in an else {} block, because the above
* if (empty($fp)) line is logic that should only be run once per
* page load.
*/
if (!empty($fp)) {
$remaining = $bytes;
$buf = '';
if ($bytes < 1) {
throw new Error(
'Length must be greater than 0'
);
}

/**
* We use fread() in a loop to protect against partial reads
* This if() block only runs if we managed to open a file handle
*
* It does not belong in an else {} block, because the above
* if (empty($fp)) line is logic that should only be run once per
* page load.
*/
do {
$read = fread($fp, $remaining);
if ($read === false) {
/**
* We cannot safely read from the file. Exit the
* do-while loop and trigger the exception condition
*/
$buf = false;
break;
}
if (!empty($fp)) {
$remaining = $bytes;
$buf = '';

/**
* Decrease the number of bytes returned from remaining
* We use fread() in a loop to protect against partial reads
*/
$remaining -= RandomCompat_strlen($read);
$buf .= $read;
} while ($remaining > 0);

/**
* Is our result valid?
*/
if ($buf !== false) {
if (RandomCompat_strlen($buf) === $bytes) {
do {
$read = fread($fp, $remaining);
if ($read === false) {
/**
* We cannot safely read from the file. Exit the
* do-while loop and trigger the exception condition
*/
$buf = false;
break;
}
/**
* Return our random entropy buffer here:
* Decrease the number of bytes returned from remaining
*/
return $buf;
$remaining -= RandomCompat_strlen($read);
$buf .= $read;
} while ($remaining > 0);

/**
* Is our result valid?
*/
if ($buf !== false) {
if (RandomCompat_strlen($buf) === $bytes) {
/**
* Return our random entropy buffer here:
*/
return $buf;
}
}
}
}

/**
* If we reach here, PHP has failed us.
*/
throw new Exception(
'Error reading from source device'
);
/**
* If we reach here, PHP has failed us.
*/
throw new Exception(
'Error reading from source device'
);
}
}
Loading

0 comments on commit 572a26a

Please sign in to comment.