PasswordHash

Portable PHP password hashing framework.

Defined (1)

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

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