PageRenderTime 47ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/PasswordLib/Password/Implementation/PBKDF.php

http://github.com/ircmaxell/PHP-PasswordLib
PHP | 166 lines | 79 code | 12 blank | 75 comment | 11 complexity | 706273666a52d29d3c46488c27e2596a MD5 | raw file
  1. <?php
  2. /**
  3. * The PBKDF based password hashing implementation
  4. *
  5. * Use this class to generate and validate PBKDF hashed passwords.
  6. *
  7. * PHP version 5.3
  8. *
  9. * @see http://httpd.apache.org/docs/2.2/misc/password_encryptions.html
  10. * @category PHPPasswordLib
  11. * @package Password
  12. * @subpackage Implementation
  13. * @author Anthony Ferrara <ircmaxell@ircmaxell.com>
  14. * @copyright 2011 The Authors
  15. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  16. * @version Build @@version@@
  17. */
  18. namespace PasswordLib\Password\Implementation;
  19. use PasswordLib\Key\Factory as KeyFactory;
  20. use PasswordLib\Random\Factory as RandomFactory;
  21. use PasswordLib\Key\Derivation\PBKDF\PBKDF2 as PBKDF2;
  22. /**
  23. * The PBKDF based password hashing implementation
  24. *
  25. * Use this class to generate and validate PBKDF hashed passwords.
  26. *
  27. * PHP version 5.3
  28. *
  29. * @see http://httpd.apache.org/docs/2.2/misc/password_encryptions.html
  30. * @category PHPPasswordLib
  31. * @package Password
  32. * @subpackage Implementation
  33. * @author Anthony Ferrara <ircmaxell@ircmaxell.com>
  34. */
  35. class PBKDF extends \PasswordLib\Password\AbstractPassword {
  36. protected $defaultOptions = array(
  37. 'kdf' => 'pbkdf2-sha512',
  38. 'size' => 40,
  39. 'iterations' => 5000,
  40. );
  41. /**
  42. * @var Generator The Random Number Generator to use for making salts
  43. */
  44. protected $generator = null;
  45. /**
  46. * @var string The prefix for the generated hash
  47. */
  48. protected static $prefix = '$pbkdf$';
  49. /**
  50. * Load an instance of the class based upon the supplied hash
  51. *
  52. * @param string $hash The hash to load from
  53. *
  54. * @return Password the created instance
  55. * @throws InvalidArgumentException if the hash wasn't created here
  56. */
  57. public static function loadFromHash($hash) {
  58. if (!static::detect($hash)) {
  59. throw new \InvalidArgumentException('Hash Not Created Here');
  60. }
  61. $parts = explode('$', $hash);
  62. if (count($parts) != 7) {
  63. throw new \InvalidArgumentException('Hash Not Created Here');
  64. }
  65. $signature = $parts[2];
  66. $factory = new KeyFactory();
  67. $hash = $factory->getPBKDFFromSignature($signature);
  68. $iterations = $parts[3];
  69. $size = $parts[4];
  70. return new static(array(
  71. 'kdf' => $hash,
  72. 'size' => $size,
  73. 'iterations' => $iterations,
  74. ));
  75. }
  76. /**
  77. * Set an option for the instance
  78. *
  79. * @param string $option The option to set
  80. * @param mixed $value The value to set the option to
  81. *
  82. * @return $this
  83. */
  84. public function setOption($option, $value) {
  85. if ($option == 'kdf') {
  86. if (!$value instanceof \PasswordLib\Key\Derivation\PBKDF) {
  87. $factory = new KeyFactory();
  88. $value = $factory->getPBKDFFromSignature($value);
  89. }
  90. }
  91. $this->options[$option] = $value;
  92. return $this;
  93. }
  94. /**
  95. * Create a password hash for a given plain text password
  96. *
  97. * @param string $password The password to hash
  98. *
  99. * @return string The formatted password hash
  100. */
  101. public function create($password) {
  102. $password = $this->checkPassword($password);
  103. $size = $this->options['size'] - 8; // remove size of stored bits
  104. $saltSize = floor($size / 5); //Use 20% of the size for the salt
  105. $hashSize = $size - $saltSize;
  106. $salt = $this->generator->generate($saltSize);
  107. return $this->hash(
  108. $password,
  109. $salt,
  110. $this->options['iterations'],
  111. $hashSize
  112. );
  113. }
  114. /**
  115. * Verify a password hash against a given plain text password
  116. *
  117. * @param string $password The password to hash
  118. * @param string $hash The supplied ahsh to validate
  119. *
  120. * @return boolean Does the password validate against the hash
  121. */
  122. public function verify($password, $hash) {
  123. $password = $this->checkPassword($password);
  124. if (strlen($hash) <= 16 || strpos($hash, '$') === false) {
  125. return false;
  126. }
  127. $parts = explode('$', $hash);
  128. if (count($parts) != 7) {
  129. return false;
  130. } elseif ($parts[2] != $this->options['kdf']->getSignature()) {
  131. return false;
  132. }
  133. $iterations = $parts[3];
  134. $size = $parts[4];
  135. $salt = base64_decode($parts[5]);
  136. $tmp = $this->hash($password, $salt, $iterations, $size);
  137. return $this->compareStrings($tmp, $hash);
  138. }
  139. /**
  140. * Perform the hashing of the password
  141. *
  142. * @param string $password The plain text password to hash
  143. * @param string $salt The 8 byte salt to use
  144. * @param int $iterations The number of iterations to use
  145. *
  146. * @return string The hashed password
  147. */
  148. protected function hash($password, $salt, $iterations, $size) {
  149. $bit = $this->options['kdf']->derive($password, $salt, $iterations, $size);
  150. $sig = $this->options['kdf']->getSignature();
  151. $sig = '$pbkdf$' . $sig . '$' . $iterations . '$' . $size;
  152. return $sig . '$' . base64_encode($salt) . '$' . base64_encode($bit);
  153. }
  154. }