Pastebin is 300% more awesome when you are logged in. Sign Up, it's FREE!
Guest

PBKDF2.class.php

By: a guest on Jul 13th, 2013  |  syntax: PHP  |  size: 6.76 KB  |  hits: 767  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. <?php
  2.     /**
  3.      * Password hashing with PBKDF2.
  4.      * (modified to use the native php function if available)
  5.      * Based on the pure PHP implementation of PBKDF2 which can be found on:
  6.      * https://defuse.ca/php-pbkdf2.htm
  7.      *
  8.      * @author havoc AT defuse.ca (www: https://defuse.ca/php-pbkdf2.htm)
  9.      * @author TheBlintOne
  10.      *
  11.      * @license Public Domain (so feel free to use it): http://en.wikipedia.org/wiki/Public_domain
  12.      */
  13.  
  14.     /**
  15.      * Class to encapsulate the PBKDF2 functions
  16.      *
  17.      * @author havoc AT defuse.ca (www: https://defuse.ca/php-pbkdf2.htm)
  18.      * @author TheBlintOne
  19.      */
  20.     class PBKDF2
  21.     {
  22.         // These constants may be changed without breaking existing hashes.
  23.         const PBKDF2_HASH_ALGORITHM = "sha256";
  24.         const PBKDF2_ITERATIONS = 1000;
  25.         const PBKDF2_SALT_BYTES = 24;
  26.         const PBKDF2_HASH_BYTES = 24;
  27.  
  28.         const HASH_SECTIONS = 4;
  29.         const HASH_ALGORITHM_INDEX = 0;
  30.         const HASH_ITERATION_INDEX = 1;
  31.         const HASH_SALT_INDEX = 2;
  32.         const HASH_PBKDF2_INDEX = 3;
  33.  
  34.         /**
  35.          * Creates a hash for the given password
  36.          *
  37.          * @param string $password    the password to hash
  38.          * @return string             the hashed password in format "algorithm:iterations:salt:hash"
  39.          */
  40.         public function create_hash( $password )
  41.         {
  42.             $salt = base64_encode( mcrypt_create_iv( PBKDF2::PBKDF2_SALT_BYTES, MCRYPT_DEV_URANDOM ) );
  43.             return PBKDF2::PBKDF2_HASH_ALGORITHM . ":" . PBKDF2::PBKDF2_ITERATIONS . ":" .  $salt . ":" .
  44.                 base64_encode( $this->hash(
  45.                     PBKDF2::PBKDF2_HASH_ALGORITHM,
  46.                     $password,
  47.                     $salt,
  48.                     PBKDF2::PBKDF2_ITERATIONS,
  49.                     PBKDF2::PBKDF2_HASH_BYTES,
  50.                     true
  51.                 ) );
  52.         }
  53.  
  54.         /**
  55.          * Checks if the given password matches the given hash created by PBKDF::create_hash( string )
  56.          *
  57.          * @param string $password     the password to check
  58.          * @param string $good_hash    the hash which should be match the password
  59.          * @return boolean             true if $password and $good_hash match, false otherwise
  60.          *
  61.          * @see PBKDF2::create_hash
  62.          */
  63.         public function validate_password( $password, $good_hash )
  64.         {
  65.             $params = explode( ":", $good_hash );
  66.             if( count( $params ) < HASH_SECTIONS )
  67.                return false;
  68.             $pbkdf2 = base64_decode( $params[ PBKDF2::HASH_PBKDF2_INDEX ] );
  69.             return slow_equals(
  70.                 $pbkdf2,
  71.                 $this->hash(
  72.                     $params[ PBKDF2::HASH_ALGORITHM_INDEX ],
  73.                     $password,
  74.                     $params[ PBKDF2::HASH_SALT_INDEX ],
  75.                     (int)$params[ PBKDF2::HASH_ITERATION_INDEX ],
  76.                     strlen( $pbkdf2 ),
  77.                     true
  78.                 )
  79.             );
  80.         }
  81.  
  82.         /**
  83.          * Compares two strings $a and $b in length-constant time
  84.          *
  85.          * @param string $a    the first string
  86.          * @param string $b    the second string
  87.          * @return boolean     true if they are equal, false otherwise
  88.          */
  89.         public function slow_equals( $a, $b )
  90.         {
  91.             $diff = strlen( $a ) ^ strlen( $b );
  92.             for( $i = 0; $i < strlen( $a ) && $i < strlen( $b ); $i++ )
  93.             {
  94.                 $diff |= ord( $a[ $i ] ) ^ ord( $b[ $i ] );
  95.             }
  96.             return $diff === 0;
  97.         }
  98.  
  99.         /**
  100.          * PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
  101.          *
  102.          * Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
  103.          *
  104.          * This implementation of PBKDF2 was originally created by https://defuse.ca
  105.          * With improvements by http://www.variations-of-shadow.com
  106.          * Added support for the native PHP implementation by TheBlintOne
  107.          *
  108.          * @param string $algorithm                                 the hash algorithm to use. Recommended: SHA256
  109.          * @param string $password                                  the Password
  110.          * @param string $salt                                      a salt that is unique to the password
  111.          * @param int $count                                        iteration count. Higher is better, but slower. Recommended: At least 1000
  112.          * @param int $key_length                                   the length of the derived key in bytes
  113.          * @param boolean $raw_output [optional] (default false)    if true, the key is returned in raw binary format. Hex encoded otherwise
  114.          * @return string                                           a $key_length-byte key derived from the password and salt,
  115.          *                                                          depending on $raw_output this is either Hex encoded or raw binary
  116.          * @throws Exception                                        if the hash algorithm are not found or if there are invalid parameters
  117.          */
  118.         public function hash( $algorithm, $password, $salt, $count, $key_length, $raw_output = false )
  119.         {
  120.             $algorithm = strtolower( $algorithm );
  121.             if( !in_array( $algorithm, hash_algos() , true ) )
  122.                 throw new Exception( 'PBKDF2 ERROR: Invalid hash algorithm.' );
  123.             if( $count <= 0 || $key_length <= 0 )
  124.                 throw new Exception( 'PBKDF2 ERROR: Invalid parameters.' );
  125.  
  126.             // use the native implementation of the algorithm if available
  127.             if( function_exists( "hash_pbkdf2" ) )
  128.             {
  129.                 return hash_pbkdf2( $algorithm, $password, $salt, $count, $key_length, $raw_output );
  130.             }
  131.  
  132.             $hash_length = strlen( hash( $algorithm, "", true ) );
  133.             $block_count = ceil( $key_length / $hash_length );
  134.  
  135.             $output = "";
  136.             for( $i = 1; $i <= $block_count; $i++ )
  137.             {
  138.                 // $i encoded as 4 bytes, big endian.
  139.                 $last = $salt . pack( "N", $i );
  140.                 // first iteration
  141.                 $last = $xorsum = hash_hmac( $algorithm, $last, $password, true );
  142.                 // perform the other $count - 1 iterations
  143.                 for( $j = 1; $j < $count; $j++ )
  144.                 {
  145.                     $xorsum ^= ( $last = hash_hmac( $algorithm, $last, $password, true ) );
  146.                 }
  147.                 $output .= $xorsum;
  148.             }
  149.  
  150.             if( $raw_output )
  151.                 return substr( $output, 0, $key_length );
  152.             else
  153.                 return bin2hex( substr( $output, 0, $key_length ) );
  154.         }
  155.     }
  156. ?>