<?php

/**
 * Holds the key for @{class:PhutilOpaqueEnvelope} in a logically distant
 * location so it will never appear in stack traces, etc. You should never need
 * to use this class directly. See @{class:PhutilOpaqueEnvelope} for
 * information about opaque envelopes.
 *
 * @task internal Internals
 */
final class PhutilOpaqueEnvelopeKey {

  private static $key;


/* -(  Internals  )---------------------------------------------------------- */


  /**
   * @task internal
   */
  private function __construct() {
    // <private>
  }


  /**
   * @task internal
   */
  public static function getKey() {
    if (self::$key === null) {
      try {
        self::$key = Filesystem::readRandomBytes(128);
      } catch (Exception $ex) {

        // NOTE: We can't throw here! Otherwise we might get a stack trace
        // including the string that was passed to PhutilOpaqueEnvelope's
        // constructor. Just die() instead.

        die(
          "Unable to read random bytes in PhutilOpaqueEnvelope. (This ".
          "causes an immediate process exit to avoid leaking the envelope ".
          "contents in a stack trace.)");
      }
    }
    return self::$key;
  }

}

<?php

/**
 * Holds the key for @{class:PhutilOpaqueEnvelope} in a logically distant
 * location so it will never appear in stack traces, etc. You should never need
 * to use this class directly. See @{class:PhutilOpaqueEnvelope} for
 * information about opaque envelopes.
 *
 * @task internal Internals
 */
final class PhutilOpaqueEnvelopeKey {

  private static $key;


/* -(  Internals  )---------------------------------------------------------- */


  /**
   * @task internal
   */
  private function __construct() {
    // <private>
  }


  /**
   * @task internal
   */
  public static function getKey() {
    if (self::$key === null) {
      // NOTE: We're using a weak random source because cryptographic levels
      // of security aren't terribly important here and it allows us to use
      // envelopes on systems which don't have a strong random source. Notably,
      // this lets us make it to the readbility check for `/dev/urandom` in
      // Phabricator on systems where we can't read it.
      self::$key = '';
      for ($ii = 0; $ii < 8; $ii++) {
        self::$key .= md5(mt_rand(), $raw_output = true);
      }
    }
    return self::$key;
  }

}

Use weak but dependency-free entropy source in PhutilOpaqueEnvelope
Use weak but dependency-free entropy source in PhutilOpaqueEnvelope

Summary:
If PHP doesn't have access to /dev/urandom, we currently fatal here before we can get to the setup check for it.

To avoid this, use a weaker random source. This doesn't need to be a strong random source, since it's only protecting against accidental disclosure through logs, etc.

Test Plan:
  - Dumped the resulting key and verified it "looked" random.
  - Dumped a bunch of them to a file and gzipped it, verified it got larger.
  - Had user in question apply patch and verified he got to the /dev/urandom setup check ("open_basedir configured crazy").

Reviewers: vrana, btrahan, asherkin

Reviewed By: asherkin

CC: aran

Differential Revision: https://secure.phabricator.com/D4561
