[SPIP][PLUGINS] v3.0-->v3.2
[lhc/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 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 * or see <http://www.gnu.org/licenses/>.
25 *
26 * Include:
27 *
28 * require_once("[path/]sha256.inc.php");
29 *
30 * Usage Options:
31 *
32 * 1) $shaStr = hash('sha256', $string_to_hash);
33 *
34 * 2) $shaStr = sha256($string_to_hash[, bool ignore_php5_hash = false]);
35 *
36 * 3) $obj = new nanoSha2([bool $upper_case_output = false]);
37 * $shaStr = $obj->hash($string_to_hash[, bool $ignore_php5_hash = false]);
38 *
39 * Reference: http://csrc.nist.gov/groups/ST/toolkit/secure_hashing.html
40 *
41 * 2007-12-13: Cleaned up for initial public release
42 * 2008-05-10: Moved all helper functions into a class. API access unchanged.
43 * 2009-06-23: Created abstraction of hash() routine
44 * 2009-07-23: Added detection of 32 vs 64bit platform, and patches.
45 * Ability to define "_NANO_SHA2_UPPER" to yeild upper case hashes.
46 * 2009-08-01: Added ability to attempt to use mhash() prior to running pure
47 * php code.
48 *
49 * 2010-06-10: Added support for 16bytes char and utf8 in string
50 *
51 * NOTE: Some sporadic versions of PHP do not handle integer overflows the
52 * same as the majority of builds. If you get hash results of:
53 * 7fffffff7fffffff7fffffff7fffffff7fffffff7fffffff7fffffff7fffffff
54 *
55 * If you do not have permissions to change PHP versions (if you did
56 * you'd probably upgrade to PHP 5 anyway) it is advised you install a
57 * module that will allow you to use their hashing routines, examples are:
58 * - mhash module : http://ca3.php.net/mhash
59 * - Suhosin : http://www.hardened-php.net/suhosin/
60 *
61 * If you install the Suhosin module, this script will transparently
62 * use their routine and define the PHP routine as _nano_sha256().
63 *
64 * If the mhash module is present, and $ignore_php5_hash = false the
65 * script will attempt to use the output from mhash prior to running
66 * the PHP code.
67 *
68 * @package SPIP\Core\Authentification\Sha256
69 */
70 if (!class_exists('nanoSha2')) {
71 /**
72 * Classe de calcul d'un SHA
73 */
74 class nanoSha2 {
75 // php 4 - 5 compatable class properties
76 /** Le résultat doit être passé en majuscule ?
77 *
78 * @var bool
79 */
80 var $toUpper;
81 /** 32 ou 64 bits ?
82 *
83 * @var int
84 */
85 var $platform;
86 /** bytes par caractères */
87 var $bytesString = 16;
88
89 /**
90 * Constructor
91 *
92 * @param bool $toUpper
93 */
94 function __construct($toUpper = false) {
95 // Determine if the caller wants upper case or not.
96 $this->toUpper = is_bool($toUpper)
97 ? $toUpper
98 : ((defined('_NANO_SHA2_UPPER')) ? true : false);
99
100 // Deteremine if the system is 32 or 64 bit.
101 $tmpInt = (int)4294967295;
102 $this->platform = ($tmpInt > 0) ? 64 : 32;
103 }
104
105 /**
106 * Here are the bitwise and functions as defined in FIPS180-2 Standard
107 *
108 * @param int $x
109 * @param int $y
110 * @param int $n
111 * @return int
112 */
113 function addmod2n($x, $y, $n = 4294967296) // Z = (X + Y) mod 2^32
114 {
115 $mask = 0x80000000;
116
117 if ($x < 0) {
118 $x &= 0x7FFFFFFF;
119 $x = (float)$x+$mask;
120 }
121
122 if ($y < 0) {
123 $y &= 0x7FFFFFFF;
124 $y = (float)$y+$mask;
125 }
126
127 $r = $x+$y;
128
129 if ($r >= $n) {
130 while ($r >= $n) {
131 $r -= $n;
132 }
133 }
134
135 return (int)$r;
136 }
137
138 /**
139 * Logical bitwise right shift (PHP default is arithmetic shift)
140 *
141 * @param int $x
142 * @param int $n
143 * return int
144 */
145 function SHR($x, $n) // x >> n
146 {
147 if ($n >= 32) { // impose some limits to keep it 32-bit
148 return (int)0;
149 }
150
151 if ($n <= 0) {
152 return (int)$x;
153 }
154
155 $mask = 0x40000000;
156
157 if ($x < 0) {
158 $x &= 0x7FFFFFFF;
159 $mask = $mask >> ($n-1);
160
161 return ($x >> $n) | $mask;
162 }
163
164 return (int)$x >> (int)$n;
165 }
166
167 /** ROTR
168 *
169 * @param int $x
170 * @param int $n
171 * @return int
172 */
173 function ROTR($x, $n) { return (int)(($this->SHR($x, $n) | ($x << (32-$n)) & 0xFFFFFFFF)); }
174
175 /** Ch
176 *
177 * @param int $x
178 * @param int $y
179 * @param int $z
180 * @return int
181 */
182 function Ch($x, $y, $z) { return ($x & $y) ^ ((~$x) & $z); }
183
184 /** Maj
185 *
186 * @param int $x
187 * @param int $y
188 * @param int $z
189 * @return int
190 */
191 function Maj($x, $y, $z) { return ($x & $y) ^ ($x & $z) ^ ($y & $z); }
192
193 /** Sigma0
194 *
195 * @param int $x
196 * @return int
197 */
198 function Sigma0($x) { return (int)($this->ROTR($x, 2) ^ $this->ROTR($x, 13) ^ $this->ROTR($x, 22)); }
199
200 /** Sigma1
201 *
202 * @param int $x
203 * @return int
204 */
205 function Sigma1($x) { return (int)($this->ROTR($x, 6) ^ $this->ROTR($x, 11) ^ $this->ROTR($x, 25)); }
206
207 /** Sigma_0
208 *
209 * @param int $x
210 * @return int
211 */
212 function sigma_0($x) { return (int)($this->ROTR($x, 7) ^ $this->ROTR($x, 18) ^ $this->SHR($x, 3)); }
213
214 /** Sigma_1
215 *
216 * @param int $x
217 * @return int
218 */
219 function sigma_1($x) { return (int)($this->ROTR($x, 17) ^ $this->ROTR($x, 19) ^ $this->SHR($x, 10)); }
220
221 /** String 2 ord UTF8
222 *
223 * @param string $s
224 * @param int $byteSize
225 * @return array
226 **/
227 function string2ordUTF8($s, &$byteSize) {
228 $chars = array();
229 // par defaut sur 8bits
230 $byteSize = 8;
231 $i = 0;
232 while ($i < strlen($s)) {
233 $chars[] = $this->ordUTF8($s, $i, $bytes);
234 $i += $bytes;
235 // mais si un char necessite 16bits, on passe tout sur 16
236 // sinon on ne concorde pas avec le lecture de la chaine en js
237 // et le sha256 js
238 if ($bytes > 1) {
239 $byteSize = 16;
240 }
241 }
242
243 return $chars;
244 }
245
246 /** Ord UTF8
247 *
248 * @param string $c
249 * @param int $index
250 * @param int $bytes
251 * @return unknown
252 **/
253 function ordUTF8($c, $index = 0, &$bytes) {
254 $len = strlen($c);
255 $bytes = 0;
256
257 if ($index >= $len) {
258 return false;
259 }
260
261 $h = ord($c{$index});
262
263 if ($h <= 0x7F) {
264 $bytes = 1;
265
266 return $h;
267 } else {
268 if ($h < 0xC2) {
269 // pas utf mais renvoyer quand meme ce qu'on a
270 $bytes = 1;
271
272 return $h;
273 } else {
274 if ($h <= 0xDF && $index < $len-1) {
275 $bytes = 2;
276
277 return ($h & 0x1F) << 6 | (ord($c{$index+1}) & 0x3F);
278 } else {
279 if ($h <= 0xEF && $index < $len-2) {
280 $bytes = 3;
281
282 return ($h & 0x0F) << 12 | (ord($c{$index+1}) & 0x3F) << 6
283 | (ord($c{$index+2}) & 0x3F);
284 } else {
285 if ($h <= 0xF4 && $index < $len-3) {
286 $bytes = 4;
287
288 return ($h & 0x0F) << 18 | (ord($c{$index+1}) & 0x3F) << 12
289 | (ord($c{$index+2}) & 0x3F) << 6
290 | (ord($c{$index+3}) & 0x3F);
291 } else {
292 // pas utf mais renvoyer quand meme ce qu'on a
293 $bytes = 1;
294
295 return $h;
296 }
297 }
298 }
299 }
300 }
301 }
302
303 /** String 2 bin int
304 *
305 * @param string $str
306 * @param int $npad
307 * @return int[]
308 **/
309 function string2binint($str, $npad = 512) {
310 $bin = array();
311 $ords = $this->string2ordUTF8($str, $this->bytesString);
312 $npad = $npad/$this->bytesString;
313 $length = count($ords);
314 $ords[] = 0x80; // append the "1" bit followed by 7 0's
315 $pad = ceil(($length+1+32/$this->bytesString)/$npad)*$npad-32/$this->bytesString;
316 $ords = array_pad($ords, $pad, 0);
317 $mask = (1 << $this->bytesString)-1;
318 for ($i = 0; $i < count($ords)*$this->bytesString; $i += $this->bytesString) {
319 if (!isset($bin[$i >> 5])) {
320 $bin[$i >> 5] = 0;
321 } // pour eviter des notices.
322 $bin[$i >> 5] |= ($ords[$i/$this->bytesString] & $mask) << (24-$i%32);
323 }
324 $bin[] = $length*$this->bytesString;
325
326 return $bin;
327 }
328
329 /** Array split
330 *
331 * @param array $a
332 * @param int $n
333 * @return array
334 **/
335 function array_split($a, $n) {
336 $split = array();
337 while (count($a) > $n) {
338 $s = array();
339 for ($i = 0; $i < $n; $i++) {
340 $s[] = array_shift($a);
341 }
342 $split[] = $s;
343 }
344 if (count($a)) {
345 $a = array_pad($a, $n, 0);
346 $split[] = $a;
347 }
348
349 return $split;
350 }
351
352 /**
353 * Process and return the hash.
354 *
355 * @param $str Input string to hash
356 * @param $ig_func Option param to ignore checking for php > 5.1.2
357 * @return string Hexadecimal representation of the message digest
358 */
359 function hash($str, $ig_func = true) {
360 unset($binStr); // binary representation of input string
361 unset($hexStr); // 256-bit message digest in readable hex format
362
363 // check for php's internal sha256 function, ignore if ig_func==true
364 if ($ig_func == false) {
365 if (version_compare(PHP_VERSION, '5.1.2', '>=') AND !defined('_NO_HASH_DEFINED')) {
366 return hash("sha256", $str, false);
367 } else {
368 if (function_exists('mhash') && defined('MHASH_SHA256')) {
369 return base64_encode(bin2hex(mhash(MHASH_SHA256, $str)));
370 }
371 }
372 }
373
374 /*
375 * SHA-256 Constants
376 * Sequence of sixty-four constant 32-bit words representing the
377 * first thirty-two bits of the fractional parts of the cube roots
378 * of the first sixtyfour prime numbers.
379 */
380 $K = array(
381 (int)0x428a2f98,
382 (int)0x71374491,
383 (int)0xb5c0fbcf,
384 (int)0xe9b5dba5,
385 (int)0x3956c25b,
386 (int)0x59f111f1,
387 (int)0x923f82a4,
388 (int)0xab1c5ed5,
389 (int)0xd807aa98,
390 (int)0x12835b01,
391 (int)0x243185be,
392 (int)0x550c7dc3,
393 (int)0x72be5d74,
394 (int)0x80deb1fe,
395 (int)0x9bdc06a7,
396 (int)0xc19bf174,
397 (int)0xe49b69c1,
398 (int)0xefbe4786,
399 (int)0x0fc19dc6,
400 (int)0x240ca1cc,
401 (int)0x2de92c6f,
402 (int)0x4a7484aa,
403 (int)0x5cb0a9dc,
404 (int)0x76f988da,
405 (int)0x983e5152,
406 (int)0xa831c66d,
407 (int)0xb00327c8,
408 (int)0xbf597fc7,
409 (int)0xc6e00bf3,
410 (int)0xd5a79147,
411 (int)0x06ca6351,
412 (int)0x14292967,
413 (int)0x27b70a85,
414 (int)0x2e1b2138,
415 (int)0x4d2c6dfc,
416 (int)0x53380d13,
417 (int)0x650a7354,
418 (int)0x766a0abb,
419 (int)0x81c2c92e,
420 (int)0x92722c85,
421 (int)0xa2bfe8a1,
422 (int)0xa81a664b,
423 (int)0xc24b8b70,
424 (int)0xc76c51a3,
425 (int)0xd192e819,
426 (int)0xd6990624,
427 (int)0xf40e3585,
428 (int)0x106aa070,
429 (int)0x19a4c116,
430 (int)0x1e376c08,
431 (int)0x2748774c,
432 (int)0x34b0bcb5,
433 (int)0x391c0cb3,
434 (int)0x4ed8aa4a,
435 (int)0x5b9cca4f,
436 (int)0x682e6ff3,
437 (int)0x748f82ee,
438 (int)0x78a5636f,
439 (int)0x84c87814,
440 (int)0x8cc70208,
441 (int)0x90befffa,
442 (int)0xa4506ceb,
443 (int)0xbef9a3f7,
444 (int)0xc67178f2
445 );
446
447 // Pre-processing: Padding the string
448 $binStr = $this->string2binint($str, 512);
449
450 // Parsing the Padded Message (Break into N 512-bit blocks)
451 $M = $this->array_split($binStr, 16);
452
453 // Set the initial hash values
454 $h[0] = (int)0x6a09e667;
455 $h[1] = (int)0xbb67ae85;
456 $h[2] = (int)0x3c6ef372;
457 $h[3] = (int)0xa54ff53a;
458 $h[4] = (int)0x510e527f;
459 $h[5] = (int)0x9b05688c;
460 $h[6] = (int)0x1f83d9ab;
461 $h[7] = (int)0x5be0cd19;
462
463 // loop through message blocks and compute hash. ( For i=1 to N : )
464 $N = count($M);
465 for ($i = 0; $i < $N; $i++) {
466 // Break input block into 16 32bit words (message schedule prep)
467 $MI = $M[$i];
468
469 // Initialize working variables
470 $_a = (int)$h[0];
471 $_b = (int)$h[1];
472 $_c = (int)$h[2];
473 $_d = (int)$h[3];
474 $_e = (int)$h[4];
475 $_f = (int)$h[5];
476 $_g = (int)$h[6];
477 $_h = (int)$h[7];
478 unset($_s0);
479 unset($_s1);
480 unset($_T1);
481 unset($_T2);
482 $W = array();
483
484 // Compute the hash and update
485 for ($t = 0; $t < 16; $t++) {
486 // Prepare the first 16 message schedule values as we loop
487 $W[$t] = $MI[$t];
488
489 // Compute hash
490 $_T1 = $this->addmod2n($this->addmod2n($this->addmod2n($this->addmod2n($_h, $this->Sigma1($_e)),
491 $this->Ch($_e, $_f, $_g)), $K[$t]), $W[$t]);
492 $_T2 = $this->addmod2n($this->Sigma0($_a), $this->Maj($_a, $_b, $_c));
493
494 // Update working variables
495 $_h = $_g;
496 $_g = $_f;
497 $_f = $_e;
498 $_e = $this->addmod2n($_d, $_T1);
499 $_d = $_c;
500 $_c = $_b;
501 $_b = $_a;
502 $_a = $this->addmod2n($_T1, $_T2);
503 }
504
505 for (; $t < 64; $t++) {
506 // Continue building the message schedule as we loop
507 $_s0 = $W[($t+1) & 0x0F];
508 $_s0 = $this->sigma_0($_s0);
509 $_s1 = $W[($t+14) & 0x0F];
510 $_s1 = $this->sigma_1($_s1);
511
512 $W[$t & 0xF] = $this->addmod2n($this->addmod2n($this->addmod2n($W[$t & 0xF], $_s0), $_s1), $W[($t+9) & 0x0F]);
513
514 // Compute hash
515 $_T1 = $this->addmod2n($this->addmod2n($this->addmod2n($this->addmod2n($_h, $this->Sigma1($_e)),
516 $this->Ch($_e, $_f, $_g)), $K[$t]), $W[$t & 0xF]);
517 $_T2 = $this->addmod2n($this->Sigma0($_a), $this->Maj($_a, $_b, $_c));
518
519 // Update working variables
520 $_h = $_g;
521 $_g = $_f;
522 $_f = $_e;
523 $_e = $this->addmod2n($_d, $_T1);
524 $_d = $_c;
525 $_c = $_b;
526 $_b = $_a;
527 $_a = $this->addmod2n($_T1, $_T2);
528 }
529
530 $h[0] = $this->addmod2n($h[0], $_a);
531 $h[1] = $this->addmod2n($h[1], $_b);
532 $h[2] = $this->addmod2n($h[2], $_c);
533 $h[3] = $this->addmod2n($h[3], $_d);
534 $h[4] = $this->addmod2n($h[4], $_e);
535 $h[5] = $this->addmod2n($h[5], $_f);
536 $h[6] = $this->addmod2n($h[6], $_g);
537 $h[7] = $this->addmod2n($h[7], $_h);
538 }
539
540 // Convert the 32-bit words into human readable hexadecimal format.
541 $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]);
542
543 return ($this->toUpper) ? strtoupper($hexStr) : $hexStr;
544 }
545
546 }
547 }
548
549 /**
550 * Main routine called from an application using this include.
551 *
552 * General usage:
553 * require_once('sha256.inc.php');
554 * $hashstr = sha256('abc');
555 *
556 * @Note
557 * PHP Strings are limitd to (2^31)-1, so it is not worth it to
558 * check for input strings > 2^64 as the FIPS180-2 defines.
559 *
560 * @param string $str Chaîne dont on veut calculer le SHA
561 * @param bool $ig_func
562 * @return string Le SHA de la chaîne
563 */
564 function _nano_sha256($str, $ig_func = true) {
565 $obj = new nanoSha2((defined('_NANO_SHA2_UPPER')) ? true : false);
566
567 return $obj->hash($str, $ig_func);
568 }
569
570 // 2009-07-23: Added check for function as the Suhosin plugin adds this routine.
571 if (!function_exists('sha256')) {
572 /**
573 * Calcul du SHA256
574 *
575 * @param string $str Chaîne dont on veut calculer le SHA
576 * @param bool $ig_func
577 * @return string Le SHA de la chaîne
578 */
579 function sha256($str, $ig_func = true) { return _nano_sha256($str, $ig_func); }
580 }
581
582 // support to give php4 the hash() routine which abstracts this code.
583 if (!function_exists('hash')) {
584 define('_NO_HASH_DEFINED', true);
585 /**
586 * Retourne le calcul d'un hachage d'une chaîne (pour PHP4)
587 *
588 * @param string $algo Nom de l'algorythme de hachage
589 * @param string $data Chaîne à hacher
590 * @return string|bool
591 * Hash de la chaîne
592 * False si pas d'algo trouvé
593 */
594 function hash($algo, $data) {
595 if (empty($algo) || !is_string($algo) || !is_string($data)) {
596 return false;
597 }
598
599 if (function_exists($algo)) {
600 return $algo($data);
601 }
602 }
603 }