/** * A Monte Carlo test that generates $cycles numbers from 0 to $tot * and test if the numbers are above or below the line y=x with a * frequency range of [$min, $max] * * Note: this code is inspired by the random number generator test * included in the PHP-CryptLib project of Anthony Ferrara * @see https://github.com/ircmaxell/PHP-CryptLib * * @dataProvider provideRandInt */ public function testRandInt($num, $valid, $cycles, $tot, $min, $max, $strong) { try { $test = Math::randBytes(1, $strong); } catch (\Zend\Math\Exception\RuntimeException $e) { $this->markTestSkipped($e->getMessage()); } $i = 0; $count = 0; do { $up = 0; $down = 0; for ($i = 0; $i < $cycles; $i++) { $x = Math::rand(0, $tot, $strong); $y = Math::rand(0, $tot, $strong); if ($x > $y) { $up++; } elseif ($x < $y) { $down++; } } $this->assertGreaterThan(0, $up); $this->assertGreaterThan(0, $down); $ratio = $up / $down; if ($ratio > $min && $ratio < $max) { $count++; } $i++; } while ($i < $num && $count < $valid); if ($count < $valid) { $this->fail('The random number generator failed the Monte Carlo test'); } }
/** * Bcrypt * * @param string $password * @throws Exception\RuntimeException * @return string */ public function create($password) { if (empty($this->salt)) { $salt = Math::randBytes(self::MIN_SALT_SIZE); } else { $salt = $this->salt; } $salt64 = substr(str_replace('+', '.', base64_encode($salt)), 0, 22); /** * Check for security flaw in the bcrypt implementation used by crypt() * @see http://php.net/security/crypt_blowfish.php */ if (version_compare(PHP_VERSION, '5.3.7') >= 0) { $prefix = '$2y$'; } else { $prefix = '$2a$'; // check if the password contains 8-bit character if (preg_match('/[\\x80-\\xFF]/', $password)) { throw new Exception\RuntimeException('The bcrypt implementation used by PHP can contains a security flaw using password with 8-bit character. ' . 'We suggest to upgrade to PHP 5.3.7+ or use passwords with only 7-bit characters'); } } $hash = crypt($password, $prefix . $this->cost . '$' . $salt64); if (strlen($hash) <= 13) { throw new Exception\RuntimeException('Error during the bcrypt generation'); } return $hash; }
public function testRandBytes() { for ($length=1; $length<4096; $length++) { $rand = Math::randBytes($length); $this->assertTrue(!empty($rand)); $this->assertEquals(strlen($rand), $length); } }
/** * Bcrypt * * @param string $password * @return string */ public function create($password) { if (empty($this->salt)) { $salt = Math::randBytes(self::MIN_SALT_SIZE, true); } else { $salt = $this->salt; } $salt64 = substr(str_replace('+', '.', base64_encode($salt)), 0, 22); $hash = crypt($password, '$2a$' . $this->cost . '$' . $salt64); if (strlen($hash) <= 13) { throw new Exception\RuntimeException('Error during the bcrypt generation'); } return $hash; }
/** * Encrypt then authenticate using HMAC * * @param string $data * @return string * @throws Exception\InvalidArgumentException */ public function encrypt($data) { if (empty($data)) { throw new Exception\InvalidArgumentException('The data to encrypt cannot be empty'); } if (empty($this->key)) { throw new Exception\InvalidArgumentException('No key specified for the encryption'); } if (empty($this->cipher)) { throw new Exception\InvalidArgumentException('No symmetric cipher specified'); } $keySize = $this->cipher->getKeySize(); // generate a random salt (IV) $this->cipher->setSalt(Math::randBytes($this->cipher->getSaltSize(), true)); // generate the encryption key and the HMAC key for the authentication $hash = Pbkdf2::calc(self::KEY_DERIV_HMAC, $this->getKey(), $this->cipher->getSalt(), $this->keyIteration, $keySize * 2); // set the encryption key $this->cipher->setKey(substr($hash, 0, $keySize)); // set the key for HMAC $keyHmac = substr($hash, $keySize); // encryption $ciphertext = $this->cipher->encrypt($data); // HMAC $hmac = Hmac::compute($keyHmac, $this->hash, $this->cipher->getAlgorithm() . $ciphertext); if (!$this->binaryOutput) { $ciphertext = base64_encode($ciphertext); } return $hmac . $ciphertext; }
/** * In the event a private number/key has not been set by the user, * or generated by ext/openssl, a best attempt will be made to * generate a random key. Having a random number generator installed * on linux/bsd is highly recommended! The alternative is not recommended * for production unless without any other option. * * @return string */ protected function generatePrivateKey() { $rand = $this->math->randBytes(strlen($this->getPrime()), true); return $rand; }