| 1 | <?php
|
|---|
| 2 | /* -----------------------------------------------------------------------------------------
|
|---|
| 3 | $Id$
|
|---|
| 4 |
|
|---|
| 5 | modified eCommerce Shopsoftware
|
|---|
| 6 | http://www.modified-shop.org
|
|---|
| 7 |
|
|---|
| 8 | Copyright (c) 2009 - 2013 [www.modified-shop.org]
|
|---|
| 9 | -----------------------------------------------------------------------------------------
|
|---|
| 10 | based on:
|
|---|
| 11 | (c) 2004-2006 Solar Designer <solar at openwall.com>
|
|---|
| 12 | (c) 2009-2011 Sam Weiss http://eschercms.org/
|
|---|
| 13 |
|
|---|
| 14 | See the original project's web site: http://www.openwall.com/phpass/
|
|---|
| 15 |
|
|---|
| 16 | changed portable hash implementation to use sha1 instead of md5, and changed
|
|---|
| 17 | the hash signature to "$Q$" so that the hash is not mistaken for an md5 hash.
|
|---|
| 18 |
|
|---|
| 19 | -----------------------------------------------------------------------------------------
|
|---|
| 20 | Released under the GNU General Public License
|
|---|
| 21 | ---------------------------------------------------------------------------------------*/
|
|---|
| 22 |
|
|---|
| 23 |
|
|---|
| 24 | class validpass {
|
|---|
| 25 | private $itoa64;
|
|---|
| 26 | private $iteration_count_log2;
|
|---|
| 27 | private $portable_hashes;
|
|---|
| 28 | private $random_state;
|
|---|
| 29 | private $cryptType;
|
|---|
| 30 |
|
|---|
| 31 |
|
|---|
| 32 | public function __construct($iterationCountLog2=10, $portableHashes=false, $cryptType = '$2a$')
|
|---|
| 33 | {
|
|---|
| 34 | $this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
|---|
| 35 |
|
|---|
| 36 | if ($iterationCountLog2 < 4 || $iterationCountLog2 > 31)
|
|---|
| 37 | {
|
|---|
| 38 | $iterationCountLog2 = 8;
|
|---|
| 39 | }
|
|---|
| 40 |
|
|---|
| 41 | $this->iteration_count_log2 = $iterationCountLog2;
|
|---|
| 42 | $this->portable_hashes = $portableHashes;
|
|---|
| 43 | $this->random_state = microtime() . getmyinode() . '-' . getmypid();
|
|---|
| 44 | $this->cryptType =$cryptType;
|
|---|
| 45 | }
|
|---|
| 46 |
|
|---|
| 47 |
|
|---|
| 48 | public function encrypt_password($plain)
|
|---|
| 49 | {
|
|---|
| 50 | $random = '';
|
|---|
| 51 |
|
|---|
| 52 | if (CRYPT_BLOWFISH === 1 && !$this->portable_hashes && function_exists('version_compare') && version_compare(phpversion(), '5.3.7', '>='))
|
|---|
| 53 | {
|
|---|
| 54 | $random = $this->getRandomBytes(16);
|
|---|
| 55 | $hash = crypt($plain, $this->gensalt_blowfish($random));
|
|---|
| 56 | if (strlen($hash) === 60 && $this->validate_password($plain, $hash) === true)
|
|---|
| 57 | {
|
|---|
| 58 | return $hash;
|
|---|
| 59 | }
|
|---|
| 60 | }
|
|---|
| 61 |
|
|---|
| 62 | if (CRYPT_EXT_DES === 1 && !$this->portable_hashes && function_exists('version_compare') && version_compare(phpversion(), '5.3.0', '>='))
|
|---|
| 63 | {
|
|---|
| 64 | if (strlen($random) != 3)
|
|---|
| 65 | {
|
|---|
| 66 | $random = $this->getRandomBytes(3);
|
|---|
| 67 | }
|
|---|
| 68 | $hash = crypt($plain, $this->gensalt_ext_des($random));
|
|---|
| 69 | if (strlen($hash) === 20 && $this->validate_password($plain, $hash) === true)
|
|---|
| 70 | {
|
|---|
| 71 | return $hash;
|
|---|
| 72 | }
|
|---|
| 73 | }
|
|---|
| 74 |
|
|---|
| 75 | if (strlen($random) != 6)
|
|---|
| 76 | {
|
|---|
| 77 | $random = $this->getRandomBytes(6);
|
|---|
| 78 | }
|
|---|
| 79 | $hash = $this->crypt_portable($plain, $this->gensalt_portable($random));
|
|---|
| 80 | if (strlen($hash) === 39 && $this->validate_password($plain, $hash) === true)
|
|---|
| 81 | {
|
|---|
| 82 | return $hash;
|
|---|
| 83 | }
|
|---|
| 84 |
|
|---|
| 85 | # Returning '*' on error is safe here, but would _not_ be safe
|
|---|
| 86 | # in a crypt(3)-like function used _both_ for generating new
|
|---|
| 87 | # hashes and for validating messages against existing hashes.
|
|---|
| 88 |
|
|---|
| 89 | return '*';
|
|---|
| 90 | }
|
|---|
| 91 |
|
|---|
| 92 |
|
|---|
| 93 | public function validate_password($plain, $encrypted)
|
|---|
| 94 | {
|
|---|
| 95 | $hash = $this->crypt_portable($plain, $encrypted);
|
|---|
| 96 |
|
|---|
| 97 | if ($hash[0] === '*')
|
|---|
| 98 | {
|
|---|
| 99 | $hash = crypt($plain, $encrypted);
|
|---|
| 100 | }
|
|---|
| 101 |
|
|---|
| 102 | // ??? BETTER ???
|
|---|
| 103 | // return hash_equals($hash, $encrypted);
|
|---|
| 104 | return ($hash === $encrypted);
|
|---|
| 105 | }
|
|---|
| 106 |
|
|---|
| 107 |
|
|---|
| 108 | protected function getRandomBytes($count)
|
|---|
| 109 | {
|
|---|
| 110 | $output = '';
|
|---|
| 111 |
|
|---|
| 112 | if (strlen($output) < $count)
|
|---|
| 113 | {
|
|---|
| 114 | $output = '';
|
|---|
| 115 | for ($i = 0; $i < $count; $i += 16)
|
|---|
| 116 | {
|
|---|
| 117 | $this->random_state = sha1(microtime() . $this->random_state);
|
|---|
| 118 | $output .= sha1($this->random_state, true);
|
|---|
| 119 | }
|
|---|
| 120 | $output = substr($output, 0, $count);
|
|---|
| 121 | }
|
|---|
| 122 |
|
|---|
| 123 | return $output;
|
|---|
| 124 | }
|
|---|
| 125 |
|
|---|
| 126 |
|
|---|
| 127 | protected function encode64($input, $count)
|
|---|
| 128 | {
|
|---|
| 129 | $output = '';
|
|---|
| 130 | $i = 0;
|
|---|
| 131 |
|
|---|
| 132 | do
|
|---|
| 133 | {
|
|---|
| 134 | $value = ord($input[$i++]);
|
|---|
| 135 | $output .= $this->itoa64[$value & 0x3f];
|
|---|
| 136 | if ($i < $count)
|
|---|
| 137 | {
|
|---|
| 138 | $value |= ord($input[$i]) << 8;
|
|---|
| 139 | }
|
|---|
| 140 | $output .= $this->itoa64[($value >> 6) & 0x3f];
|
|---|
| 141 | if ($i++ >= $count)
|
|---|
| 142 | {
|
|---|
| 143 | break;
|
|---|
| 144 | }
|
|---|
| 145 | if ($i < $count)
|
|---|
| 146 | {
|
|---|
| 147 | $value |= ord($input[$i]) << 16;
|
|---|
| 148 | }
|
|---|
| 149 | $output .= $this->itoa64[($value >> 12) & 0x3f];
|
|---|
| 150 | if ($i++ >= $count)
|
|---|
| 151 | {
|
|---|
| 152 | break;
|
|---|
| 153 | }
|
|---|
| 154 | $output .= $this->itoa64[($value >> 18) & 0x3f];
|
|---|
| 155 | } while ($i < $count);
|
|---|
| 156 |
|
|---|
| 157 | return $output;
|
|---|
| 158 | }
|
|---|
| 159 |
|
|---|
| 160 |
|
|---|
| 161 | protected function crypt_portable($message, $setting)
|
|---|
| 162 | {
|
|---|
| 163 | $output = '*0';
|
|---|
| 164 |
|
|---|
| 165 | if (substr($setting, 0, 2) === $output)
|
|---|
| 166 | {
|
|---|
| 167 | $output = '*1';
|
|---|
| 168 | }
|
|---|
| 169 |
|
|---|
| 170 | if (substr($setting, 0, 3) != '$Q$')
|
|---|
| 171 | {
|
|---|
| 172 | return $output;
|
|---|
| 173 | }
|
|---|
| 174 |
|
|---|
| 175 | $count_log2 = strpos($this->itoa64, $setting[3]);
|
|---|
| 176 | if ($count_log2 < 7 || $count_log2 > 30)
|
|---|
| 177 | {
|
|---|
| 178 | return $output;
|
|---|
| 179 | }
|
|---|
| 180 |
|
|---|
| 181 | $count = 1 << $count_log2;
|
|---|
| 182 |
|
|---|
| 183 | $salt = substr($setting, 4, 8);
|
|---|
| 184 | if (strlen($salt) != 8)
|
|---|
| 185 | {
|
|---|
| 186 | return $output;
|
|---|
| 187 | }
|
|---|
| 188 |
|
|---|
| 189 | $hash = sha1($salt . $message, TRUE);
|
|---|
| 190 | do
|
|---|
| 191 | {
|
|---|
| 192 | $hash = sha1($hash . $message, TRUE);
|
|---|
| 193 | } while (--$count);
|
|---|
| 194 |
|
|---|
| 195 | $output = substr($setting, 0, 12) . $this->encode64($hash, 20);
|
|---|
| 196 |
|
|---|
| 197 | return $output;
|
|---|
| 198 | }
|
|---|
| 199 |
|
|---|
| 200 |
|
|---|
| 201 | protected function gensalt_portable($input)
|
|---|
| 202 | {
|
|---|
| 203 | $output = '$Q$';
|
|---|
| 204 | $output .= $this->itoa64[min($this->iteration_count_log2 + 5, 30)];
|
|---|
| 205 | $output .= $this->encode64($input, 6);
|
|---|
| 206 |
|
|---|
| 207 | return $output;
|
|---|
| 208 | }
|
|---|
| 209 |
|
|---|
| 210 |
|
|---|
| 211 | protected function gensalt_ext_des($input)
|
|---|
| 212 | {
|
|---|
| 213 | $count_log2 = min($this->iteration_count_log2 + 8, 24);
|
|---|
| 214 | # This should be odd to not reveal weak DES keys, and the
|
|---|
| 215 | # maximum valid value is (2**24 - 1) which is odd anyway.
|
|---|
| 216 | $count = (1 << $count_log2) - 1;
|
|---|
| 217 |
|
|---|
| 218 | $output = '_';
|
|---|
| 219 | $output .= $this->itoa64[$count & 0x3f];
|
|---|
| 220 | $output .= $this->itoa64[($count >> 6) & 0x3f];
|
|---|
| 221 | $output .= $this->itoa64[($count >> 12) & 0x3f];
|
|---|
| 222 | $output .= $this->itoa64[($count >> 18) & 0x3f];
|
|---|
| 223 |
|
|---|
| 224 | $output .= $this->encode64($input, 3);
|
|---|
| 225 |
|
|---|
| 226 | return $output;
|
|---|
| 227 | }
|
|---|
| 228 |
|
|---|
| 229 |
|
|---|
| 230 | protected function gensalt_blowfish($input)
|
|---|
| 231 | {
|
|---|
| 232 | # This one needs to use a different order of characters and a
|
|---|
| 233 | # different encoding scheme from the one in encode64() above.
|
|---|
| 234 | # We care because the last character in our encoded string will
|
|---|
| 235 | # only represent 2 bits. While two known implementations of
|
|---|
| 236 | # bcrypt will happily accept and correct a salt string which
|
|---|
| 237 | # has the 4 unused bits set to non-zero, we do not want to take
|
|---|
| 238 | # chances and we also do not want to waste an additional byte
|
|---|
| 239 | # of entropy.
|
|---|
| 240 | $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|---|
| 241 |
|
|---|
| 242 | //$output = '$2a$';
|
|---|
| 243 | //$output = '$2y$';
|
|---|
| 244 | $output = $this->cryptType;
|
|---|
| 245 | $output .= chr(ord('0') + $this->iteration_count_log2 / 10);
|
|---|
| 246 | $output .= chr(ord('0') + $this->iteration_count_log2 % 10);
|
|---|
| 247 | $output .= '$';
|
|---|
| 248 |
|
|---|
| 249 | $i = 0;
|
|---|
| 250 | do
|
|---|
| 251 | {
|
|---|
| 252 | $c1 = ord($input[$i++]);
|
|---|
| 253 | $output .= $itoa64[$c1 >> 2];
|
|---|
| 254 | $c1 = ($c1 & 0x03) << 4;
|
|---|
| 255 | if ($i >= 16)
|
|---|
| 256 | {
|
|---|
| 257 | $output .= $itoa64[$c1];
|
|---|
| 258 | break;
|
|---|
| 259 | }
|
|---|
| 260 |
|
|---|
| 261 | $c2 = ord($input[$i++]);
|
|---|
| 262 | $c1 |= $c2 >> 4;
|
|---|
| 263 | $output .= $itoa64[$c1];
|
|---|
| 264 | $c1 = ($c2 & 0x0f) << 2;
|
|---|
| 265 |
|
|---|
| 266 | $c2 = ord($input[$i++]);
|
|---|
| 267 | $c1 |= $c2 >> 6;
|
|---|
| 268 | $output .= $itoa64[$c1];
|
|---|
| 269 | $output .= $itoa64[$c2 & 0x3f];
|
|---|
| 270 | } while (1);
|
|---|
| 271 |
|
|---|
| 272 | return $output;
|
|---|
| 273 | }
|
|---|
| 274 | }
|
|---|
| 275 | ?>
|
|---|