Beispiel #1
0
 public function deriveKey($password, $salt, $keyLength, $iterations = null)
 {
     $iterations = $iterations ?: $this->kdfIterations;
     $key = openssl_pbkdf2($password, $salt, $keyLength, $iterations, 'sha512');
     // This is really not ideal, but openssl's PEM key encryption doesn't
     // work if there are any null bytes in the passphrase. See the doc comment
     // for Encryptor::generateRandomBytesWithoutNulls() for more detail.
     return str_replace(hex2bin('00'), hex2bin('FF'), $key);
 }
Beispiel #2
0
 /**
  * Display time to compute increasing numbers of PBKDF2 iterations
  */
 public function benchmark_kdfAction()
 {
     $password = openssl_random_pseudo_bytes(15);
     $salt = openssl_random_pseudo_bytes(32);
     $iterations = 1000;
     while (true) {
         $this->startTimer();
         openssl_pbkdf2($password, $salt, 32, $iterations);
         $time = $this->getElapsed();
         printf("%d iterations in %.2fms\n", $iterations, $time);
         if ($time < 2) {
             $iterations *= 1.5;
         } else {
             break;
         }
     }
     echo "Put your chosen number of KDF iterations in your local config under 'encryption.kdf.iterations'\n";
 }
Beispiel #3
0
 /**
  * Key derivation wth pbkdf2: http://en.wikipedia.org/wiki/PBKDF2
  * @param string $key payload
  * @param string $salt random string from generate_salt
  * @param string $length result length
  * @param string $count iterations
  * @param string $algo hash algorithm to use
  */
 public static function pbkdf2($key, $salt, $length, $count, $algo)
 {
     /* requires PHP >= 5.5 */
     if (Hm_Functions::function_exists('openssl_pbkdf2')) {
         return openssl_pbkdf2($key, $salt, $length, $count, $algo);
     }
     /* manual version */
     $size = strlen(hash($algo, '', true));
     $len = ceil($length / $size);
     $result = '';
     for ($i = 1; $i <= $len; $i++) {
         $tmp = hash_hmac($algo, $salt . pack('N', $i), $key, true);
         $res = $tmp;
         for ($j = 1; $j < $count; $j++) {
             $tmp = hash_hmac($algo, $tmp, $key, true);
             $res ^= $tmp;
         }
         $result .= $res;
     }
     return substr($result, 0, $length);
 }
<?php

// official test vectors
var_dump(bin2hex(openssl_pbkdf2('password', 'salt', 20, 1)));
var_dump(bin2hex(openssl_pbkdf2('password', 'salt', 20, 2)));
var_dump(bin2hex(openssl_pbkdf2('password', 'salt', 20, 4096)));
/* really slow but should be:
string(40) "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984"
var_dump(bin2hex(openssl_pbkdf2('password', 'salt', 20, 16777216)));
*/
var_dump(bin2hex(openssl_pbkdf2('passwordPASSWORDpassword', 'saltSALTsaltSALTsaltSALTsaltSALTsalt', 25, 4096)));
var_dump(bin2hex(openssl_pbkdf2("password", "salt", 16, 4096)));
Beispiel #5
0
 /**
  * PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt.
  * 
  * Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
  *
  * This implementation of PBKDF2 was originally created by https://defuse.ca
  * With improvements by http://www.variations-of-shadow.com
  * 
  * @param string $password     the password
  * @param string $salt         a salt that is unique to the password
  * @param string $keyLength    the length of the derived key in bytes
  * @param string $count        iteration count. Higher is better, but slower. Recommended: At least 1000
  * @param string $algorithm    the hash algorithm to use. Recommended: SHA256
  * @param string $binaryUnsafe if true, the key is returned in raw binary format. Hex encoded otherwise
  *
  * @return string the key derived from the password and salt
  *
  * @throws \InvalidArgumentException invalid arguments have been passed
  * @throws HashingException          the error occurred while generating the requested hashing algorithm
  */
 public static function pbkdf2($password, $salt, $keyLength, $count, $algorithm = self::SHA1, $binaryUnsafe = false)
 {
     if (!is_integer($count) || $count <= 0) {
         throw new \InvalidArgumentException('The iteration number for the PBKDF2 function must be a positive non-zero integer', 2);
     }
     if (!is_integer($keyLength) || $keyLength <= 0) {
         throw new \InvalidArgumentException('The resulting key length for the PBKDF2 function must be a positive non-zero integer', 2);
     }
     if (!is_string($algorithm) || strlen($algorithm) <= 0) {
         throw new \InvalidArgumentException('The hashing algorithm for the PBKDF2 function must be a non-empty string', 2);
     }
     //an algorithm is represented as a string of only lowercase chars
     $algorithm = strtolower($algorithm);
     //the raw output of the max legth (beyond the $keyLength algorithm)
     $output = '';
     if (function_exists('openssl_pbkdf2')) {
         /*          execute the native openssl_pbkdf2                   */
         //check if the algorithm is valid
         if (!in_array($algorithm, openssl_get_md_methods(true), true)) {
             throw new HashingException('Invalid algorithm: the choosen algorithm is not valid for the PBKDF2 function', 2);
         }
         $output = openssl_pbkdf2($password, $salt, $keyLength, $count, $algorithm);
     } elseif (function_exists('hash_pbkdf2')) {
         /*          execute the native hash_pbkdf2                     */
         //check if the algorithm is valid
         if (!in_array($algorithm, hash_algos(), true)) {
             throw new HashingException('Invalid algorithm: the choosen algorithm is not valid for the PBKDF2 function', 2);
         }
         // The output length is in NIBBLES (4-bits) if $binaryUnsafe is false!
         if (!$binaryUnsafe) {
             $keyLength = $keyLength * 2;
         }
         return hash_pbkdf2($algorithm, $password, $salt, $count, $keyLength, $binaryUnsafe);
     } else {
         /*          use an hack to emulate openssl_pbkdf2               */
         //check if the algorithm is valid
         if (!in_array($algorithm, hash_algos(), true)) {
             throw new HashingException('Invalid algorithm: the choosen algorithm is not valid for the PBKDF2 function', 2);
         }
         $hashLength = strlen(hash($algorithm, '', true));
         $blockCount = ceil($keyLength / $hashLength);
         for ($i = 1; $i <= $blockCount; ++$i) {
             // $i encoded as 4 bytes, big endian.
             $last = $salt . pack('N', $i);
             // first iteration
             $last = $xorsum = hash_hmac($algorithm, $last, $password, true);
             // perform the other $count - 1 iterations
             for ($j = 1; $j < $count; ++$j) {
                 $xorsum ^= $last = hash_hmac($algorithm, $last, $password, true);
             }
             $output .= $xorsum;
         }
     }
     return $binaryUnsafe ? substr($output, 0, $keyLength) : bin2hex(substr($output, 0, $keyLength));
 }