PasswordHash

Portable PHP password hashing framework.

Defined (1)

The class is defined in the following location(s).

/wp-includes/class-phpass.php  
  1. class PasswordHash { 
  2. var $itoa64; 
  3. var $iteration_count_log2; 
  4. var $portable_hashes; 
  5. var $random_state; 
  6.  
  7. /** 
  8. * PHP5 constructor. 
  9. */ 
  10. function __construct( $iteration_count_log2, $portable_hashes ) 
  11. $this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; 
  12.  
  13. if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31) 
  14. $iteration_count_log2 = 8; 
  15. $this->iteration_count_log2 = $iteration_count_log2; 
  16.  
  17. $this->portable_hashes = $portable_hashes; 
  18.  
  19. $this->random_state = microtime() . uniqid(rand(), TRUE); // removed getmypid() for compatibility reasons 
  20.  
  21. /** 
  22. * PHP4 constructor. 
  23. */ 
  24. public function PasswordHash( $iteration_count_log2, $portable_hashes ) { 
  25. self::__construct( $iteration_count_log2, $portable_hashes ); 
  26.  
  27. function get_random_bytes($count) 
  28. $output = ''; 
  29. if ( @is_readable('/dev/urandom') && 
  30. ($fh = @fopen('/dev/urandom', 'rb'))) { 
  31. $output = fread($fh, $count); 
  32. fclose($fh); 
  33.  
  34. if (strlen($output) < $count) { 
  35. $output = ''; 
  36. for ($i = 0; $i < $count; $i += 16) { 
  37. $this->random_state = 
  38. md5(microtime() . $this->random_state); 
  39. $output .= 
  40. pack('H*', md5($this->random_state)); 
  41. $output = substr($output, 0, $count); 
  42.  
  43. return $output; 
  44.  
  45. function encode64($input, $count) 
  46. $output = ''; 
  47. $i = 0; 
  48. do { 
  49. $value = ord($input[$i++]); 
  50. $output .= $this->itoa64[$value & 0x3f]; 
  51. if ($i < $count) 
  52. $value |= ord($input[$i]) << 8; 
  53. $output .= $this->itoa64[($value >> 6) & 0x3f]; 
  54. if ($i++ >= $count) 
  55. break; 
  56. if ($i < $count) 
  57. $value |= ord($input[$i]) << 16; 
  58. $output .= $this->itoa64[($value >> 12) & 0x3f]; 
  59. if ($i++ >= $count) 
  60. break; 
  61. $output .= $this->itoa64[($value >> 18) & 0x3f]; 
  62. } while ($i < $count); 
  63.  
  64. return $output; 
  65.  
  66. function gensalt_private($input) 
  67. $output = '$P$'; 
  68. $output .= $this->itoa64[min($this->iteration_count_log2 + 
  69. ((PHP_VERSION >= '5') ? 5 : 3), 30)]; 
  70. $output .= $this->encode64($input, 6); 
  71.  
  72. return $output; 
  73.  
  74. function crypt_private($password, $setting) 
  75. $output = '*0'; 
  76. if (substr($setting, 0, 2) == $output) 
  77. $output = '*1'; 
  78.  
  79. $id = substr($setting, 0, 3); 
  80. # We use "$P$", phpBB3 uses "$H$" for the same thing 
  81. if ($id != '$P$' && $id != '$H$') 
  82. return $output; 
  83.  
  84. $count_log2 = strpos($this->itoa64, $setting[3]); 
  85. if ($count_log2 < 7 || $count_log2 > 30) 
  86. return $output; 
  87.  
  88. $count = 1 << $count_log2; 
  89.  
  90. $salt = substr($setting, 4, 8); 
  91. if (strlen($salt) != 8) 
  92. return $output; 
  93.  
  94. # We're kind of forced to use MD5 here since it's the only 
  95. # cryptographic primitive available in all versions of PHP 
  96. # currently in use. To implement our own low-level crypto 
  97. # in PHP would result in much worse performance and 
  98. # consequently in lower iteration counts and hashes that are 
  99. # quicker to crack (by non-PHP code). 
  100. if (PHP_VERSION >= '5') { 
  101. $hash = md5($salt . $password, TRUE); 
  102. do { 
  103. $hash = md5($hash . $password, TRUE); 
  104. } while (--$count); 
  105. } else { 
  106. $hash = pack('H*', md5($salt . $password)); 
  107. do { 
  108. $hash = pack('H*', md5($hash . $password)); 
  109. } while (--$count); 
  110.  
  111. $output = substr($setting, 0, 12); 
  112. $output .= $this->encode64($hash, 16); 
  113.  
  114. return $output; 
  115.  
  116. function gensalt_extended($input) 
  117. $count_log2 = min($this->iteration_count_log2 + 8, 24); 
  118. # This should be odd to not reveal weak DES keys, and the 
  119. # maximum valid value is (2**24 - 1) which is odd anyway. 
  120. $count = (1 << $count_log2) - 1; 
  121.  
  122. $output = '_'; 
  123. $output .= $this->itoa64[$count & 0x3f]; 
  124. $output .= $this->itoa64[($count >> 6) & 0x3f]; 
  125. $output .= $this->itoa64[($count >> 12) & 0x3f]; 
  126. $output .= $this->itoa64[($count >> 18) & 0x3f]; 
  127.  
  128. $output .= $this->encode64($input, 3); 
  129.  
  130. return $output; 
  131.  
  132. function gensalt_blowfish($input) 
  133. # This one needs to use a different order of characters and a 
  134. # different encoding scheme from the one in encode64() above. 
  135. # We care because the last character in our encoded string will 
  136. # only represent 2 bits. While two known implementations of 
  137. # bcrypt will happily accept and correct a salt string which 
  138. # has the 4 unused bits set to non-zero, we do not want to take 
  139. # chances and we also do not want to waste an additional byte 
  140. # of entropy. 
  141. $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 
  142.  
  143. $output = '$2a$'; 
  144. $output .= chr(ord('0') + $this->iteration_count_log2 / 10); 
  145. $output .= chr(ord('0') + $this->iteration_count_log2 % 10); 
  146. $output .= '$'; 
  147.  
  148. $i = 0; 
  149. do { 
  150. $c1 = ord($input[$i++]); 
  151. $output .= $itoa64[$c1 >> 2]; 
  152. $c1 = ($c1 & 0x03) << 4; 
  153. if ($i >= 16) { 
  154. $output .= $itoa64[$c1]; 
  155. break; 
  156.  
  157. $c2 = ord($input[$i++]); 
  158. $c1 |= $c2 >> 4; 
  159. $output .= $itoa64[$c1]; 
  160. $c1 = ($c2 & 0x0f) << 2; 
  161.  
  162. $c2 = ord($input[$i++]); 
  163. $c1 |= $c2 >> 6; 
  164. $output .= $itoa64[$c1]; 
  165. $output .= $itoa64[$c2 & 0x3f]; 
  166. } while (1); 
  167.  
  168. return $output; 
  169.  
  170. function HashPassword($password) 
  171. if ( strlen( $password ) > 4096 ) { 
  172. return '*'; 
  173.  
  174. $random = ''; 
  175.  
  176. if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) { 
  177. $random = $this->get_random_bytes(16); 
  178. $hash = 
  179. crypt($password, $this->gensalt_blowfish($random)); 
  180. if (strlen($hash) == 60) 
  181. return $hash; 
  182.  
  183. if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) { 
  184. if (strlen($random) < 3) 
  185. $random = $this->get_random_bytes(3); 
  186. $hash = 
  187. crypt($password, $this->gensalt_extended($random)); 
  188. if (strlen($hash) == 20) 
  189. return $hash; 
  190.  
  191. if (strlen($random) < 6) 
  192. $random = $this->get_random_bytes(6); 
  193. $hash = 
  194. $this->crypt_private($password,  
  195. $this->gensalt_private($random)); 
  196. if (strlen($hash) == 34) 
  197. return $hash; 
  198.  
  199. # Returning '*' on error is safe here, but would _not_ be safe 
  200. # in a crypt(3)-like function used _both_ for generating new 
  201. # hashes and for validating passwords against existing hashes. 
  202. return '*'; 
  203.  
  204. function CheckPassword($password, $stored_hash) 
  205. if ( strlen( $password ) > 4096 ) { 
  206. return false; 
  207.  
  208. $hash = $this->crypt_private($password, $stored_hash); 
  209. if ($hash[0] == '*') 
  210. $hash = crypt($password, $stored_hash); 
  211.  
  212. return $hash === $stored_hash;