/passhash.php

https://github.com/bproctor/PassHash · PHP · 144 lines · 32 code · 11 blank · 101 comment · 2 complexity · 99d00a2974f0e6ad35458b655c747543 MD5 · raw file

  1. <?php
  2. /**
  3. * passhash.php
  4. *
  5. * A strong password hashing class for PHP
  6. *
  7. * Copyright (c) 2010-2012 Brad Proctor. (http://bradleyproctor.com)
  8. *
  9. * Licensed under The MIT License
  10. * Redistributions of files must retain the above copyright notice.
  11. *
  12. * @author Brad Proctor
  13. * @copyright Copyright (c) 2010-2012 Brad Proctor
  14. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  15. * @link http://bradleyproctor.com/
  16. * @version 1.9.1
  17. */
  18. /**
  19. * The Password class works by generating a 104-character hash. The first 16 characters are a unique
  20. * salt value that is generated for each password. The rest of the 88 characters is the hash generated
  21. * by the whirlpool algorithm, which is much stronger than common md5 or sha1 methods. The hash value is
  22. * also created using the HMAC method and a site wide key is used to further secure the hash. The site
  23. * wide key can be any value, but a very strong 80-character unique value for 'authPepper' can be generated at
  24. * http://bradleyproctor.com/tools/salt.php
  25. *
  26. * Usage:
  27. * $hash = Passhash::hash('password'); // Store this value in your database
  28. *
  29. * if (Passhash::compare('password', $hash) === true) {
  30. * // Password is correct
  31. * } else {
  32. * // Password was incorrect
  33. * }
  34. */
  35. abstract class Passhash
  36. {
  37. /**
  38. * Number of characters in the salt value
  39. */
  40. const saltLength = 16;
  41. /**
  42. * a unique site-wide value (pepper) to compliment the unique salts.
  43. * Change this to a unique value.
  44. */
  45. const authPepper = 'jS#W_;[;sjiNOUc9NG,S3T76NOTmK~%mu|#WI9-v.l^Bt]6H)1wz:kc=hPtS+JZv)haB!0dTo}klfWrr';
  46. /**
  47. * Used for key stretching. It is used to calculate the number of iterations to run the
  48. * hashing algorithm. Raise this to increase security, lower this to make it run faster. Default value
  49. * is 5.
  50. */
  51. const authLevel = 5;
  52. /*************************************************************************************/
  53. /**
  54. * Generate a password salt
  55. *
  56. * @param int $length
  57. * The number of characters that the salt should be
  58. *
  59. * @return string
  60. * Returns a salt that can be used to salt a password hash
  61. *
  62. * @access private
  63. */
  64. final private static function salt()
  65. {
  66. $salt = '';
  67. while (strlen($salt) < static::saltLength) {
  68. $salt .= pack('C', dechex(mt_rand()));
  69. }
  70. return substr(base64_encode($salt), 0, static::saltLength);
  71. }
  72. /**
  73. * PBKDF2 Implementation (described in RFC 2898)
  74. * Password-Based Key Derivation Function
  75. * (Simplified, since some variables are known)
  76. *
  77. * @param string $password
  78. * The plain text password
  79. *
  80. * @param string $salt
  81. * The salt used to generate the hash
  82. *
  83. * @return string
  84. * Derived key
  85. *
  86. * @access private
  87. */
  88. final private static function pbkdf2($password, $salt)
  89. {
  90. $ib = $b = hash_hmac('whirlpool', $salt . static::authPepper, $password, true);
  91. for ($i = 1; $i < static::authLevel * 1000; $i++) {
  92. $ib ^= ($b = hash_hmac('whirlpool', $b . static::authPepper, $password, true));
  93. }
  94. return base64_encode($ib);
  95. }
  96. /**
  97. * Generate a 104 character password hash
  98. *
  99. * @param string $password
  100. * The plain text password
  101. *
  102. * @param string $salt
  103. * The salt to use to generate the password
  104. *
  105. * @return string
  106. * Returns the 104-character hashed and salted password
  107. *
  108. * @access public
  109. */
  110. final public static function hash($password, $salt = null)
  111. {
  112. $salt or $salt = static::salt();
  113. return $salt . static::pbkdf2($password, $salt);
  114. }
  115. /**
  116. * Compare a password with a hash
  117. *
  118. * @param string $password
  119. * The plain text password to compare
  120. *
  121. * @param string $hash
  122. * The 104 character password hash
  123. *
  124. * @return bool
  125. * Returns TRUE if the password matches, FALSE if not
  126. *
  127. * @access public
  128. */
  129. final public static function compare($password, $hash)
  130. {
  131. return 0 === strcmp($hash, static::hash($password, substr($hash, 0, static::saltLength), static::authLevel));
  132. }
  133. }