blob: 15954559ca2470ad09cff3fe5e8e1f49b19fb8ad [file] [log] [blame]
Andrey Andreev9a152a92014-02-18 16:29:53 +02001<?php
2/**
3 * CodeIgniter
4 *
Andrey Andreevfe9309d2015-01-09 17:48:58 +02005 * An open source application development framework for PHP
Andrey Andreev9a152a92014-02-18 16:29:53 +02006 *
Andrey Andreevbdb96ca2014-10-28 00:13:31 +02007 * This content is released under the MIT License (MIT)
Andrey Andreev9a152a92014-02-18 16:29:53 +02008 *
Andrey Andreevfe9309d2015-01-09 17:48:58 +02009 * Copyright (c) 2014 - 2015, British Columbia Institute of Technology
Andrey Andreev9a152a92014-02-18 16:29:53 +020010 *
Andrey Andreevbdb96ca2014-10-28 00:13:31 +020011 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
Andrey Andreev9a152a92014-02-18 16:29:53 +020017 *
Andrey Andreevbdb96ca2014-10-28 00:13:31 +020018 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 * THE SOFTWARE.
28 *
29 * @package CodeIgniter
30 * @author EllisLab Dev Team
Andrey Andreev9a152a92014-02-18 16:29:53 +020031 * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
Andrey Andreevfe9309d2015-01-09 17:48:58 +020032 * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
Andrey Andreevbdb96ca2014-10-28 00:13:31 +020033 * @license http://opensource.org/licenses/MIT MIT License
34 * @link http://codeigniter.com
35 * @since Version 3.0.0
Andrey Andreev9a152a92014-02-18 16:29:53 +020036 * @filesource
37 */
38defined('BASEPATH') OR exit('No direct script access allowed');
39
40/**
41 * PHP ext/hash compatibility package
42 *
43 * @package CodeIgniter
44 * @subpackage CodeIgniter
45 * @category Compatibility
46 * @author Andrey Andreev
47 * @link http://codeigniter.com/user_guide/
48 * @link http://php.net/hash
49 */
50
51// ------------------------------------------------------------------------
52
Andrey Andreeva5621b82014-05-09 11:23:08 +030053if (is_php('5.6'))
54{
55 return;
56}
57
58// ------------------------------------------------------------------------
59
60if ( ! function_exists('hash_equals'))
61{
62 /**
63 * hash_equals()
64 *
65 * @link http://php.net/hash_equals
66 * @param string $known_string
67 * @param string $user_string
68 * @return bool
69 */
70 function hash_equals($known_string, $user_string)
71 {
72 if ( ! is_string($known_string))
73 {
74 trigger_error('hash_equals(): Expected known_string to be a string, '.strtolower(gettype($known_string)).' given', E_USER_WARNING);
75 return FALSE;
76 }
77 elseif ( ! is_string($user_string))
78 {
79 trigger_error('hash_equals(): Expected user_string to be a string, '.strtolower(gettype($user_string)).' given', E_USER_WARNING);
80 return FALSE;
81 }
82 elseif (($length = strlen($known_string)) !== strlen($user_string))
83 {
84 return FALSE;
85 }
86
87 $diff = 0;
88 for ($i = 0; $i < $length; $i++)
89 {
90 $diff |= ord($known_string[$i]) ^ ord($user_string[$i]);
91 }
92
93 return ($diff === 0);
94 }
95}
96
97// ------------------------------------------------------------------------
98
Andrey Andreev9a152a92014-02-18 16:29:53 +020099if (is_php('5.5'))
100{
101 return;
102}
103
104// ------------------------------------------------------------------------
105
106if ( ! function_exists('hash_pbkdf2'))
107{
108 /**
109 * hash_pbkdf2()
110 *
111 * @link http://php.net/hash_pbkdf2
112 * @param string $algo
113 * @param string $password
114 * @param string $salt
115 * @param int $iterations
116 * @param int $length
117 * @param bool $raw_output
118 * @return string
119 */
120 function hash_pbkdf2($algo, $password, $salt, $iterations, $length = 0, $raw_output = FALSE)
121 {
122 if ( ! in_array($algo, hash_algos(), TRUE))
123 {
124 trigger_error('hash_pbkdf2(): Unknown hashing algorithm: '.$algo, E_USER_WARNING);
125 return FALSE;
126 }
127
128 if (($type = gettype($iterations)) !== 'integer')
129 {
130 if ($type === 'object' && method_exists($iterations, '__toString'))
131 {
132 $iterations = (string) $iterations;
133 }
134
135 if (is_string($iterations) && is_numeric($iterations))
136 {
137 $iterations = (int) $iterations;
138 }
139 else
140 {
141 trigger_error('hash_pbkdf2() expects parameter 4 to be long, '.$type.' given', E_USER_WARNING);
142 return NULL;
143 }
144 }
145
146 if ($iterations < 1)
147 {
148 trigger_error('hash_pbkdf2(): Iterations must be a positive integer: '.$iterations, E_USER_WARNING);
149 return FALSE;
150 }
151
152 if (($type = gettype($length)) !== 'integer')
153 {
154 if ($type === 'object' && method_exists($length, '__toString'))
155 {
156 $length = (string) $length;
157 }
158
159 if (is_string($length) && is_numeric($length))
160 {
161 $length = (int) $length;
162 }
163 else
164 {
165 trigger_error('hash_pbkdf2() expects parameter 5 to be long, '.$type.' given', E_USER_WARNING);
166 return NULL;
167 }
168 }
169
170 if ($length < 0)
171 {
172 trigger_error('hash_pbkdf2(): Length must be greater than or equal to 0: '.$length, E_USER_WARNING);
173 return FALSE;
174 }
175
176 $hash_length = strlen(hash($algo, NULL, TRUE));
Andrey Andreev68bad622015-04-01 14:51:25 +0300177 empty($length) && $length = $hash_length;
178
179 // Pre-hash password inputs longer than the algorithm's block size
180 // (i.e. prepare HMAC key) to mitigate potential DoS attacks.
181 static $block_sizes;
182 empty($block_sizes) && $block_sizes = array(
183 'gost' => 32,
184 'haval128,3' => 128,
185 'haval160,3' => 128,
186 'haval192,3' => 128,
187 'haval224,3' => 128,
188 'haval256,3' => 128,
189 'haval128,4' => 128,
190 'haval160,4' => 128,
191 'haval192,4' => 128,
192 'haval224,4' => 128,
193 'haval256,4' => 128,
194 'haval128,5' => 128,
195 'haval160,5' => 128,
196 'haval192,5' => 128,
197 'haval224,5' => 128,
198 'haval256,5' => 128,
199 'md2' => 16,
200 'md4' => 64,
201 'md5' => 64,
202 'ripemd128' => 64,
203 'ripemd160' => 64,
204 'ripemd256' => 64,
205 'ripemd320' => 64,
206 'salsa10' => 64,
207 'salsa20' => 64,
208 'sha1' => 64,
209 'sha224' => 64,
210 'sha256' => 64,
211 'sha384' => 128,
212 'sha512' => 128,
213 'snefru' => 32,
214 'snefru256' => 32,
215 'tiger128,3' => 64,
216 'tiger160,3' => 64,
217 'tiger192,3' => 64,
218 'tiger128,4' => 64,
219 'tiger160,4' => 64,
220 'tiger192,4' => 64,
221 'whirlpool' => 64
222 );
223
224 if (isset($block_sizes[$algo]) && strlen($password) > $block_sizes[$algo])
Andrey Andreev9a152a92014-02-18 16:29:53 +0200225 {
Andrey Andreev68bad622015-04-01 14:51:25 +0300226 $password = hash($algo, $password, TRUE);
Andrey Andreev9a152a92014-02-18 16:29:53 +0200227 }
228
229 $hash = '';
230 // Note: Blocks are NOT 0-indexed
231 for ($bc = ceil($length / $hash_length), $bi = 1; $bi <= $bc; $bi++)
232 {
233 $key = $derived_key = hash_hmac($algo, $salt.pack('N', $bi), $password, TRUE);
234 for ($i = 1; $i < $iterations; $i++)
235 {
236 $derived_key ^= $key = hash_hmac($algo, $key, $password, TRUE);
237 }
238
239 $hash .= $derived_key;
240 }
241
242 // This is not RFC-compatible, but we're aiming for natural PHP compatibility
243 return substr($raw_output ? $hash : bin2hex($hash), 0, $length);
244 }
245}