/vendor/zendframework/zend-servicemanager/Zend/ServiceManager/library/Zend/Crypt/Password/Bcrypt.php

https://bitbucket.org/zbahij/eprojets_app · PHP · 198 lines · 104 code · 15 blank · 79 comment · 14 complexity · 58de050a8da4c44745fd0a064151b22a MD5 · raw file

  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. */
  9. namespace Zend\Crypt\Password;
  10. use Traversable;
  11. use Zend\Math\Rand;
  12. use Zend\Stdlib\ArrayUtils;
  13. /**
  14. * Bcrypt algorithm using crypt() function of PHP
  15. */
  16. class Bcrypt implements PasswordInterface
  17. {
  18. const MIN_SALT_SIZE = 16;
  19. /**
  20. * @var string
  21. */
  22. protected $cost = '14';
  23. /**
  24. * @var string
  25. */
  26. protected $salt;
  27. /**
  28. * @var boolean
  29. */
  30. protected $backwardCompatibility = false;
  31. /**
  32. * Constructor
  33. *
  34. * @param array|Traversable $options
  35. * @throws Exception\InvalidArgumentException
  36. */
  37. public function __construct($options = array())
  38. {
  39. if (!empty($options)) {
  40. if ($options instanceof Traversable) {
  41. $options = ArrayUtils::iteratorToArray($options);
  42. } elseif (!is_array($options)) {
  43. throw new Exception\InvalidArgumentException(
  44. 'The options parameter must be an array or a Traversable'
  45. );
  46. }
  47. foreach ($options as $key => $value) {
  48. switch (strtolower($key)) {
  49. case 'salt':
  50. $this->setSalt($value);
  51. break;
  52. case 'cost':
  53. $this->setCost($value);
  54. break;
  55. }
  56. }
  57. }
  58. }
  59. /**
  60. * Bcrypt
  61. *
  62. * @param string $password
  63. * @throws Exception\RuntimeException
  64. * @return string
  65. */
  66. public function create($password)
  67. {
  68. if (empty($this->salt)) {
  69. $salt = Rand::getBytes(self::MIN_SALT_SIZE);
  70. } else {
  71. $salt = $this->salt;
  72. }
  73. $salt64 = substr(str_replace('+', '.', base64_encode($salt)), 0, 22);
  74. /**
  75. * Check for security flaw in the bcrypt implementation used by crypt()
  76. * @see http://php.net/security/crypt_blowfish.php
  77. */
  78. if ((version_compare(PHP_VERSION, '5.3.7') >= 0) && !$this->backwardCompatibility) {
  79. $prefix = '$2y$';
  80. } else {
  81. $prefix = '$2a$';
  82. // check if the password contains 8-bit character
  83. if (preg_match('/[\x80-\xFF]/', $password)) {
  84. throw new Exception\RuntimeException(
  85. 'The bcrypt implementation used by PHP can contains a security flaw ' .
  86. 'using password with 8-bit character. ' .
  87. 'We suggest to upgrade to PHP 5.3.7+ or use passwords with only 7-bit characters'
  88. );
  89. }
  90. }
  91. $hash = crypt($password, $prefix . $this->cost . '$' . $salt64);
  92. if (strlen($hash) <= 13) {
  93. throw new Exception\RuntimeException('Error during the bcrypt generation');
  94. }
  95. return $hash;
  96. }
  97. /**
  98. * Verify if a password is correct against an hash value
  99. *
  100. * @param string $password
  101. * @param string $hash
  102. * @return bool
  103. */
  104. public function verify($password, $hash)
  105. {
  106. return ($hash === crypt($password, $hash));
  107. }
  108. /**
  109. * Set the cost parameter
  110. *
  111. * @param integer|string $cost
  112. * @throws Exception\InvalidArgumentException
  113. * @return Bcrypt
  114. */
  115. public function setCost($cost)
  116. {
  117. if (!empty($cost)) {
  118. $cost = (int) $cost;
  119. if ($cost < 4 || $cost > 31) {
  120. throw new Exception\InvalidArgumentException(
  121. 'The cost parameter of bcrypt must be in range 04-31'
  122. );
  123. }
  124. $this->cost = sprintf('%1$02d', $cost);
  125. }
  126. return $this;
  127. }
  128. /**
  129. * Get the cost parameter
  130. *
  131. * @return string
  132. */
  133. public function getCost()
  134. {
  135. return $this->cost;
  136. }
  137. /**
  138. * Set the salt value
  139. *
  140. * @param string $salt
  141. * @throws Exception\InvalidArgumentException
  142. * @return Bcrypt
  143. */
  144. public function setSalt($salt)
  145. {
  146. if (strlen($salt) < self::MIN_SALT_SIZE) {
  147. throw new Exception\InvalidArgumentException(
  148. 'The length of the salt must be at least ' . self::MIN_SALT_SIZE . ' bytes'
  149. );
  150. }
  151. $this->salt = $salt;
  152. return $this;
  153. }
  154. /**
  155. * Get the salt value
  156. *
  157. * @return string
  158. */
  159. public function getSalt()
  160. {
  161. return $this->salt;
  162. }
  163. /**
  164. * Set the backward compatibility $2a$ instead of $2y$ for PHP 5.3.7+
  165. *
  166. * @param boolean $value
  167. * @return Bcrypt
  168. */
  169. public function setBackwardCompatibility($value)
  170. {
  171. $this->backwardCompatibility = (boolean) $value;
  172. return $this;
  173. }
  174. /**
  175. * Get the backward compatibility
  176. *
  177. * @return boolean
  178. */
  179. public function getBackwardCompatibility()
  180. {
  181. return $this->backwardCompatibility;
  182. }
  183. }