PageRenderTime 117ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Phpass/Hash/Adapter/Pbkdf2.php

http://github.com/rchouinard/phpass
PHP | 159 lines | 57 code | 21 blank | 81 comment | 12 complexity | f518519fc537e956e3138fa15fff9e4c MD5 | raw file
  1. <?php
  2. /**
  3. * PHP Password Library
  4. *
  5. * @package PHPass\Hashes
  6. * @category Cryptography
  7. * @author Ryan Chouinard <rchouinard at gmail.com>
  8. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  9. * @link https://github.com/rchouinard/phpass Project at GitHub
  10. */
  11. /**
  12. * @namespace
  13. */
  14. namespace Phpass\Hash\Adapter;
  15. /**
  16. * PBKDF2 hash adapter
  17. *
  18. * @package PHPass\Hashes
  19. * @category Cryptography
  20. * @author Ryan Chouinard <rchouinard at gmail.com>
  21. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  22. * @link https://github.com/rchouinard/phpass Project at GitHub
  23. */
  24. class Pbkdf2 extends Base
  25. {
  26. /**
  27. * Hashing algorithm used by the PBKDF2 implementation.
  28. *
  29. * @var string
  30. */
  31. protected $_algo = 'sha256';
  32. /**
  33. * Return a hashed string.
  34. *
  35. * @param string $password
  36. * The string to be hashed.
  37. * @param string $salt
  38. * An optional salt string to base the hashing on. If not provided, the
  39. * adapter will generate a new secure salt value.
  40. * @return string
  41. * Returns the hashed string.
  42. * @see Adapter::crypt()
  43. */
  44. public function crypt($password, $salt = null)
  45. {
  46. $setting = $salt;
  47. if (!$setting) {
  48. $setting = $this->genSalt();
  49. }
  50. // Return blowfish error string *0 or *1 on failure
  51. // Portable adapter does this, so we do it here to remain consistent
  52. $output = '*0';
  53. if (substr($setting, 0, 2) == $output) {
  54. $output = '*1';
  55. }
  56. if (substr($setting, 0, 6) != '$p5v2$') {
  57. return $output;
  58. }
  59. $countLog2 = $countLog2 = strpos($this->_itoa64, $setting[6]);
  60. if ($countLog2 < 0 || $countLog2 > 30) {
  61. return $output;
  62. }
  63. $count = 1 << $countLog2;
  64. $salt = substr($setting, 7, 8);
  65. if (strlen($salt) != 8) {
  66. return $output;
  67. }
  68. $hash = $this->_pbkdf2($password, $salt, $count, 24, $this->_algo);
  69. $output = substr($setting, 0, 16);
  70. $output .= $this->_encode64($hash, 24);
  71. return $output;
  72. }
  73. /**
  74. * Generate a salt string suitable for the crypt() method.
  75. *
  76. * Pbkdf2::genSalt() generates a 16-character salt string which can be
  77. * passed to crypt(). The salt consists of a string beginning with a
  78. * compatible hash identifier, one byte of iteration count, and an
  79. * 8-byte encoded salt followed by "$".
  80. *
  81. * @param string $input
  82. * Optional random data to be used when generating the salt. Must contain
  83. * at least 6 bytes of data.
  84. * @return string
  85. * Returns the generated salt string.
  86. * @see Adapter::genSalt()
  87. */
  88. public function genSalt($input = null)
  89. {
  90. if (!$input) {
  91. $input = $this->_getRandomBytes(6);
  92. }
  93. // PKCS #5, version 2
  94. // Python implementation uses $p5k2$, but we're not using a compatible
  95. // string. https://www.dlitz.net/software/python-pbkdf2/
  96. $output = '$p5v2$';
  97. // Iteration count between 1 and 1,073,741,824
  98. $output .= $this->_itoa64[min(max($this->_iterationCountLog2, 0), 30)];
  99. // 8-byte (64-bit) salt value, as recommended by the standard
  100. $output .= $this->_encode64($input, 6);
  101. // $p5v2$CSSSSSSSS$
  102. return $output . '$';
  103. }
  104. /**
  105. * Internal implementation of PKCS #5 v2.0.
  106. *
  107. * This implementation passes tests using vectors given in RFC 6070 s.2,
  108. * PBKDF2 HMAC-SHA1 Test Vectors. Vectors given for PBKDF2 HMAC-SHA2 at
  109. * http://stackoverflow.com/questions/5130513 also pass.
  110. *
  111. * @param string $password
  112. * The string to be hashed.
  113. * @param string $salt
  114. * Salt value used by the HMAC function.
  115. * @param integer $iterationCount
  116. * Number of iterations for key stretching.
  117. * @param integer $keyLength
  118. * Length of derived key.
  119. * @param string $algo
  120. * Algorithm to use when generating HMAC digest.
  121. * @return string
  122. * Returns the raw hash string.
  123. */
  124. protected function _pbkdf2($password, $salt, $iterationCount = 1000, $keyLength = 20, $algo = 'sha1')
  125. {
  126. $hashLength = strlen(hash($algo, null, true));
  127. $keyBlocks = ceil($keyLength / $hashLength);
  128. $derivedKey = '';
  129. for ($block = 1; $block <= $keyBlocks; ++$block) {
  130. $iteratedBlock = $currentBlock = hash_hmac($algo, $salt . pack('N', $block), $password, true);
  131. for ($iteration = 1; $iteration < $iterationCount; ++$iteration) {
  132. $iteratedBlock ^= $currentBlock = hash_hmac($algo, $currentBlock, $password, true);
  133. }
  134. $derivedKey .= $iteratedBlock;
  135. }
  136. return substr($derivedKey, 0, $keyLength);
  137. }
  138. }