wp/wp-includes/class-phpass.php
changeset 22 8c2e4d02f4ef
parent 21 48c4eec2b7e6
equal deleted inserted replaced
21:48c4eec2b7e6 22:8c2e4d02f4ef
     8  */
     8  */
     9 
     9 
    10 #
    10 #
    11 # Portable PHP password hashing framework.
    11 # Portable PHP password hashing framework.
    12 #
    12 #
    13 # Version 0.5 / WordPress.
    13 # Version 0.5.4 / WordPress.
    14 #
    14 #
    15 # Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
    15 # Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
    16 # the public domain.  Revised in subsequent years, still public domain.
    16 # the public domain.  Revised in subsequent years, still public domain.
    17 #
    17 #
    18 # There's absolutely no warranty.
    18 # There's absolutely no warranty.
    49 
    49 
    50 	function __construct($iteration_count_log2, $portable_hashes)
    50 	function __construct($iteration_count_log2, $portable_hashes)
    51 	{
    51 	{
    52 		$this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    52 		$this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    53 
    53 
    54 		if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
    54 		if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31) {
    55 			$iteration_count_log2 = 8;
    55 			$iteration_count_log2 = 8;
       
    56 		}
    56 		$this->iteration_count_log2 = $iteration_count_log2;
    57 		$this->iteration_count_log2 = $iteration_count_log2;
    57 
    58 
    58 		$this->portable_hashes = $portable_hashes;
    59 		$this->portable_hashes = $portable_hashes;
    59 
    60 
    60 		$this->random_state = microtime();
    61 		$this->random_state = microtime();
    61 		if (function_exists('getmypid'))
    62 		if (function_exists('getmypid')) {
    62 			$this->random_state .= getmypid();
    63 			$this->random_state .= getmypid();
       
    64 		}
    63 	}
    65 	}
    64 
    66 
    65 	function PasswordHash($iteration_count_log2, $portable_hashes)
    67 	function PasswordHash($iteration_count_log2, $portable_hashes)
    66 	{
    68 	{
    67 		self::__construct($iteration_count_log2, $portable_hashes);
    69 		self::__construct($iteration_count_log2, $portable_hashes);
    94 		$output = '';
    96 		$output = '';
    95 		$i = 0;
    97 		$i = 0;
    96 		do {
    98 		do {
    97 			$value = ord($input[$i++]);
    99 			$value = ord($input[$i++]);
    98 			$output .= $this->itoa64[$value & 0x3f];
   100 			$output .= $this->itoa64[$value & 0x3f];
    99 			if ($i < $count)
   101 			if ($i < $count) {
   100 				$value |= ord($input[$i]) << 8;
   102 				$value |= ord($input[$i]) << 8;
       
   103 			}
   101 			$output .= $this->itoa64[($value >> 6) & 0x3f];
   104 			$output .= $this->itoa64[($value >> 6) & 0x3f];
   102 			if ($i++ >= $count)
   105 			if ($i++ >= $count) {
   103 				break;
   106 				break;
   104 			if ($i < $count)
   107 			}
       
   108 			if ($i < $count) {
   105 				$value |= ord($input[$i]) << 16;
   109 				$value |= ord($input[$i]) << 16;
       
   110 			}
   106 			$output .= $this->itoa64[($value >> 12) & 0x3f];
   111 			$output .= $this->itoa64[($value >> 12) & 0x3f];
   107 			if ($i++ >= $count)
   112 			if ($i++ >= $count) {
   108 				break;
   113 				break;
       
   114 			}
   109 			$output .= $this->itoa64[($value >> 18) & 0x3f];
   115 			$output .= $this->itoa64[($value >> 18) & 0x3f];
   110 		} while ($i < $count);
   116 		} while ($i < $count);
   111 
   117 
   112 		return $output;
   118 		return $output;
   113 	}
   119 	}
   114 
   120 
   115 	function gensalt_private($input)
   121 	function gensalt_private($input)
   116 	{
   122 	{
   117 		$output = '$P$';
   123 		$output = '$P$';
   118 		$output .= $this->itoa64[min($this->iteration_count_log2 +
   124 		$output .= $this->itoa64[min($this->iteration_count_log2 + 5,
   119 			((PHP_VERSION >= '5') ? 5 : 3), 30)];
   125 		    30)];
   120 		$output .= $this->encode64($input, 6);
   126 		$output .= $this->encode64($input, 6);
   121 
   127 
   122 		return $output;
   128 		return $output;
   123 	}
   129 	}
   124 
   130 
   125 	function crypt_private($password, $setting)
   131 	function crypt_private($password, $setting)
   126 	{
   132 	{
   127 		$output = '*0';
   133 		$output = '*0';
   128 		if (substr($setting, 0, 2) === $output)
   134 		if (substr($setting, 0, 2) === $output) {
   129 			$output = '*1';
   135 			$output = '*1';
       
   136 		}
   130 
   137 
   131 		$id = substr($setting, 0, 3);
   138 		$id = substr($setting, 0, 3);
   132 		# We use "$P$", phpBB3 uses "$H$" for the same thing
   139 		# We use "$P$", phpBB3 uses "$H$" for the same thing
   133 		if ($id !== '$P$' && $id !== '$H$')
   140 		if ($id !== '$P$' && $id !== '$H$') {
   134 			return $output;
   141 			return $output;
       
   142 		}
   135 
   143 
   136 		$count_log2 = strpos($this->itoa64, $setting[3]);
   144 		$count_log2 = strpos($this->itoa64, $setting[3]);
   137 		if ($count_log2 < 7 || $count_log2 > 30)
   145 		if ($count_log2 < 7 || $count_log2 > 30) {
   138 			return $output;
   146 			return $output;
       
   147 		}
   139 
   148 
   140 		$count = 1 << $count_log2;
   149 		$count = 1 << $count_log2;
   141 
   150 
   142 		$salt = substr($setting, 4, 8);
   151 		$salt = substr($setting, 4, 8);
   143 		if (strlen($salt) !== 8)
   152 		if (strlen($salt) !== 8) {
   144 			return $output;
   153 			return $output;
       
   154 		}
   145 
   155 
   146 		# We were kind of forced to use MD5 here since it's the only
   156 		# We were kind of forced to use MD5 here since it's the only
   147 		# cryptographic primitive that was available in all versions
   157 		# cryptographic primitive that was available in all versions
   148 		# of PHP in use.  To implement our own low-level crypto in PHP
   158 		# of PHP in use.  To implement our own low-level crypto in PHP
   149 		# would have resulted in much worse performance and
   159 		# would have resulted in much worse performance and
   172 		# of entropy.
   182 		# of entropy.
   173 		$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
   183 		$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
   174 
   184 
   175 		$output = '$2a$';
   185 		$output = '$2a$';
   176 		$output .= chr((int)(ord('0') + $this->iteration_count_log2 / 10));
   186 		$output .= chr((int)(ord('0') + $this->iteration_count_log2 / 10));
   177 		$output .= chr((ord('0') + $this->iteration_count_log2 % 10));
   187 		$output .= chr(ord('0') + $this->iteration_count_log2 % 10);
   178 		$output .= '$';
   188 		$output .= '$';
   179 
   189 
   180 		$i = 0;
   190 		$i = 0;
   181 		do {
   191 		do {
   182 			$c1 = ord($input[$i++]);
   192 			$c1 = ord($input[$i++]);
   211 
   221 
   212 		if (CRYPT_BLOWFISH === 1 && !$this->portable_hashes) {
   222 		if (CRYPT_BLOWFISH === 1 && !$this->portable_hashes) {
   213 			$random = $this->get_random_bytes(16);
   223 			$random = $this->get_random_bytes(16);
   214 			$hash =
   224 			$hash =
   215 			    crypt($password, $this->gensalt_blowfish($random));
   225 			    crypt($password, $this->gensalt_blowfish($random));
   216 			if (strlen($hash) === 60)
   226 			if (strlen($hash) === 60) {
   217 				return $hash;
   227 				return $hash;
   218 		}
   228 			}
   219 
   229 		}
   220 		if (strlen($random) < 6)
   230 
       
   231 		if (strlen($random) < 6) {
   221 			$random = $this->get_random_bytes(6);
   232 			$random = $this->get_random_bytes(6);
       
   233 		}
   222 		$hash =
   234 		$hash =
   223 		    $this->crypt_private($password,
   235 		    $this->crypt_private($password,
   224 		    $this->gensalt_private($random));
   236 		    $this->gensalt_private($random));
   225 		if (strlen($hash) === 34)
   237 		if (strlen($hash) === 34) {
   226 			return $hash;
   238 			return $hash;
       
   239 		}
   227 
   240 
   228 		# Returning '*' on error is safe here, but would _not_ be safe
   241 		# Returning '*' on error is safe here, but would _not_ be safe
   229 		# in a crypt(3)-like function used _both_ for generating new
   242 		# in a crypt(3)-like function used _both_ for generating new
   230 		# hashes and for validating passwords against existing hashes.
   243 		# hashes and for validating passwords against existing hashes.
   231 		return '*';
   244 		return '*';
   236 		if ( strlen( $password ) > 4096 ) {
   249 		if ( strlen( $password ) > 4096 ) {
   237 			return false;
   250 			return false;
   238 		}
   251 		}
   239 
   252 
   240 		$hash = $this->crypt_private($password, $stored_hash);
   253 		$hash = $this->crypt_private($password, $stored_hash);
   241 		if ($hash[0] === '*')
   254 		if ($hash[0] === '*') {
   242 			$hash = crypt($password, $stored_hash);
   255 			$hash = crypt($password, $stored_hash);
       
   256 		}
   243 
   257 
   244 		# This is not constant-time.  In order to keep the code simple,
   258 		# This is not constant-time.  In order to keep the code simple,
   245 		# for timing safety we currently rely on the salts being
   259 		# for timing safety we currently rely on the salts being
   246 		# unpredictable, which they are at least in the non-fallback
   260 		# unpredictable, which they are at least in the non-fallback
   247 		# cases (that is, when we use /dev/urandom and bcrypt).
   261 		# cases (that is, when we use /dev/urandom and bcrypt).