bcrypt.php 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. <?php
  2. /**
  3. * Copyright (c) 2009-2019 F3::Factory/Bong Cosca, All rights reserved.
  4. *
  5. * This file is part of the Fat-Free Framework (http://fatfreeframework.com).
  6. *
  7. * This is free software: you can redistribute it and/or modify it under the
  8. * terms of the GNU General Public License as published by the Free Software
  9. * Foundation, either version 3 of the License, or later.
  10. *
  11. * Fat-Free Framework is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with Fat-Free Framework. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. **/
  20. /**
  21. * Lightweight password hashing library (PHP 5.5+ only)
  22. * @deprecated Use http://php.net/manual/en/ref.password.php instead
  23. **/
  24. class Bcrypt extends Prefab {
  25. //@{ Error messages
  26. const
  27. E_CostArg='Invalid cost parameter',
  28. E_SaltArg='Salt must be at least 22 alphanumeric characters';
  29. //@}
  30. //! Default cost
  31. const
  32. COST=10;
  33. /**
  34. * Generate bcrypt hash of string
  35. * @return string|FALSE
  36. * @param $pw string
  37. * @param $salt string
  38. * @param $cost int
  39. **/
  40. function hash($pw,$salt=NULL,$cost=self::COST) {
  41. if ($cost<4 || $cost>31)
  42. user_error(self::E_CostArg,E_USER_ERROR);
  43. $len=22;
  44. if ($salt) {
  45. if (!preg_match('/^[[:alnum:]\.\/]{'.$len.',}$/',$salt))
  46. user_error(self::E_SaltArg,E_USER_ERROR);
  47. }
  48. else {
  49. $raw=16;
  50. $iv='';
  51. if (!$iv && extension_loaded('openssl'))
  52. $iv=openssl_random_pseudo_bytes($raw);
  53. if (!$iv)
  54. for ($i=0;$i<$raw;$i++)
  55. $iv.=chr(mt_rand(0,255));
  56. $salt=str_replace('+','.',base64_encode($iv));
  57. }
  58. $salt=substr($salt,0,$len);
  59. $hash=crypt($pw,sprintf('$2y$%02d$',$cost).$salt);
  60. return strlen($hash)>13?$hash:FALSE;
  61. }
  62. /**
  63. * Check if password is still strong enough
  64. * @return bool
  65. * @param $hash string
  66. * @param $cost int
  67. **/
  68. function needs_rehash($hash,$cost=self::COST) {
  69. list($pwcost)=sscanf($hash,"$2y$%d$");
  70. return $pwcost<$cost;
  71. }
  72. /**
  73. * Verify password against hash using timing attack resistant approach
  74. * @return bool
  75. * @param $pw string
  76. * @param $hash string
  77. **/
  78. function verify($pw,$hash) {
  79. $val=crypt($pw,$hash);
  80. $len=strlen($val);
  81. if ($len!=strlen($hash) || $len<14)
  82. return FALSE;
  83. $out=0;
  84. for ($i=0;$i<$len;$i++)
  85. $out|=(ord($val[$i])^ord($hash[$i]));
  86. return $out===0;
  87. }
  88. }