Posted By

mladoux on 05/28/12


Tagged

password security codeigniter phpass bcrypt


Versions (?)

Who likes this?

1 person have marked this snippet as a favorite

Priestd09


Portable PHP Password Hashing Framework - Modified for CodeIgniter


 / Published in: PHP
 

URL: http://www.openwall.com/phpass/

Modified by adding public and protected declarations, renamed PasswordHash constructor to __construct. Adapted for use with CodeIgniter

  1. <?php
  2. /**
  3.  * Portable PHP password hashing framework.
  4.  *
  5.  * Version 0.3 / modified.
  6.  *
  7.  * Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
  8.  * the public domain. Revised in subsequent years, still public domain.
  9.  *
  10.  * Modified by adding public and protected declarations, renamed PasswordHash
  11.  * constructor to __construct. Adapted for use with CodeIgniter
  12.  *
  13.  * There's absolutely no warranty.
  14.  *
  15.  * The homepage URL for this framework is:
  16.  *
  17.  * http://www.openwall.com/phpass/
  18.  *
  19.  * Please be sure to update the Version line if you edit this file in any way.
  20.  * It is suggested that you leave the main version number intact, but indicate
  21.  * your project name (after the slash) and add your own revision information.
  22.  *
  23.  * Please do not change the "private" password hashing method implemented in
  24.  * here, thereby making your hashes incompatible. However, if you must, please
  25.  * change the hash type identifier (the "$P$") to something different.
  26.  *
  27.  * Obviously, since this code is in the public domain, the above are not
  28.  * requirements (there can be none), but merely suggestions.
  29.  */
  30. class Hasher {
  31. protected $itoa64;
  32. protected $iteration_count_log2;
  33. protected $portable_hashes;
  34. protected $random_state;
  35.  
  36. public function __construct()
  37. {
  38. $this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
  39.  
  40. // load ci instance temporarily to get some configuration data
  41. $ci =& get_instance();
  42.  
  43. // retrieve the configurations.
  44. if($ci->load->config('hasher', TRUE, TRUE))
  45. {
  46. $iteration_count_log2 = $ci->config->item('iterations', 'hasher');
  47. $portable_hashes = $ci->config->item('portable', 'hasher');
  48. }
  49. else
  50. {
  51. $iteration_count_log2 = 8;
  52. $portable_hashes = FALSE;
  53. }
  54.  
  55. // free up the memory used by the instance as it's not needed anymore.
  56. unset($ci);
  57.  
  58. if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
  59. $iteration_count_log2 = 8;
  60. $this->iteration_count_log2 = $iteration_count_log2;
  61.  
  62. $this->portable_hashes = $portable_hashes;
  63.  
  64. $this->random_state = microtime();
  65. if (function_exists('getmypid'))
  66. $this->random_state .= getmypid();
  67. }
  68.  
  69. protected function get_random_bytes($count)
  70. {
  71. $output = '';
  72. if (is_readable('/dev/urandom') &&
  73. ($fh = @fopen('/dev/urandom', 'rb'))) {
  74. $output = fread($fh, $count);
  75. fclose($fh);
  76. }
  77.  
  78. if (strlen($output) < $count) {
  79. $output = '';
  80. for ($i = 0; $i < $count; $i += 16) {
  81. $this->random_state =
  82. md5(microtime() . $this->random_state);
  83. $output .=
  84. pack('H*', md5($this->random_state));
  85. }
  86. $output = substr($output, 0, $count);
  87. }
  88.  
  89. return $output;
  90. }
  91.  
  92. protected function encode64($input, $count)
  93. {
  94. $output = '';
  95. $i = 0;
  96. do {
  97. $value = ord($input[$i++]);
  98. $output .= $this->itoa64[$value & 0x3f];
  99. if ($i < $count)
  100. $value |= ord($input[$i]) << 8;
  101. $output .= $this->itoa64[($value >> 6) & 0x3f];
  102. if ($i++ >= $count)
  103. break;
  104. if ($i < $count)
  105. $value |= ord($input[$i]) << 16;
  106. $output .= $this->itoa64[($value >> 12) & 0x3f];
  107. if ($i++ >= $count)
  108. break;
  109. $output .= $this->itoa64[($value >> 18) & 0x3f];
  110. } while ($i < $count);
  111.  
  112. return $output;
  113. }
  114.  
  115. protected function gensalt_private($input)
  116. {
  117. $output = '$P$';
  118. $output .= $this->itoa64[min($this->iteration_count_log2 +
  119. ((PHP_VERSION >= '5') ? 5 : 3), 30)];
  120. $output .= $this->encode64($input, 6);
  121.  
  122. return $output;
  123. }
  124.  
  125. protected function crypt_private($password, $setting)
  126. {
  127. $output = '*0';
  128. if (substr($setting, 0, 2) == $output)
  129. $output = '*1';
  130.  
  131. $id = substr($setting, 0, 3);
  132. # We use "$P$", phpBB3 uses "$H$" for the same thing
  133. if ($id != '$P$' && $id != '$H$')
  134. return $output;
  135.  
  136. $count_log2 = strpos($this->itoa64, $setting[3]);
  137. if ($count_log2 < 7 || $count_log2 > 30)
  138. return $output;
  139.  
  140. $count = 1 << $count_log2;
  141.  
  142. $salt = substr($setting, 4, 8);
  143. if (strlen($salt) != 8)
  144. return $output;
  145.  
  146. # We're kind of forced to use MD5 here since it's the only
  147. # cryptographic primitive available in all versions of PHP
  148. # currently in use. To implement our own low-level crypto
  149. # in PHP would result in much worse performance and
  150. # consequently in lower iteration counts and hashes that are
  151. # quicker to crack (by non-PHP code).
  152. if (PHP_VERSION >= '5') {
  153. $hash = md5($salt . $password, TRUE);
  154. do {
  155. $hash = md5($hash . $password, TRUE);
  156. } while (--$count);
  157. } else {
  158. $hash = pack('H*', md5($salt . $password));
  159. do {
  160. $hash = pack('H*', md5($hash . $password));
  161. } while (--$count);
  162. }
  163.  
  164. $output = substr($setting, 0, 12);
  165. $output .= $this->encode64($hash, 16);
  166.  
  167. return $output;
  168. }
  169.  
  170. protected function gensalt_extended($input)
  171. {
  172. $count_log2 = min($this->iteration_count_log2 + 8, 24);
  173. # This should be odd to not reveal weak DES keys, and the
  174. # maximum valid value is (2**24 - 1) which is odd anyway.
  175. $count = (1 << $count_log2) - 1;
  176.  
  177. $output = '_';
  178. $output .= $this->itoa64[$count & 0x3f];
  179. $output .= $this->itoa64[($count >> 6) & 0x3f];
  180. $output .= $this->itoa64[($count >> 12) & 0x3f];
  181. $output .= $this->itoa64[($count >> 18) & 0x3f];
  182.  
  183. $output .= $this->encode64($input, 3);
  184.  
  185. return $output;
  186. }
  187.  
  188. protected function gensalt_blowfish($input)
  189. {
  190. # This one needs to use a different order of characters and a
  191. # different encoding scheme from the one in encode64() above.
  192. # We care because the last character in our encoded string will
  193. # only represent 2 bits. While two known implementations of
  194. # bcrypt will happily accept and correct a salt string which
  195. # has the 4 unused bits set to non-zero, we do not want to take
  196. # chances and we also do not want to waste an additional byte
  197. # of entropy.
  198. $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  199.  
  200. $output = '$2a$';
  201. $output .= chr(ord('0') + $this->iteration_count_log2 / 10);
  202. $output .= chr(ord('0') + $this->iteration_count_log2 % 10);
  203. $output .= '$';
  204.  
  205. $i = 0;
  206. do {
  207. $c1 = ord($input[$i++]);
  208. $output .= $itoa64[$c1 >> 2];
  209. $c1 = ($c1 & 0x03) << 4;
  210. if ($i >= 16) {
  211. $output .= $itoa64[$c1];
  212. break;
  213. }
  214.  
  215. $c2 = ord($input[$i++]);
  216. $c1 |= $c2 >> 4;
  217. $output .= $itoa64[$c1];
  218. $c1 = ($c2 & 0x0f) << 2;
  219.  
  220. $c2 = ord($input[$i++]);
  221. $c1 |= $c2 >> 6;
  222. $output .= $itoa64[$c1];
  223. $output .= $itoa64[$c2 & 0x3f];
  224. } while (1);
  225.  
  226. return $output;
  227. }
  228.  
  229. public function HashPassword($password)
  230. {
  231. $random = '';
  232.  
  233. if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
  234. $random = $this->get_random_bytes(16);
  235. $hash =
  236. crypt($password, $this->gensalt_blowfish($random));
  237. if (strlen($hash) == 60)
  238. return $hash;
  239. }
  240.  
  241. if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
  242. if (strlen($random) < 3)
  243. $random = $this->get_random_bytes(3);
  244. $hash =
  245. crypt($password, $this->gensalt_extended($random));
  246. if (strlen($hash) == 20)
  247. return $hash;
  248. }
  249.  
  250. if (strlen($random) < 6)
  251. $random = $this->get_random_bytes(6);
  252. $hash =
  253. $this->crypt_private($password,
  254. $this->gensalt_private($random));
  255. if (strlen($hash) == 34)
  256. return $hash;
  257.  
  258. # Returning '*' on error is safe here, but would _not_ be safe
  259. # in a crypt(3)-like function used _both_ for generating new
  260. # hashes and for validating passwords against existing hashes.
  261. return '*';
  262. }
  263.  
  264. public function CheckPassword($password, $stored_hash)
  265. {
  266. $hash = $this->crypt_private($password, $stored_hash);
  267. if ($hash[0] == '*')
  268. $hash = crypt($password, $stored_hash);
  269.  
  270. return $hash == $stored_hash;
  271. }
  272. }

Report this snippet  

You need to login to post a comment.