diff --git a/core/core.services.yml b/core/core.services.yml
index 895b384..7b10bd5 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -238,7 +238,7 @@ services:
 # password hashing method was introduced in Drupal 7 with a log2 count of 15.
   password:
     class: Drupal\Core\Password\PhpassHashedPassword
-    arguments: [16]
+    arguments: [16, '@random.bytes']
   mime_type_matcher:
     class: Drupal\Core\Routing\MimeTypeMatcher
     tags:
@@ -379,3 +379,6 @@ services:
     class: Drupal\system\Plugin\ImageToolkitInterface
     factory_method: getDefaultToolkit
     factory_service: image.toolkit.manager
+  random.bytes:
+    class: Drupal\Component\Utility\RandomBytes
+    arguments: ['@request']
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 4711c8d..ad08f19 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -1900,68 +1900,6 @@ function drupal_set_title($title = NULL, $output = CHECK_PLAIN) {
 }
 
 /**
- * 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
- * PHP function because it can return a long string of bytes (compared to < 4
- * bytes normally from mt_rand()) and uses the best available pseudo-random
- * source.
- *
- * @param $count
- *   The number of characters (bytes) to return in the string.
- */
-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) {
-    // 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', '>=');
-    }
-    // /dev/urandom is available on many *nix systems and is considered the
-    // best commonly available pseudo-random source.
-    if ($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));
-      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
-    // 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()
-    // invocations are different, and that the extra input into the first one -
-    // 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);
-    }
-  }
-  $output = substr($bytes, 0, $count);
-  $bytes = substr($bytes, $count);
-  return $output;
-}
-
-/**
  * Calculates a base-64 encoded, URL-safe sha-256 hmac.
  *
  * @param $data
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 0e824a0..b034761 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -4849,7 +4849,7 @@ function drupal_json_decode($var) {
  */
 function drupal_get_private_key() {
   if (!($key = state()->get('system.private_key'))) {
-    $key = drupal_hash_base64(drupal_random_bytes(55));
+    $key = drupal_hash_base64(Drupal::service('random.bytes')->generate());
     state()->set('system.private_key', $key);
   }
   return $key;
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 47982dd..76a459c 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -340,6 +340,8 @@ function install_begin_request(&$install_state) {
     // @todo Move into a proper Drupal\Core\DependencyInjection\InstallContainerBuilder.
     $container = new ContainerBuilder();
 
+    $container->register('request', $request);
+
     $container->register('event_dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher');
 
     $container->register('config.storage', 'Drupal\Core\Config\InstallStorage');
@@ -396,6 +398,10 @@ function install_begin_request(&$install_state) {
     // Register Twig template engine for use during install.
     CoreBundle::registerTwig($container);
 
+    // Register the RandomBytes component.
+    $container->register('random.bytes', 'Drupal\Component\Utility\RandomBytes')
+      ->addArgument(new Reference('request'));
+
     Drupal::setContainer($container);
   }
 
@@ -1138,7 +1144,7 @@ function install_settings_form_submit($form, &$form_state) {
     'required' => TRUE,
   );
   $settings['drupal_hash_salt'] = (object) array(
-    'value'    => drupal_hash_base64(drupal_random_bytes(55)),
+    'value'    => drupal_hash_base64(Drupal::service('random.bytes')->generate()),
     'required' => TRUE,
   );
 
diff --git a/core/includes/install.inc b/core/includes/install.inc
index 391750f..7e065b2 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -445,7 +445,7 @@ function drupal_install_config_directories() {
   // Add a randomized config directory name to settings.php, unless it was
   // manually defined in the existing already.
   if (empty($config_directories)) {
-    $config_directories_hash = drupal_hash_base64(drupal_random_bytes(55));
+    $config_directories_hash = drupal_hash_base64(Drupal::service('random.bytes')->generate());
     $settings['config_directories'] = array(
       CONFIG_ACTIVE_DIRECTORY => array(
         'path' => (object) array(
diff --git a/core/includes/session.inc b/core/includes/session.inc
index a0de5e9..5bea4b1 100644
--- a/core/includes/session.inc
+++ b/core/includes/session.inc
@@ -357,7 +357,7 @@ function drupal_session_regenerate() {
       $old_insecure_session_id = $_COOKIE[$insecure_session_name];
     }
     $params = session_get_cookie_params();
-    $session_id = drupal_hash_base64(uniqid(mt_rand(), TRUE) . drupal_random_bytes(55));
+    $session_id = drupal_hash_base64(uniqid(mt_rand(), TRUE) . Drupal::service('random.bytes')->generate());
     // If a session cookie lifetime is set, the session will expire
     // $params['lifetime'] seconds from the current request. If it is not set,
     // it will expire when the browser is closed.
@@ -369,7 +369,7 @@ function drupal_session_regenerate() {
   if (drupal_session_started()) {
     $old_session_id = session_id();
   }
-  session_id(drupal_hash_base64(uniqid(mt_rand(), TRUE) . drupal_random_bytes(55)));
+  session_id(drupal_hash_base64(uniqid(mt_rand(), TRUE) . Drupal::service('random.bytes')->generate()));
 
   if (isset($old_session_id)) {
     $params = session_get_cookie_params();
diff --git a/core/lib/Drupal/Component/Utility/RandomBytes.php b/core/lib/Drupal/Component/Utility/RandomBytes.php
new file mode 100644
index 0000000..1b27f6a
--- /dev/null
+++ b/core/lib/Drupal/Component/Utility/RandomBytes.php
@@ -0,0 +1,89 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Component\Utility\RandomBytes.
+ */
+
+namespace Drupal\Component\Utility;
+
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Generates randomized bytes.
+ */
+class RandomBytes {
+
+  /**
+   * The current random state.
+   *
+   * @var string
+   */
+  protected $randomState;
+
+  /**
+   * The random generated bytes string so far.
+   *
+   * @var string
+   */
+  protected $bytes = '';
+
+  /**
+   * Constructs a RandomBytes object.
+   */
+  public function __construct(Request $request) {
+    // The contents of $_SERVER includes a mix of user-specific and system
+    // information that varies a little with each page.
+    $this->randomState = print_r($request->server->all(), TRUE);
+    if (function_exists('getmypid')) {
+      // Further initialize with the somewhat random PHP process ID.
+      $this->randomState .= getmypid();
+    }
+  }
+
+  /**
+   * 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
+   * PHP function because it can return a long string of bytes (compared to < 4
+   * bytes normally from mt_rand()) and uses the best available pseudo-random
+   * source.
+   *
+   * @param int $count
+   *   The number of characters (bytes) to return in the string. Defaults to 55.
+   */
+  public function generate($count = 55) {
+    if (strlen($this->bytes) < $count) {
+      // /dev/urandom is available on many *nix systems and is considered the
+      // best commonly available pseudo-random source.
+      if ($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.
+        $this->bytes .= fread($fh, max(4096, $count));
+        fclose($fh);
+      }
+      // openssl_random_pseudo_bytes() will find entropy in a system-dependent
+      // way.
+      elseif (function_exists('openssl_random_pseudo_bytes')) {
+        $this->bytes .= openssl_random_pseudo_bytes($count - strlen($this->bytes));
+      }
+      // If /dev/urandom is not available or returns no bytes, this loop will
+      // generate a good set of pseudo-random bytes on any system.
+      // Note that it may be important that our $randomState is passed
+      // through hash() prior to being rolled into $output, that the two hash()
+      // invocations are different, and that the extra input into the first one -
+      // the microtime() - is prepended rather than appended. This is to avoid
+      // directly leaking $randomState via the $output stream, which could
+      // allow for trivial prediction of further "random" numbers.
+      while (strlen($this->bytes) < $count) {
+        $this->randomState = hash('sha256', microtime() . mt_rand() . $this->randomState);
+        $this->bytes .= hash('sha256', mt_rand() . $this->randomState, TRUE);
+      }
+    }
+    $output = substr($this->bytes, 0, $count);
+    $this->bytes = substr($this->bytes, $count);
+    return $output;
+  }
+
+}
diff --git a/core/lib/Drupal/Component/Uuid/Php.php b/core/lib/Drupal/Component/Uuid/Php.php
index fd12fc0..c4b5e4e 100644
--- a/core/lib/Drupal/Component/Uuid/Php.php
+++ b/core/lib/Drupal/Component/Uuid/Php.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Component\Uuid;
 
+use Drupal\Component\Utility\RandomBytes;
+
 /**
  * Generates a UUID v4 using PHP code.
  *
@@ -17,10 +19,25 @@
 class Php implements UuidInterface {
 
   /**
+   * The random bytes generator component.
+   *
+   * @var \Drupal\Component\Utility\RandomBytes
+   */
+  protected $randomBytes;
+
+  /**
+   * Constructs a new PHP UUID generator instance.
+   */
+  function __construct() {
+    // @todo Somehow inject this.
+    $this->randomBytes = \Drupal::service('random.bytes');
+  }
+
+  /**
    * Implements Drupal\Component\Uuid\UuidInterface::generate().
    */
   public function generate() {
-    $hex = substr(hash('sha256', drupal_random_bytes(16)), 0, 32);
+    $hex = substr(hash('sha256', $this->randomBytes->generate(16)), 0, 32);
 
     // The field names refer to RFC 4122 section 4.1.2.
     $time_low = substr($hex, 0, 8);
diff --git a/core/lib/Drupal/Core/Password/PhpassHashedPassword.php b/core/lib/Drupal/Core/Password/PhpassHashedPassword.php
index 157e14c..20d291d 100644
--- a/core/lib/Drupal/Core/Password/PhpassHashedPassword.php
+++ b/core/lib/Drupal/Core/Password/PhpassHashedPassword.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Core\Password;
 
+use Drupal\Component\Utility\RandomBytes;
+
 /**
  * Secure password hashing functions based on the Portable PHP password
  * hashing framework.
@@ -42,6 +44,13 @@ class PhpassHashedPassword implements PasswordInterface {
   protected $countLog2;
 
   /**
+   * The random bytes generator component.
+   *
+   * @var \Drupal\Component\Utility\RandomBytes
+   */
+  protected $randomBytes;
+
+  /**
    * Constructs a new phpass password hashing instance.
    *
    * @param int $countLog2
@@ -49,10 +58,13 @@ class PhpassHashedPassword implements PasswordInterface {
    *   hashing function will be applied when generating new password hashes.
    *   The number of times is calculated by raising 2 to the power of the given
    *   value.
+   * @param \Drupal\Component\Utility\RandomBytes $randomBytes
+   *   The random bytes generator component.
    */
-  function __construct($countLog2) {
+  function __construct($countLog2, RandomBytes $randomBytes) {
     // Ensure that $countLog2 is within set bounds.
     $this->countLog2 = $this->enforceLog2Boundaries($countLog2);
+    $this->randomBytes = $randomBytes;
   }
 
   /**
@@ -109,7 +121,7 @@ protected function generateSalt() {
     // We encode the final log2 iteration count in base 64.
     $output .= static::$ITOA64[$this->countLog2];
     // 6 bytes is the standard salt for a portable phpass hash.
-    $output .= $this->base64Encode(drupal_random_bytes(6), 6);
+    $output .= $this->base64Encode($this->RandomBytes->generate(6), 6);
     return $output;
   }
 
diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php
index 31fcf04..b68df81 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php
@@ -52,7 +52,7 @@ protected function prepareD8Session() {
 
     // Generate and set a D7-compatible session cookie.
     $this->curlInitialize();
-    $sid = drupal_hash_base64(uniqid(mt_rand(), TRUE) . drupal_random_bytes(55));
+    $sid = drupal_hash_base64(uniqid(mt_rand(), TRUE) . $this->container->get('random.bytes')->generate());
     curl_setopt($this->curlHandle, CURLOPT_COOKIE, rawurlencode(session_name()) . '=' . rawurlencode($sid));
 
     // Force our way into the session of the child site.
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 493db9b..236173a 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -531,7 +531,7 @@ function system_install() {
     ->save();
 
   // Populate the cron key state variable.
-  $cron_key = drupal_hash_base64(drupal_random_bytes(55));
+  $cron_key = drupal_hash_base64(Drupal::service('random.bytes')->generate());
   state()->set('system.cron_key', $cron_key);
 }
 
diff --git a/core/modules/user/user.pages.inc b/core/modules/user/user.pages.inc
index 140b767..1b6d2fe 100644
--- a/core/modules/user/user.pages.inc
+++ b/core/modules/user/user.pages.inc
@@ -126,7 +126,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
           watchdog('user', 'User %name used one-time login link at time %timestamp.', array('%name' => $account->name, '%timestamp' => $timestamp));
           drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.'));
           // Let the user's password be changed without the current password check.
-          $token = drupal_hash_base64(drupal_random_bytes(55));
+          $token = drupal_hash_base64(Drupal::service('random.bytes')->generate());
           $_SESSION['pass_reset_' . $user->uid] = $token;
           drupal_goto('user/' . $user->uid . '/edit', array('query' => array('pass-reset-token' => $token)));
         }
diff --git a/core/tests/Drupal/Tests/Component/Utility/RandomTest.php b/core/tests/Drupal/Tests/Component/Utility/RandomTest.php
new file mode 100644
index 0000000..e98ce38
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/Utility/RandomTest.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Component\Utility\RandomTest.
+ */
+
+namespace Drupal\Tests\Component\Utility;
+
+use Symfony\Component\HttpFoundation\Request;
+use Drupal\Tests\UnitTestCase;
+use Drupal\Component\Utility\RandomBytes;
+
+/**
+ * Tests string filtering.
+ *
+ * @see \Drupal\Component\Utility\String
+ */
+class RandomBytesTest extends UnitTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'RandomBytes generator tests',
+      'description' => 'Test random values generation of RandomBytes component.',
+    );
+  }
+
+  /**
+   * Tests \Drupal\Component\Utility\RandomBytes::generate().
+   */
+  public function testGenerate() {
+    $generator = new RandomBytes(Request::create('http://example.com'));
+    for ($i = 1; $i < 10; $i++) {
+      $count = rand(10, 10000);
+      // Check that different values are being generated.
+      $this->assertNotEquals($generator->generate($count), $generator->generate($count));
+      // Check the length.
+      $this->assertEquals(strlen($generator->generate($count)), $count);
+    }
+  }
+
+}
