bcrypt.php 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. <?php
  2. /**
  3. * PHP bcrypt wrapper
  4. *
  5. * Bcrypt is a wrapper to simplify the use of bcrypt algorithm in PHP.
  6. *
  7. * Functionality is stronlgy based on article published by Thomas Ptacek on
  8. * http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know
  9. * -about-s.html. It also features constant-time algorithm as nicely described by Coda Hale on
  10. * http://codahale.com/a-lesson-in-timing-attacks/.
  11. *
  12. * Usage example:
  13. *
  14. * // hash password before storing it
  15. * $hashed = Bcrypt::hash($password);
  16. *
  17. * // check password by comparing it to its hashed value
  18. * $check = Bcrypt::check($password, $hashed);
  19. *
  20. * // use a stronger salt
  21. * $salt = Bcrypt::salt(24); // 2^24 iterations
  22. * $hashed = Bcrypt::hash($password, $salt);
  23. *
  24. * @author David Kuridža <david@kuridza.si>
  25. * @license http://www.opensource.org/licenses/mit-license.php MIT
  26. * @link http://github.com/davidkuridza/php-bcrypt-wrapper
  27. */
  28. class Bcrypt {
  29. /**
  30. * Default number of iterations for salt generation. Can be between and including `4` and `31`.
  31. *
  32. * @var integer
  33. */
  34. const DEFAULT_ITERATION_COUNT = 10;
  35. /**
  36. * Hashes a password using PHP's `crypt()` function and a salt. If no salt is provided, it is
  37. * generated using `Bcrypt::salt()` with default iteration of `Bcrypt::DEFAULT_ITERATION_COUNT`.
  38. *
  39. * @param string $password Password to be hashed.
  40. * @param string $salt Optional. The salt string to be used.
  41. * @return string
  42. */
  43. public static function hash($password, $salt = null) {
  44. return crypt($password, $salt ? : self::salt());
  45. }
  46. /**
  47. * Checks `$password` and its stored `$hash` value using PHP's `crypt()` function and
  48. * constant-time algorithm to defend againt timing attacks, see
  49. * http://codahale.com/a-lesson-in-timing-attacks/ for more details.
  50. *
  51. * @param string $password Password to check.
  52. * @param string $hash Hashed password to compare `$password` to.
  53. * @return boolean
  54. */
  55. public static function check($password, $hash) {
  56. // hash it
  57. $password = crypt($password, $hash);
  58. // firstly, make sure both hashes are of the same length
  59. if (($length = strlen($password)) !== strlen($hash)) {
  60. return false;
  61. }
  62. // flag to be returned
  63. $result = 0;
  64. // check each character
  65. for ($i = 0; $i < $length; $i++) {
  66. // character at position $i need to be the same
  67. $result |= $password[$i] !== $hash[$i];
  68. }
  69. // so, is it valid?
  70. return $result === 0;
  71. }
  72. /**
  73. * Generate cryptographically strong salt using Blowfish method.
  74. *
  75. * @param integer $iteration Optional. Base-2 logarithm of the iteration, defaults to `10`.
  76. * Can be between and including `4` and `31`.
  77. * @return string
  78. * @throws \InvalidArgumentException if `$iterationCount` is out of bounds.
  79. */
  80. public static function salt($iterationCount = self::DEFAULT_ITERATION_COUNT) {
  81. // make sure $iteration is valid
  82. if ((int) $iterationCount < 4 || (int) $iterationCount > 31) {
  83. $message = '$iterationCount value has to be between 4 and 31.';
  84. throw new \InvalidArgumentException($message);
  85. }
  86. return sprintf(
  87. '$2a$%02d$%s', $iterationCount,
  88. // black magic :)
  89. substr(
  90. strtr(
  91. base64_encode(openssl_random_pseudo_bytes(16)), '+', '.'
  92. ), 0, 22
  93. )
  94. );
  95. }
  96. }
  97. ?>