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