web/wp-includes/class-phpass.php
branchwordpress
changeset 109 03b0d1493584
child 132 4d4862461b8d
equal deleted inserted replaced
-1:000000000000 109:03b0d1493584
       
     1 <?php
       
     2 /**
       
     3  * Portable PHP password hashing framework.
       
     4  * @package phpass
       
     5  * @since 2.5
       
     6  * @version 0.1
       
     7  * @link http://www.openwall.com/phpass/
       
     8  */
       
     9 
       
    10 #
       
    11 # Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
       
    12 # the public domain.
       
    13 #
       
    14 # There's absolutely no warranty.
       
    15 #
       
    16 # Please be sure to update the Version line if you edit this file in any way.
       
    17 # It is suggested that you leave the main version number intact, but indicate
       
    18 # your project name (after the slash) and add your own revision information.
       
    19 #
       
    20 # Please do not change the "private" password hashing method implemented in
       
    21 # here, thereby making your hashes incompatible.  However, if you must, please
       
    22 # change the hash type identifier (the "$P$") to something different.
       
    23 #
       
    24 # Obviously, since this code is in the public domain, the above are not
       
    25 # requirements (there can be none), but merely suggestions.
       
    26 #
       
    27 
       
    28 /**
       
    29  * Portable PHP password hashing framework.
       
    30  *
       
    31  * @package phpass
       
    32  * @version 0.1 / genuine
       
    33  * @link http://www.openwall.com/phpass/
       
    34  * @since 2.5
       
    35  */
       
    36 class PasswordHash {
       
    37 	var $itoa64;
       
    38 	var $iteration_count_log2;
       
    39 	var $portable_hashes;
       
    40 	var $random_state;
       
    41 
       
    42 	function PasswordHash($iteration_count_log2, $portable_hashes)
       
    43 	{
       
    44 		$this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
       
    45 
       
    46 		if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
       
    47 			$iteration_count_log2 = 8;
       
    48 		$this->iteration_count_log2 = $iteration_count_log2;
       
    49 
       
    50 		$this->portable_hashes = $portable_hashes;
       
    51 
       
    52 		$this->random_state = microtime() . (function_exists('getmypid') ? getmypid() : '') . uniqid(rand(), TRUE);
       
    53 
       
    54 	}
       
    55 
       
    56 	function get_random_bytes($count)
       
    57 	{
       
    58 		$output = '';
       
    59 		if (($fh = @fopen('/dev/urandom', 'rb'))) {
       
    60 			$output = fread($fh, $count);
       
    61 			fclose($fh);
       
    62 		}
       
    63 
       
    64 		if (strlen($output) < $count) {
       
    65 			$output = '';
       
    66 			for ($i = 0; $i < $count; $i += 16) {
       
    67 				$this->random_state =
       
    68 				    md5(microtime() . $this->random_state);
       
    69 				$output .=
       
    70 				    pack('H*', md5($this->random_state));
       
    71 			}
       
    72 			$output = substr($output, 0, $count);
       
    73 		}
       
    74 
       
    75 		return $output;
       
    76 	}
       
    77 
       
    78 	function encode64($input, $count)
       
    79 	{
       
    80 		$output = '';
       
    81 		$i = 0;
       
    82 		do {
       
    83 			$value = ord($input[$i++]);
       
    84 			$output .= $this->itoa64[$value & 0x3f];
       
    85 			if ($i < $count)
       
    86 				$value |= ord($input[$i]) << 8;
       
    87 			$output .= $this->itoa64[($value >> 6) & 0x3f];
       
    88 			if ($i++ >= $count)
       
    89 				break;
       
    90 			if ($i < $count)
       
    91 				$value |= ord($input[$i]) << 16;
       
    92 			$output .= $this->itoa64[($value >> 12) & 0x3f];
       
    93 			if ($i++ >= $count)
       
    94 				break;
       
    95 			$output .= $this->itoa64[($value >> 18) & 0x3f];
       
    96 		} while ($i < $count);
       
    97 
       
    98 		return $output;
       
    99 	}
       
   100 
       
   101 	function gensalt_private($input)
       
   102 	{
       
   103 		$output = '$P$';
       
   104 		$output .= $this->itoa64[min($this->iteration_count_log2 +
       
   105 			((PHP_VERSION >= '5') ? 5 : 3), 30)];
       
   106 		$output .= $this->encode64($input, 6);
       
   107 
       
   108 		return $output;
       
   109 	}
       
   110 
       
   111 	function crypt_private($password, $setting)
       
   112 	{
       
   113 		$output = '*0';
       
   114 		if (substr($setting, 0, 2) == $output)
       
   115 			$output = '*1';
       
   116 
       
   117 		if (substr($setting, 0, 3) != '$P$')
       
   118 			return $output;
       
   119 
       
   120 		$count_log2 = strpos($this->itoa64, $setting[3]);
       
   121 		if ($count_log2 < 7 || $count_log2 > 30)
       
   122 			return $output;
       
   123 
       
   124 		$count = 1 << $count_log2;
       
   125 
       
   126 		$salt = substr($setting, 4, 8);
       
   127 		if (strlen($salt) != 8)
       
   128 			return $output;
       
   129 
       
   130 		# We're kind of forced to use MD5 here since it's the only
       
   131 		# cryptographic primitive available in all versions of PHP
       
   132 		# currently in use.  To implement our own low-level crypto
       
   133 		# in PHP would result in much worse performance and
       
   134 		# consequently in lower iteration counts and hashes that are
       
   135 		# quicker to crack (by non-PHP code).
       
   136 		if (PHP_VERSION >= '5') {
       
   137 			$hash = md5($salt . $password, TRUE);
       
   138 			do {
       
   139 				$hash = md5($hash . $password, TRUE);
       
   140 			} while (--$count);
       
   141 		} else {
       
   142 			$hash = pack('H*', md5($salt . $password));
       
   143 			do {
       
   144 				$hash = pack('H*', md5($hash . $password));
       
   145 			} while (--$count);
       
   146 		}
       
   147 
       
   148 		$output = substr($setting, 0, 12);
       
   149 		$output .= $this->encode64($hash, 16);
       
   150 
       
   151 		return $output;
       
   152 	}
       
   153 
       
   154 	function gensalt_extended($input)
       
   155 	{
       
   156 		$count_log2 = min($this->iteration_count_log2 + 8, 24);
       
   157 		# This should be odd to not reveal weak DES keys, and the
       
   158 		# maximum valid value is (2**24 - 1) which is odd anyway.
       
   159 		$count = (1 << $count_log2) - 1;
       
   160 
       
   161 		$output = '_';
       
   162 		$output .= $this->itoa64[$count & 0x3f];
       
   163 		$output .= $this->itoa64[($count >> 6) & 0x3f];
       
   164 		$output .= $this->itoa64[($count >> 12) & 0x3f];
       
   165 		$output .= $this->itoa64[($count >> 18) & 0x3f];
       
   166 
       
   167 		$output .= $this->encode64($input, 3);
       
   168 
       
   169 		return $output;
       
   170 	}
       
   171 
       
   172 	function gensalt_blowfish($input)
       
   173 	{
       
   174 		# This one needs to use a different order of characters and a
       
   175 		# different encoding scheme from the one in encode64() above.
       
   176 		# We care because the last character in our encoded string will
       
   177 		# only represent 2 bits.  While two known implementations of
       
   178 		# bcrypt will happily accept and correct a salt string which
       
   179 		# has the 4 unused bits set to non-zero, we do not want to take
       
   180 		# chances and we also do not want to waste an additional byte
       
   181 		# of entropy.
       
   182 		$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
       
   183 
       
   184 		$output = '$2a$';
       
   185 		$output .= chr(ord('0') + $this->iteration_count_log2 / 10);
       
   186 		$output .= chr(ord('0') + $this->iteration_count_log2 % 10);
       
   187 		$output .= '$';
       
   188 
       
   189 		$i = 0;
       
   190 		do {
       
   191 			$c1 = ord($input[$i++]);
       
   192 			$output .= $itoa64[$c1 >> 2];
       
   193 			$c1 = ($c1 & 0x03) << 4;
       
   194 			if ($i >= 16) {
       
   195 				$output .= $itoa64[$c1];
       
   196 				break;
       
   197 			}
       
   198 
       
   199 			$c2 = ord($input[$i++]);
       
   200 			$c1 |= $c2 >> 4;
       
   201 			$output .= $itoa64[$c1];
       
   202 			$c1 = ($c2 & 0x0f) << 2;
       
   203 
       
   204 			$c2 = ord($input[$i++]);
       
   205 			$c1 |= $c2 >> 6;
       
   206 			$output .= $itoa64[$c1];
       
   207 			$output .= $itoa64[$c2 & 0x3f];
       
   208 		} while (1);
       
   209 
       
   210 		return $output;
       
   211 	}
       
   212 
       
   213 	function HashPassword($password)
       
   214 	{
       
   215 		$random = '';
       
   216 
       
   217 		if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
       
   218 			$random = $this->get_random_bytes(16);
       
   219 			$hash =
       
   220 			    crypt($password, $this->gensalt_blowfish($random));
       
   221 			if (strlen($hash) == 60)
       
   222 				return $hash;
       
   223 		}
       
   224 
       
   225 		if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
       
   226 			if (strlen($random) < 3)
       
   227 				$random = $this->get_random_bytes(3);
       
   228 			$hash =
       
   229 			    crypt($password, $this->gensalt_extended($random));
       
   230 			if (strlen($hash) == 20)
       
   231 				return $hash;
       
   232 		}
       
   233 
       
   234 		if (strlen($random) < 6)
       
   235 			$random = $this->get_random_bytes(6);
       
   236 		$hash =
       
   237 		    $this->crypt_private($password,
       
   238 		    $this->gensalt_private($random));
       
   239 		if (strlen($hash) == 34)
       
   240 			return $hash;
       
   241 
       
   242 		# Returning '*' on error is safe here, but would _not_ be safe
       
   243 		# in a crypt(3)-like function used _both_ for generating new
       
   244 		# hashes and for validating passwords against existing hashes.
       
   245 		return '*';
       
   246 	}
       
   247 
       
   248 	function CheckPassword($password, $stored_hash)
       
   249 	{
       
   250 		$hash = $this->crypt_private($password, $stored_hash);
       
   251 		if ($hash[0] == '*')
       
   252 			$hash = crypt($password, $stored_hash);
       
   253 
       
   254 		return $hash == $stored_hash;
       
   255 	}
       
   256 }
       
   257 
       
   258 ?>