[SPIP] +2.1.12
[velocampus/web/www.git] / www / ecrire / auth / sha256.inc.php
1 <?php
2 /*
3 * Transparent SHA-256 Implementation for PHP 4 and PHP 5
4 *
5 * Author: Perry McGee (pmcgee@nanolink.ca)
6 * Website: http://www.nanolink.ca/pub/sha256
7 *
8 * Copyright (C) 2006,2007,2008,2009 Nanolink Solutions
9 *
10 * Created: Feb 11, 2006
11 *
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
16 *
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
21
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 * or see <http://www.gnu.org/licenses/>.
26 *
27 * Include:
28 *
29 * require_once("[path/]sha256.inc.php");
30 *
31 * Usage Options:
32 *
33 * 1) $shaStr = hash('sha256', $string_to_hash);
34 *
35 * 2) $shaStr = sha256($string_to_hash[, bool ignore_php5_hash = false]);
36 *
37 * 3) $obj = new nanoSha2([bool $upper_case_output = false]);
38 * $shaStr = $obj->hash($string_to_hash[, bool $ignore_php5_hash = false]);
39 *
40 * Reference: http://csrc.nist.gov/groups/ST/toolkit/secure_hashing.html
41 *
42 * 2007-12-13: Cleaned up for initial public release
43 * 2008-05-10: Moved all helper functions into a class. API access unchanged.
44 * 2009-06-23: Created abstraction of hash() routine
45 * 2009-07-23: Added detection of 32 vs 64bit platform, and patches.
46 * Ability to define "_NANO_SHA2_UPPER" to yeild upper case hashes.
47 * 2009-08-01: Added ability to attempt to use mhash() prior to running pure
48 * php code.
49 *
50 * 2010-06-10: Added support for 16bytes char and utf8 in string
51 *
52 * NOTE: Some sporadic versions of PHP do not handle integer overflows the
53 * same as the majority of builds. If you get hash results of:
54 * 7fffffff7fffffff7fffffff7fffffff7fffffff7fffffff7fffffff7fffffff
55 *
56 * If you do not have permissions to change PHP versions (if you did
57 * you'd probably upgrade to PHP 5 anyway) it is advised you install a
58 * module that will allow you to use their hashing routines, examples are:
59 * - mhash module : http://ca3.php.net/mhash
60 * - Suhosin : http://www.hardened-php.net/suhosin/
61 *
62 * If you install the Suhosin module, this script will transparently
63 * use their routine and define the PHP routine as _nano_sha256().
64 *
65 * If the mhash module is present, and $ignore_php5_hash = false the
66 * script will attempt to use the output from mhash prior to running
67 * the PHP code.
68 */
69 if (!class_exists('nanoSha2'))
70 {
71 class nanoSha2
72 {
73 // php 4 - 5 compatable class properties
74 var $toUpper;
75 var $platform;
76 var $bytesString = 16;
77
78 // Php 4 - 6 compatable constructor
79 function nanoSha2($toUpper = false) {
80 // Determine if the caller wants upper case or not.
81 $this->toUpper = is_bool($toUpper)
82 ? $toUpper
83 : ((defined('_NANO_SHA2_UPPER')) ? true : false);
84
85 // Deteremine if the system is 32 or 64 bit.
86 $tmpInt = (int)4294967295;
87 $this->platform = ($tmpInt > 0) ? 64 : 32;
88 }
89
90 // Here are the bitwise and functions as defined in FIPS180-2 Standard
91 function addmod2n($x, $y, $n = 4294967296) // Z = (X + Y) mod 2^32
92 {
93 $mask = 0x80000000;
94
95 if ($x < 0) {
96 $x &= 0x7FFFFFFF;
97 $x = (float)$x + $mask;
98 }
99
100 if ($y < 0) {
101 $y &= 0x7FFFFFFF;
102 $y = (float)$y + $mask;
103 }
104
105 $r = $x + $y;
106
107 if ($r >= $n) {
108 while ($r >= $n) {
109 $r -= $n;
110 }
111 }
112
113 return (int)$r;
114 }
115
116 // Logical bitwise right shift (PHP default is arithmetic shift)
117 function SHR($x, $n) // x >> n
118 {
119 if ($n >= 32) { // impose some limits to keep it 32-bit
120 return (int)0;
121 }
122
123 if ($n <= 0) {
124 return (int)$x;
125 }
126
127 $mask = 0x40000000;
128
129 if ($x < 0) {
130 $x &= 0x7FFFFFFF;
131 $mask = $mask >> ($n-1);
132 return ($x >> $n) | $mask;
133 }
134
135 return (int)$x >> (int)$n;
136 }
137
138 function ROTR($x, $n) { return (int)(($this->SHR($x, $n) | ($x << (32-$n)) & 0xFFFFFFFF)); }
139 function Ch($x, $y, $z) { return ($x & $y) ^ ((~$x) & $z); }
140 function Maj($x, $y, $z) { return ($x & $y) ^ ($x & $z) ^ ($y & $z); }
141 function Sigma0($x) { return (int) ($this->ROTR($x, 2)^$this->ROTR($x, 13)^$this->ROTR($x, 22)); }
142 function Sigma1($x) { return (int) ($this->ROTR($x, 6)^$this->ROTR($x, 11)^$this->ROTR($x, 25)); }
143 function sigma_0($x) { return (int) ($this->ROTR($x, 7)^$this->ROTR($x, 18)^$this->SHR($x, 3)); }
144 function sigma_1($x) { return (int) ($this->ROTR($x, 17)^$this->ROTR($x, 19)^$this->SHR($x, 10)); }
145
146
147 function string2ordUTF8($s,&$byteSize){
148 $chars = array();
149 // par defaut sur 8bits
150 $byteSize = 8;
151 $i = 0;
152 while ($i<strlen($s)){
153 $chars[] = $this->ordUTF8($s, $i, $bytes);
154 $i+=$bytes;
155 // mais si un char necessite 16bits, on passe tout sur 16
156 // sinon on ne concorde pas avec le lecture de la chaine en js
157 // et le sha256 js
158 if ($bytes>1) $byteSize = 16;
159 }
160 return $chars;
161 }
162
163 function ordUTF8($c, $index = 0, &$bytes)
164 {
165 $len = strlen($c);
166 $bytes = 0;
167
168 if ($index >= $len)
169 return false;
170
171 $h = ord($c{$index});
172
173 if ($h <= 0x7F) {
174 $bytes = 1;
175 return $h;
176 }
177 else if ($h < 0xC2){
178 // pas utf mais renvoyer quand meme ce qu'on a
179 $bytes = 1;
180 return $h;
181 }
182 else if ($h <= 0xDF && $index < $len - 1) {
183 $bytes = 2;
184 return ($h & 0x1F) << 6 | (ord($c{$index + 1}) & 0x3F);
185 }
186 else if ($h <= 0xEF && $index < $len - 2) {
187 $bytes = 3;
188 return ($h & 0x0F) << 12 | (ord($c{$index + 1}) & 0x3F) << 6
189 | (ord($c{$index + 2}) & 0x3F);
190 }
191 else if ($h <= 0xF4 && $index < $len - 3) {
192 $bytes = 4;
193 return ($h & 0x0F) << 18 | (ord($c{$index + 1}) & 0x3F) << 12
194 | (ord($c{$index + 2}) & 0x3F) << 6
195 | (ord($c{$index + 3}) & 0x3F);
196 }
197 else {
198 // pas utf mais renvoyer quand meme ce qu'on a
199 $bytes = 1;
200 return $h;
201 }
202 }
203
204 function string2binint ($str,$npad=512) {
205 $bin = array();
206 $ords = $this->string2ordUTF8($str,$this->bytesString);
207 $npad = $npad/$this->bytesString;
208 $length = count($ords);
209 $ords[] = 0x80; // append the "1" bit followed by 7 0's
210 $ords = array_pad($ords,ceil(($length+32/$this->bytesString)/$npad)*$npad-32/$this->bytesString,0);
211 $mask = (1 << $this->bytesString) - 1;
212 for($i = 0; $i < count($ords) * $this->bytesString; $i += $this->bytesString)
213 $bin[$i>>5] |= ($ords[$i / $this->bytesString] & $mask) << (24 - $i%32);
214 $bin[] = $length*$this->bytesString;
215 return $bin;
216 }
217
218 function array_split($a, $n) {
219 $split = array();
220 while (count($a)>$n) {
221 $s = array();
222 for($i = 0;$i<$n;$i++)
223 $s[] = array_shift($a);
224 $split[] = $s;
225 }
226 if (count($a)){
227 $a = array_pad($a,$n,0);
228 $split[] = $a;
229 }
230 return $split;
231 }
232
233 /**
234 * Process and return the hash.
235 *
236 * @param $str Input string to hash
237 * @param $ig_func Option param to ignore checking for php > 5.1.2
238 * @return string Hexadecimal representation of the message digest
239 */
240 function hash($str, $ig_func = true)
241 {
242 unset($binStr); // binary representation of input string
243 unset($hexStr); // 256-bit message digest in readable hex format
244
245 // check for php's internal sha256 function, ignore if ig_func==true
246 if ($ig_func == false) {
247 if (version_compare(PHP_VERSION,'5.1.2','>=') AND !defined('_NO_HASH_DEFINED')) {
248 return hash("sha256", $str, false);
249 } else if (function_exists('mhash') && defined('MHASH_SHA256')) {
250 return base64_encode(bin2hex(mhash(MHASH_SHA256, $str)));
251 }
252 }
253
254 /*
255 * SHA-256 Constants
256 * Sequence of sixty-four constant 32-bit words representing the
257 * first thirty-two bits of the fractional parts of the cube roots
258 * of the first sixtyfour prime numbers.
259 */
260 $K = array((int)0x428a2f98, (int)0x71374491, (int)0xb5c0fbcf,
261 (int)0xe9b5dba5, (int)0x3956c25b, (int)0x59f111f1,
262 (int)0x923f82a4, (int)0xab1c5ed5, (int)0xd807aa98,
263 (int)0x12835b01, (int)0x243185be, (int)0x550c7dc3,
264 (int)0x72be5d74, (int)0x80deb1fe, (int)0x9bdc06a7,
265 (int)0xc19bf174, (int)0xe49b69c1, (int)0xefbe4786,
266 (int)0x0fc19dc6, (int)0x240ca1cc, (int)0x2de92c6f,
267 (int)0x4a7484aa, (int)0x5cb0a9dc, (int)0x76f988da,
268 (int)0x983e5152, (int)0xa831c66d, (int)0xb00327c8,
269 (int)0xbf597fc7, (int)0xc6e00bf3, (int)0xd5a79147,
270 (int)0x06ca6351, (int)0x14292967, (int)0x27b70a85,
271 (int)0x2e1b2138, (int)0x4d2c6dfc, (int)0x53380d13,
272 (int)0x650a7354, (int)0x766a0abb, (int)0x81c2c92e,
273 (int)0x92722c85, (int)0xa2bfe8a1, (int)0xa81a664b,
274 (int)0xc24b8b70, (int)0xc76c51a3, (int)0xd192e819,
275 (int)0xd6990624, (int)0xf40e3585, (int)0x106aa070,
276 (int)0x19a4c116, (int)0x1e376c08, (int)0x2748774c,
277 (int)0x34b0bcb5, (int)0x391c0cb3, (int)0x4ed8aa4a,
278 (int)0x5b9cca4f, (int)0x682e6ff3, (int)0x748f82ee,
279 (int)0x78a5636f, (int)0x84c87814, (int)0x8cc70208,
280 (int)0x90befffa, (int)0xa4506ceb, (int)0xbef9a3f7,
281 (int)0xc67178f2);
282
283 // Pre-processing: Padding the string
284 $binStr = $this->string2binint($str,512);
285
286 // Parsing the Padded Message (Break into N 512-bit blocks)
287 $M = $this->array_split($binStr, 16);
288
289 // Set the initial hash values
290 $h[0] = (int)0x6a09e667;
291 $h[1] = (int)0xbb67ae85;
292 $h[2] = (int)0x3c6ef372;
293 $h[3] = (int)0xa54ff53a;
294 $h[4] = (int)0x510e527f;
295 $h[5] = (int)0x9b05688c;
296 $h[6] = (int)0x1f83d9ab;
297 $h[7] = (int)0x5be0cd19;
298
299 // loop through message blocks and compute hash. ( For i=1 to N : )
300 $N = count($M);
301 for ($i = 0; $i < $N; $i++)
302 {
303 // Break input block into 16 32bit words (message schedule prep)
304 $MI = $M[$i];
305
306 // Initialize working variables
307 $_a = (int)$h[0];
308 $_b = (int)$h[1];
309 $_c = (int)$h[2];
310 $_d = (int)$h[3];
311 $_e = (int)$h[4];
312 $_f = (int)$h[5];
313 $_g = (int)$h[6];
314 $_h = (int)$h[7];
315 unset($_s0);
316 unset($_s1);
317 unset($_T1);
318 unset($_T2);
319 $W = array();
320
321 // Compute the hash and update
322 for ($t = 0; $t < 16; $t++)
323 {
324 // Prepare the first 16 message schedule values as we loop
325 $W[$t] = $MI[$t];
326
327 // Compute hash
328 $_T1 = $this->addmod2n($this->addmod2n($this->addmod2n($this->addmod2n($_h, $this->Sigma1($_e)), $this->Ch($_e, $_f, $_g)), $K[$t]), $W[$t]);
329 $_T2 = $this->addmod2n($this->Sigma0($_a), $this->Maj($_a, $_b, $_c));
330
331 // Update working variables
332 $_h = $_g; $_g = $_f; $_f = $_e; $_e = $this->addmod2n($_d, $_T1);
333 $_d = $_c; $_c = $_b; $_b = $_a; $_a = $this->addmod2n($_T1, $_T2);
334 }
335
336 for (; $t < 64; $t++)
337 {
338 // Continue building the message schedule as we loop
339 $_s0 = $W[($t+1)&0x0F];
340 $_s0 = $this->sigma_0($_s0);
341 $_s1 = $W[($t+14)&0x0F];
342 $_s1 = $this->sigma_1($_s1);
343
344 $W[$t&0xF] = $this->addmod2n($this->addmod2n($this->addmod2n($W[$t&0xF], $_s0), $_s1), $W[($t+9)&0x0F]);
345
346 // Compute hash
347 $_T1 = $this->addmod2n($this->addmod2n($this->addmod2n($this->addmod2n($_h, $this->Sigma1($_e)), $this->Ch($_e, $_f, $_g)), $K[$t]), $W[$t&0xF]);
348 $_T2 = $this->addmod2n($this->Sigma0($_a), $this->Maj($_a, $_b, $_c));
349
350 // Update working variables
351 $_h = $_g; $_g = $_f; $_f = $_e; $_e = $this->addmod2n($_d, $_T1);
352 $_d = $_c; $_c = $_b; $_b = $_a; $_a = $this->addmod2n($_T1, $_T2);
353 }
354
355 $h[0] = $this->addmod2n($h[0], $_a);
356 $h[1] = $this->addmod2n($h[1], $_b);
357 $h[2] = $this->addmod2n($h[2], $_c);
358 $h[3] = $this->addmod2n($h[3], $_d);
359 $h[4] = $this->addmod2n($h[4], $_e);
360 $h[5] = $this->addmod2n($h[5], $_f);
361 $h[6] = $this->addmod2n($h[6], $_g);
362 $h[7] = $this->addmod2n($h[7], $_h);
363 }
364
365 // Convert the 32-bit words into human readable hexadecimal format.
366 $hexStr = sprintf("%08x%08x%08x%08x%08x%08x%08x%08x", $h[0], $h[1], $h[2], $h[3], $h[4], $h[5], $h[6], $h[7]);
367
368 return ($this->toUpper) ? strtoupper($hexStr) : $hexStr;
369 }
370
371 }
372 }
373
374 if (!function_exists('str_split'))
375 {
376 /**
377 * Splits a string into an array of strings with specified length.
378 * Compatability with older verions of PHP
379 */
380 function str_split($string, $split_length = 1)
381 {
382 $sign = ($split_length < 0) ? -1 : 1;
383 $strlen = strlen($string);
384 $split_length = abs($split_length);
385
386 if (($split_length == 0) || ($strlen == 0)) {
387 $result = false;
388 } elseif ($split_length >= $strlen) {
389 $result[] = $string;
390 } else {
391 $length = $split_length;
392
393 for ($i = 0; $i < $strlen; $i++)
394 {
395 $i = (($sign < 0) ? $i + $length : $i);
396 $result[] = substr($string, $sign*$i, $length);
397 $i--;
398 $i = (($sign < 0) ? $i : $i + $length);
399
400 $length = (($i + $split_length) > $strlen)
401 ? ($strlen - ($i + 1))
402 : $split_length;
403 }
404 }
405
406 return $result;
407 }
408 }
409
410 /**
411 * Main routine called from an application using this include.
412 *
413 * General usage:
414 * require_once('sha256.inc.php');
415 * $hashstr = sha256('abc');
416 *
417 * Note:
418 * PHP Strings are limitd to (2^31)-1, so it is not worth it to
419 * check for input strings > 2^64 as the FIPS180-2 defines.
420 */
421 function _nano_sha256($str, $ig_func = true) {
422 $obj = new nanoSha2((defined('_NANO_SHA2_UPPER')) ? true : false);
423 return $obj->hash($str, $ig_func);
424 }
425 // 2009-07-23: Added check for function as the Suhosin plugin adds this routine.
426 if (!function_exists('sha256')) {
427 function sha256($str, $ig_func = true) { return _nano_sha256($str, $ig_func); }
428 }
429
430 // support to give php4 the hash() routine which abstracts this code.
431 if (!function_exists('hash'))
432 {
433 define('_NO_HASH_DEFINED',true);
434 function hash($algo, $data)
435 {
436 if (empty($algo) || !is_string($algo) || !is_string($data)) {
437 return false;
438 }
439
440 if (function_exists($algo)) {
441 return $algo($data);
442 }
443 }
444 }
445
446 ?>