├── .gitignore ├── README.md ├── config └── bcrypt.php └── libraries └── Bcrypt.php /.gitignore: -------------------------------------------------------------------------------- 1 | # OS generated files # 2 | .DS_Store* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # codeigniter-bcrypt 2 | 3 | ## DEPRECATION WARNING 4 | 5 | This library is not maintained, and it is suggested that you don't use it. It was simply a CodeIgniter wrapper around the PHPPass library. Please look into using [PHP's native password hasing functions instead](https://secure.php.net/manual/en/function.password-hash.php). 6 | 7 | 8 | ## Bcrypt (PHPPass) for CodeIgniter 9 | 10 | Adaption of PHPPass (0.3) for use as a CodeIgniter Bcrypt library. 11 | 12 | Allowed for the use of a separate config file, adjusted for some CodeIgniter configurability, added the scope of functions, changed hashing and checking functions to meet CodeIgniter standards for function names. 13 | 14 | ## Installation 15 | 16 | * Place ``Bcrypt.php`` in your ``application/libraries`` folder. 17 | * Place ``bcrypt.php`` in your ``application/config`` folder. 18 | * Adjust options in the config file as neccessary. 19 | 20 | ## Usage 21 | First, load the Bcrypt library or autoload it in ``config/autoload.php``. 22 | 23 | $this->load->library('bcrypt'); 24 | 25 | ### Hashing 26 | To hash a password, simply pass the string to ``hash_password()``. 27 | 28 | $password = 'hunter2'; 29 | $hash = $this->bcrypt->hash_password($password); 30 | 31 | The function will return the hashed password or ``*`` on error. 32 | 33 | ### Checking 34 | To check a hash password, simply pass the string and stored password to ``check_password()``. 35 | 36 | $password = 'hunter2'; 37 | 38 | if ($this->bcrypt->check_password($password, $stored_hash)) 39 | { 40 | // Password does match stored password. 41 | } 42 | else 43 | { 44 | // Password does not match stored password. 45 | } 46 | 47 | The function will return ``TRUE`` or ``FALSE`` dependant on success. 48 | -------------------------------------------------------------------------------- /config/bcrypt.php: -------------------------------------------------------------------------------- 1 | in 2004-2006 and placed in 10 | * the public domain. Revised in subsequent years, still public domain. 11 | * 12 | * There's absolutely no warranty. 13 | * 14 | * The homepage URL for this framework is: 15 | * 16 | * http://www.openwall.com/phpass/ 17 | * 18 | * Please be sure to update the Version line if you edit this file in any way. 19 | * It is suggested that you leave the main version number intact, but indicate 20 | * your project name (after the slash) and add your own revision information. 21 | * 22 | * Please do not change the "private" password hashing method implemented in 23 | * here, thereby making your hashes incompatible. However, if you must, please 24 | * change the hash type identifier (the "$P$") to something different. 25 | * 26 | * Obviously, since this code is in the public domain, the above are not 27 | * requirements (there can be none), but merely suggestions. 28 | **/ 29 | class Bcrypt { 30 | 31 | /** 32 | * Privates 33 | */ 34 | private $_itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; 35 | private $_random_state; 36 | 37 | /** 38 | * Options 39 | */ 40 | private $_iteration_count = 8; 41 | private $_portable_hashes = FALSE; 42 | 43 | /** 44 | * Constructor 45 | * 46 | * @access public 47 | * @param array 48 | */ 49 | public function __construct($params = array()) 50 | { 51 | if (count($params) > 0) 52 | { 53 | $this->initialize($params); 54 | } 55 | 56 | if ($this->_iteration_count < 4 || $this->_iteration_count > 31) 57 | $this->_iteration_count = 8; 58 | 59 | $this->_random_state = microtime(); 60 | if (function_exists('getmypid')) 61 | $this->_random_state .= getmypid(); 62 | } 63 | 64 | /** 65 | * Initialize preferences 66 | * 67 | * @access public 68 | * @param array 69 | * @return void 70 | */ 71 | private function initialize($params = array()) 72 | { 73 | if (count($params) > 0) 74 | { 75 | foreach ($params as $key => $value) 76 | { 77 | if (isset($this->{'_' . $key})) 78 | { 79 | $this->{'_' . $key} = $value; 80 | } 81 | } 82 | } 83 | } 84 | 85 | protected function get_random_bytes($count) 86 | { 87 | $output = ''; 88 | if (is_readable('/dev/urandom') && 89 | ($fh = @fopen('/dev/urandom', 'rb'))) { 90 | $output = fread($fh, $count); 91 | fclose($fh); 92 | } 93 | 94 | if (strlen($output) < $count) { 95 | $output = ''; 96 | for ($i = 0; $i < $count; $i += 16) { 97 | $this->_random_state = 98 | md5(microtime() . $this->_random_state); 99 | $output .= 100 | pack('H*', md5($this->_random_state)); 101 | } 102 | $output = substr($output, 0, $count); 103 | } 104 | 105 | return $output; 106 | } 107 | 108 | protected function encode64($input, $count) 109 | { 110 | $output = ''; 111 | $i = 0; 112 | do { 113 | $value = ord($input[$i++]); 114 | $output .= $this->_itoa64[$value & 0x3f]; 115 | if ($i < $count) 116 | $value |= ord($input[$i]) << 8; 117 | $output .= $this->_itoa64[($value >> 6) & 0x3f]; 118 | if ($i++ >= $count) 119 | break; 120 | if ($i < $count) 121 | $value |= ord($input[$i]) << 16; 122 | $output .= $this->_itoa64[($value >> 12) & 0x3f]; 123 | if ($i++ >= $count) 124 | break; 125 | $output .= $this->_itoa64[($value >> 18) & 0x3f]; 126 | } while ($i < $count); 127 | 128 | return $output; 129 | } 130 | 131 | protected function gensalt_private($input) 132 | { 133 | $output = '$P$'; 134 | $output .= $this->_itoa64[min($this->_iteration_count + 135 | ((PHP_VERSION >= '5') ? 5 : 3), 30)]; 136 | $output .= $this->encode64($input, 6); 137 | 138 | return $output; 139 | } 140 | 141 | protected function crypt_private($password, $setting) 142 | { 143 | $output = '*0'; 144 | if (substr($setting, 0, 2) == $output) 145 | $output = '*1'; 146 | 147 | $id = substr($setting, 0, 3); 148 | # We use "$P$", phpBB3 uses "$H$" for the same thing 149 | if ($id != '$P$' && $id != '$H$') 150 | return $output; 151 | 152 | $count_log2 = strpos($this->_itoa64, $setting[3]); 153 | if ($count_log2 < 7 || $count_log2 > 30) 154 | return $output; 155 | 156 | $count = 1 << $count_log2; 157 | 158 | $salt = substr($setting, 4, 8); 159 | if (strlen($salt) != 8) 160 | return $output; 161 | 162 | # We're kind of forced to use MD5 here since it's the only 163 | # cryptographic primitive available in all versions of PHP 164 | # currently in use. To implement our own low-level crypto 165 | # in PHP would result in much worse performance and 166 | # consequently in lower iteration counts and hashes that are 167 | # quicker to crack (by non-PHP code). 168 | if (PHP_VERSION >= '5') { 169 | $hash = md5($salt . $password, TRUE); 170 | do { 171 | $hash = md5($hash . $password, TRUE); 172 | } while (--$count); 173 | } else { 174 | $hash = pack('H*', md5($salt . $password)); 175 | do { 176 | $hash = pack('H*', md5($hash . $password)); 177 | } while (--$count); 178 | } 179 | 180 | $output = substr($setting, 0, 12); 181 | $output .= $this->encode64($hash, 16); 182 | 183 | return $output; 184 | } 185 | 186 | protected function gensalt_extended($input) 187 | { 188 | $count_log2 = min($this->_iteration_count + 8, 24); 189 | # This should be odd to not reveal weak DES keys, and the 190 | # maximum valid value is (2**24 - 1) which is odd anyway. 191 | $count = (1 << $count_log2) - 1; 192 | 193 | $output = '_'; 194 | $output .= $this->_itoa64[$count & 0x3f]; 195 | $output .= $this->_itoa64[($count >> 6) & 0x3f]; 196 | $output .= $this->_itoa64[($count >> 12) & 0x3f]; 197 | $output .= $this->_itoa64[($count >> 18) & 0x3f]; 198 | 199 | $output .= $this->encode64($input, 3); 200 | 201 | return $output; 202 | } 203 | 204 | protected function gensalt_blowfish($input) 205 | { 206 | # This one needs to use a different order of characters and a 207 | # different encoding scheme from the one in encode64() above. 208 | # We care because the last character in our encoded string will 209 | # only represent 2 bits. While two known implementations of 210 | # bcrypt will happily accept and correct a salt string which 211 | # has the 4 unused bits set to non-zero, we do not want to take 212 | # chances and we also do not want to waste an additional byte 213 | # of entropy. 214 | $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 215 | 216 | $output = '$2a$'; 217 | $output .= chr(ord('0') + $this->_iteration_count / 10); 218 | $output .= chr(ord('0') + $this->_iteration_count % 10); 219 | $output .= '$'; 220 | 221 | $i = 0; 222 | do { 223 | $c1 = ord($input[$i++]); 224 | $output .= $itoa64[$c1 >> 2]; 225 | $c1 = ($c1 & 0x03) << 4; 226 | if ($i >= 16) { 227 | $output .= $itoa64[$c1]; 228 | break; 229 | } 230 | 231 | $c2 = ord($input[$i++]); 232 | $c1 |= $c2 >> 4; 233 | $output .= $itoa64[$c1]; 234 | $c1 = ($c2 & 0x0f) << 2; 235 | 236 | $c2 = ord($input[$i++]); 237 | $c1 |= $c2 >> 6; 238 | $output .= $itoa64[$c1]; 239 | $output .= $itoa64[$c2 & 0x3f]; 240 | } while (1); 241 | 242 | return $output; 243 | } 244 | 245 | public function hash_password($password) 246 | { 247 | $random = ''; 248 | 249 | if (CRYPT_BLOWFISH == 1 && !$this->_portable_hashes) { 250 | $random = $this->get_random_bytes(16); 251 | $hash = 252 | crypt($password, $this->gensalt_blowfish($random)); 253 | if (strlen($hash) == 60) 254 | return $hash; 255 | } 256 | 257 | if (CRYPT_EXT_DES == 1 && !$this->_portable_hashes) { 258 | if (strlen($random) < 3) 259 | $random = $this->get_random_bytes(3); 260 | $hash = 261 | crypt($password, $this->gensalt_extended($random)); 262 | if (strlen($hash) == 20) 263 | return $hash; 264 | } 265 | 266 | if (strlen($random) < 6) 267 | $random = $this->get_random_bytes(6); 268 | $hash = 269 | $this->crypt_private($password, 270 | $this->gensalt_private($random)); 271 | if (strlen($hash) == 34) 272 | return $hash; 273 | 274 | # Returning '*' on error is safe here, but would _not_ be safe 275 | # in a crypt(3)-like function used _both_ for generating new 276 | # hashes and for validating passwords against existing hashes. 277 | return '*'; 278 | } 279 | 280 | public function check_password($password, $stored_hash) 281 | { 282 | $hash = $this->crypt_private($password, $stored_hash); 283 | if ($hash[0] == '*') 284 | $hash = crypt($password, $stored_hash); 285 | 286 | return $hash == $stored_hash; 287 | } 288 | } 289 | 290 | /* End of file bcrypt.php */ 291 | /* Location: ./application/libraries/bcrypt.php */ --------------------------------------------------------------------------------