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