summaryrefslogtreecommitdiff
path: root/includes/bootstrap.inc
diff options
context:
space:
mode:
Diffstat (limited to 'includes/bootstrap.inc')
-rw-r--r--includes/bootstrap.inc105
1 files changed, 73 insertions, 32 deletions
diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc
index e31322c0c..1c8b5c72d 100644
--- a/includes/bootstrap.inc
+++ b/includes/bootstrap.inc
@@ -8,7 +8,7 @@
/**
* The current system version.
*/
-define('VERSION', '7.24-dev');
+define('VERSION', '7.25-dev');
/**
* Core API compatibility.
@@ -1933,6 +1933,33 @@ function drupal_block_denied($ip) {
}
/**
+ * Returns a URL-safe, base64 encoded string of highly randomized bytes (over the full 8-bit range).
+ *
+ * @param $byte_count
+ * The number of random bytes to fetch and base64 encode.
+ *
+ * @return string
+ * The base64 encoded result will have a length of up to 4 * $byte_count.
+ */
+function drupal_random_key($byte_count = 32) {
+ return drupal_base64_encode(drupal_random_bytes($byte_count));
+}
+
+/**
+ * Returns a URL-safe, base64 encoded version of the supplied string.
+ *
+ * @param $string
+ * The string to convert to base64.
+ *
+ * @return string
+ */
+function drupal_base64_encode($string) {
+ $data = base64_encode($string);
+ // Modify the output so it's safe to use in URLs.
+ return strtr($data, array('+' => '-', '/' => '_', '=' => ''));
+}
+
+/**
* Returns a string of highly randomized bytes (over the full 8-bit range).
*
* This function is better than simply calling mt_rand() or any other built-in
@@ -1945,38 +1972,34 @@ function drupal_block_denied($ip) {
*/
function drupal_random_bytes($count) {
// $random_state does not use drupal_static as it stores random bytes.
- static $random_state, $bytes, $php_compatible;
- // Initialize on the first call. The contents of $_SERVER includes a mix of
- // user-specific and system information that varies a little with each page.
- if (!isset($random_state)) {
- $random_state = print_r($_SERVER, TRUE);
- if (function_exists('getmypid')) {
- // Further initialize with the somewhat random PHP process ID.
- $random_state .= getmypid();
- }
- $bytes = '';
- }
- if (strlen($bytes) < $count) {
+ static $random_state, $bytes, $has_openssl;
+
+ $missing_bytes = $count - strlen($bytes);
+
+ if ($missing_bytes > 0) {
// PHP versions prior 5.3.4 experienced openssl_random_pseudo_bytes()
// locking on Windows and rendered it unusable.
- if (!isset($php_compatible)) {
- $php_compatible = version_compare(PHP_VERSION, '5.3.4', '>=');
+ if (!isset($has_openssl)) {
+ $has_openssl = version_compare(PHP_VERSION, '5.3.4', '>=') && function_exists('openssl_random_pseudo_bytes');
}
- // /dev/urandom is available on many *nix systems and is considered the
- // best commonly available pseudo-random source.
- if ($fh = @fopen('/dev/urandom', 'rb')) {
+
+ // openssl_random_pseudo_bytes() will find entropy in a system-dependent
+ // way.
+ if ($has_openssl) {
+ $bytes .= openssl_random_pseudo_bytes($missing_bytes);
+ }
+
+ // Else, read directly from /dev/urandom, which is available on many *nix
+ // systems and is considered cryptographically secure.
+ elseif ($fh = @fopen('/dev/urandom', 'rb')) {
// PHP only performs buffered reads, so in reality it will always read
// at least 4096 bytes. Thus, it costs nothing extra to read and store
// that much so as to speed any additional invocations.
- $bytes .= fread($fh, max(4096, $count));
+ $bytes .= fread($fh, max(4096, $missing_bytes));
fclose($fh);
}
- // openssl_random_pseudo_bytes() will find entropy in a system-dependent
- // way.
- elseif ($php_compatible && function_exists('openssl_random_pseudo_bytes')) {
- $bytes .= openssl_random_pseudo_bytes($count - strlen($bytes));
- }
- // If /dev/urandom is not available or returns no bytes, this loop will
+
+ // If we couldn't get enough entropy, this simple hash-based PRNG will
// generate a good set of pseudo-random bytes on any system.
// Note that it may be important that our $random_state is passed
// through hash() prior to being rolled into $output, that the two hash()
@@ -1984,9 +2007,23 @@ function drupal_random_bytes($count) {
// the microtime() - is prepended rather than appended. This is to avoid
// directly leaking $random_state via the $output stream, which could
// allow for trivial prediction of further "random" numbers.
- while (strlen($bytes) < $count) {
- $random_state = hash('sha256', microtime() . mt_rand() . $random_state);
- $bytes .= hash('sha256', mt_rand() . $random_state, TRUE);
+ if (strlen($bytes) < $count) {
+ // Initialize on the first call. The contents of $_SERVER includes a mix of
+ // user-specific and system information that varies a little with each page.
+ if (!isset($random_state)) {
+ $random_state = print_r($_SERVER, TRUE);
+ if (function_exists('getmypid')) {
+ // Further initialize with the somewhat random PHP process ID.
+ $random_state .= getmypid();
+ }
+ $bytes = '';
+ }
+
+ do {
+ $random_state = hash('sha256', microtime() . mt_rand() . $random_state);
+ $bytes .= hash('sha256', mt_rand() . $random_state, TRUE);
+ }
+ while (strlen($bytes) < $count);
}
}
$output = substr($bytes, 0, $count);
@@ -1997,17 +2034,21 @@ function drupal_random_bytes($count) {
/**
* Calculates a base-64 encoded, URL-safe sha-256 hmac.
*
- * @param $data
+ * @param string $data
* String to be validated with the hmac.
- * @param $key
+ * @param string $key
* A secret string key.
*
- * @return
+ * @return string
* A base-64 encoded sha-256 hmac, with + replaced with -, / with _ and
* any = padding characters removed.
*/
function drupal_hmac_base64($data, $key) {
- $hmac = base64_encode(hash_hmac('sha256', $data, $key, TRUE));
+ // Casting $data and $key to strings here is necessary to avoid empty string
+ // results of the hash function if they are not scalar values. As this
+ // function is used in security-critical contexts like token validation it is
+ // important that it never returns an empty string.
+ $hmac = base64_encode(hash_hmac('sha256', (string) $data, (string) $key, TRUE));
// Modify the hmac so it's safe to use in URLs.
return strtr($hmac, array('+' => '-', '/' => '_', '=' => ''));
}