add methods to decrypt return data from router
[GitHub/Stricted/speedport-hybrid-php-api.git] / CryptLib / Password / Implementation / PHPASS.php
1 <?php
2 /**
3 * The PHPASS password hashing implementation
4 *
5 * Use this class to generate and validate PHPASS password hashes.
6 *
7 * PHP version 5.3
8 *
9 * @see http://www.openwall.com/phpass/
10 * @category PHPCryptLib
11 * @package Password
12 * @subpackage Implementation
13 * @author Anthony Ferrara <ircmaxell@ircmaxell.com>
14 * @copyright 2011 The Authors
15 * @license http://www.opensource.org/licenses/mit-license.html MIT License
16 * @version Build @@version@@
17 */
18
19 namespace CryptLib\Password\Implementation;
20
21 use CryptLib\Random\Factory as RandomFactory;
22
23 /**
24 * The PHPASS password hashing implementation
25 *
26 * Use this class to generate and validate PHPASS password hashes.
27 *
28 * @see http://www.openwall.com/phpass/
29 * @category PHPCryptLib
30 * @package Password
31 * @subpackage Implementation
32 * @author Anthony Ferrara <ircmaxell@ircmaxell.com>
33 */
34 class PHPASS implements \CryptLib\Password\Password {
35
36 /**
37 * @var string The ITOA string to be used for base64 conversion
38 */
39 protected static $itoa = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ
40 abcdefghijklmnopqrstuvwxyz';
41
42 /**
43 * @var Generator The random generator to use for seeds
44 */
45 protected $generator = null;
46
47 /**
48 * This is the hash function to use. To be overriden by child classes
49 *
50 * @var string The hash function to use for this instance
51 */
52 protected $hashFunction = 'md5';
53
54 /**
55 * @var int The number of iterations to perform (base 2)
56 */
57 protected $iterations = 10;
58
59 /**
60 * @var string The prefix for the generated hash
61 */
62 protected static $prefix = '$P$';
63
64 /**
65 * Determine if the hash was made with this method
66 *
67 * @param string $hash The hashed data to check
68 *
69 * @return boolean Was the hash created by this method
70 */
71 public static function detect($hash) {
72 $prefix = preg_quote(static::$prefix, '/');
73 return 1 == preg_match('/^'.$prefix.'[a-zA-Z0-9.\/]{31}$/', $hash);
74 }
75
76 /**
77 * Return the prefix used by this hashing method
78 *
79 * @return string The prefix used
80 */
81 public static function getPrefix() {
82 return static::$prefix;
83 }
84
85 /**
86 * Initialize the password hasher by replacing away spaces in the itoa var
87 *
88 * @return void
89 */
90 public static function init() {
91 static::$itoa = preg_replace('/\s/', '', static::$itoa);
92 }
93
94 /**
95 * Load an instance of the class based upon the supplied hash
96 *
97 * @param string $hash The hash to load from
98 *
99 * @return Password the created instance
100 * @throws InvalidArgumentException if the hash wasn't created here
101 */
102 public static function loadFromHash($hash) {
103 if (!static::detect($hash)) {
104 throw new \InvalidArgumentException('Hash Not Created Here');
105 }
106 $iterations = static::decodeIterations($hash[3]);
107 return new static($iterations);
108 }
109
110 /**
111 * Decode an ITOA encoded iteration count
112 *
113 * @param string $byte The character to decode
114 *
115 * @return int The decoded iteration count (base2)
116 */
117 protected static function decodeIterations($byte) {
118 return strpos(static::$itoa, $byte);
119 }
120
121 /**
122 * Encode a base2 iteration count to a base64 character
123 *
124 * @param int $number
125 *
126 * @return string The encoded character
127 */
128 protected static function encodeIterations($number) {
129 return static::$itoa[$number];
130 }
131
132 /**
133 * Build a new instance
134 *
135 * @param int $iterations The number of times to iterate the hash
136 * @param Generator $generator The random generator to use for seeds
137 * @param Factory $factory The hash factory to use for this instance
138 *
139 * @return void
140 */
141 public function __construct(
142 $iterations = 8,
143 \CryptLib\Random\Generator $generator = null
144 ) {
145 if ($iterations > 30 || $iterations < 7) {
146 throw new \InvalidArgumentException('Invalid Iteration Count Supplied');
147 }
148 $this->iterations = $iterations;
149 if (is_null($generator)) {
150 $random = new RandomFactory();
151 $generator = $random->getMediumStrengthGenerator();
152 }
153 $this->generator = $generator;
154 }
155
156 /**
157 * Create a password hash for a given plain text password
158 *
159 * @param string $password The password to hash
160 *
161 * @return string The formatted password hash
162 */
163 public function create($password) {
164 $salt = $this->to64($this->generator->generate(6));
165 $prefix = static::encodeIterations($this->iterations) . $salt;
166 return static::$prefix . $prefix . $this->hash($password, $salt);
167 }
168
169 /**
170 * Verify a password hash against a given plain text password
171 *
172 * @param string $password The password to hash
173 * @param string $hash The supplied ahsh to validate
174 *
175 * @return boolean Does the password validate against the hash
176 */
177 public function verify($password, $hash) {
178 if (!static::detect($hash)) {
179 throw new \InvalidArgumentException(
180 'The hash was not created here, we cannot verify it'
181 );
182 }
183 $iterations = static::decodeIterations($hash[3]);
184 if ($iterations != $this->iterations) {
185 throw new \InvalidArgumentException(
186 'Iteration Count Mismatch, Bailing'
187 );
188 }
189 $salt = substr($hash, 4, 8);
190 $hash = substr($hash, 12);
191 $test = $this->hash($password, $salt);
192 return $test == $hash;
193 }
194
195 /**
196 * Execute the hash function with proper iterations
197 *
198 * @param string $password The password to hash
199 * @param string $salt The salt to use to hash
200 *
201 * @return string The base64 encoded generated hash
202 */
203 protected function hash($password, $salt) {
204 $count = 1 << $this->iterations;
205 $hash = hash($this->hashFunction, $salt . $password, true);
206 do {
207 $hash = hash($this->hashFunction, $hash . $password, true);
208 } while (--$count);
209 return $this->to64($hash);
210 }
211
212 /**
213 * Convert the input number to a base64 number of the specified size
214 *
215 * @param int $input The number to convert
216 *
217 * @return string The converted representation
218 */
219 protected function to64($input) {
220 $output = '';
221 $count = strlen($input);
222 $ictr = 0;
223 do {
224 $value = ord($input[$ictr++]);
225 $output .= static::$itoa[$value & 0x3f];
226 if ($ictr < $count) {
227 $value |= ord($input[$ictr]) << 8;
228 }
229 $output .= static::$itoa[($value >> 6) & 0x3f];
230 if ($ictr++ >= $count) {
231 break;
232 }
233 if ($ictr < $count) {
234 $value |= ord($input[$ictr]) << 16;
235 }
236 $output .= static::$itoa[($value >> 12) & 0x3f];
237 if ($ictr++ < $count) {
238 $output .= static::$itoa[($value >> 18) & 0x3f];
239 }
240 } while ($ictr < $count);
241 return $output;
242 }
243
244 }
245
246 PHPASS::init();