[SPIP] ~2.1.12 -->2.1.25
[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 $pad = ceil(($length+32/$this->bytesString)/$npad)*$npad-32/$this->bytesString;
211 $ords = array_pad($ords,$pad,0);
212
213 $pad *= $this->bytesString;
214 $bin = array_pad(array(), $pad>>5, 0);
215 $mask = (1 << $this->bytesString) - 1;
216 for($i = 0; $i < $pad ; $i += $this->bytesString)
217 $bin[$i>>5] |= ($ords[$i / $this->bytesString] & $mask) << (24 - $i%32);
218 $bin[] = $length*$this->bytesString;
219 return $bin;
220 }
221
222 function array_split($a, $n) {
223 $split = array();
224 while (count($a)>$n) {
225 $s = array();
226 for($i = 0;$i<$n;$i++)
227 $s[] = array_shift($a);
228 $split[] = $s;
229 }
230 if (count($a)){
231 $a = array_pad($a,$n,0);
232 $split[] = $a;
233 }
234 return $split;
235 }
236
237 /**
238 * Process and return the hash.
239 *
240 * @param $str Input string to hash
241 * @param $ig_func Option param to ignore checking for php > 5.1.2
242 * @return string Hexadecimal representation of the message digest
243 */
244 function hash($str, $ig_func = true)
245 {
246 unset($binStr); // binary representation of input string
247 unset($hexStr); // 256-bit message digest in readable hex format
248
249 // check for php's internal sha256 function, ignore if ig_func==true
250 if ($ig_func == false) {
251 if (version_compare(PHP_VERSION,'5.1.2','>=') AND !defined('_NO_HASH_DEFINED')) {
252 return hash("sha256", $str, false);
253 } else if (function_exists('mhash') && defined('MHASH_SHA256')) {
254 return base64_encode(bin2hex(mhash(MHASH_SHA256, $str)));
255 }
256 }
257
258 /*
259 * SHA-256 Constants
260 * Sequence of sixty-four constant 32-bit words representing the
261 * first thirty-two bits of the fractional parts of the cube roots
262 * of the first sixtyfour prime numbers.
263 */
264 $K = array((int)0x428a2f98, (int)0x71374491, (int)0xb5c0fbcf,
265 (int)0xe9b5dba5, (int)0x3956c25b, (int)0x59f111f1,
266 (int)0x923f82a4, (int)0xab1c5ed5, (int)0xd807aa98,
267 (int)0x12835b01, (int)0x243185be, (int)0x550c7dc3,
268 (int)0x72be5d74, (int)0x80deb1fe, (int)0x9bdc06a7,
269 (int)0xc19bf174, (int)0xe49b69c1, (int)0xefbe4786,
270 (int)0x0fc19dc6, (int)0x240ca1cc, (int)0x2de92c6f,
271 (int)0x4a7484aa, (int)0x5cb0a9dc, (int)0x76f988da,
272 (int)0x983e5152, (int)0xa831c66d, (int)0xb00327c8,
273 (int)0xbf597fc7, (int)0xc6e00bf3, (int)0xd5a79147,
274 (int)0x06ca6351, (int)0x14292967, (int)0x27b70a85,
275 (int)0x2e1b2138, (int)0x4d2c6dfc, (int)0x53380d13,
276 (int)0x650a7354, (int)0x766a0abb, (int)0x81c2c92e,
277 (int)0x92722c85, (int)0xa2bfe8a1, (int)0xa81a664b,
278 (int)0xc24b8b70, (int)0xc76c51a3, (int)0xd192e819,
279 (int)0xd6990624, (int)0xf40e3585, (int)0x106aa070,
280 (int)0x19a4c116, (int)0x1e376c08, (int)0x2748774c,
281 (int)0x34b0bcb5, (int)0x391c0cb3, (int)0x4ed8aa4a,
282 (int)0x5b9cca4f, (int)0x682e6ff3, (int)0x748f82ee,
283 (int)0x78a5636f, (int)0x84c87814, (int)0x8cc70208,
284 (int)0x90befffa, (int)0xa4506ceb, (int)0xbef9a3f7,
285 (int)0xc67178f2);
286
287 // Pre-processing: Padding the string
288 $binStr = $this->string2binint($str,512);
289
290 // Parsing the Padded Message (Break into N 512-bit blocks)
291 $M = $this->array_split($binStr, 16);
292
293 // Set the initial hash values
294 $h[0] = (int)0x6a09e667;
295 $h[1] = (int)0xbb67ae85;
296 $h[2] = (int)0x3c6ef372;
297 $h[3] = (int)0xa54ff53a;
298 $h[4] = (int)0x510e527f;
299 $h[5] = (int)0x9b05688c;
300 $h[6] = (int)0x1f83d9ab;
301 $h[7] = (int)0x5be0cd19;
302
303 // loop through message blocks and compute hash. ( For i=1 to N : )
304 $N = count($M);
305 for ($i = 0; $i < $N; $i++)
306 {
307 // Break input block into 16 32bit words (message schedule prep)
308 $MI = $M[$i];
309
310 // Initialize working variables
311 $_a = (int)$h[0];
312 $_b = (int)$h[1];
313 $_c = (int)$h[2];
314 $_d = (int)$h[3];
315 $_e = (int)$h[4];
316 $_f = (int)$h[5];
317 $_g = (int)$h[6];
318 $_h = (int)$h[7];
319 unset($_s0);
320 unset($_s1);
321 unset($_T1);
322 unset($_T2);
323 $W = array();
324
325 // Compute the hash and update
326 for ($t = 0; $t < 16; $t++)
327 {
328 // Prepare the first 16 message schedule values as we loop
329 $W[$t] = $MI[$t];
330
331 // Compute hash
332 $_T1 = $this->addmod2n($this->addmod2n($this->addmod2n($this->addmod2n($_h, $this->Sigma1($_e)), $this->Ch($_e, $_f, $_g)), $K[$t]), $W[$t]);
333 $_T2 = $this->addmod2n($this->Sigma0($_a), $this->Maj($_a, $_b, $_c));
334
335 // Update working variables
336 $_h = $_g; $_g = $_f; $_f = $_e; $_e = $this->addmod2n($_d, $_T1);
337 $_d = $_c; $_c = $_b; $_b = $_a; $_a = $this->addmod2n($_T1, $_T2);
338 }
339
340 for (; $t < 64; $t++)
341 {
342 // Continue building the message schedule as we loop
343 $_s0 = $W[($t+1)&0x0F];
344 $_s0 = $this->sigma_0($_s0);
345 $_s1 = $W[($t+14)&0x0F];
346 $_s1 = $this->sigma_1($_s1);
347
348 $W[$t&0xF] = $this->addmod2n($this->addmod2n($this->addmod2n($W[$t&0xF], $_s0), $_s1), $W[($t+9)&0x0F]);
349
350 // Compute hash
351 $_T1 = $this->addmod2n($this->addmod2n($this->addmod2n($this->addmod2n($_h, $this->Sigma1($_e)), $this->Ch($_e, $_f, $_g)), $K[$t]), $W[$t&0xF]);
352 $_T2 = $this->addmod2n($this->Sigma0($_a), $this->Maj($_a, $_b, $_c));
353
354 // Update working variables
355 $_h = $_g; $_g = $_f; $_f = $_e; $_e = $this->addmod2n($_d, $_T1);
356 $_d = $_c; $_c = $_b; $_b = $_a; $_a = $this->addmod2n($_T1, $_T2);
357 }
358
359 $h[0] = $this->addmod2n($h[0], $_a);
360 $h[1] = $this->addmod2n($h[1], $_b);
361 $h[2] = $this->addmod2n($h[2], $_c);
362 $h[3] = $this->addmod2n($h[3], $_d);
363 $h[4] = $this->addmod2n($h[4], $_e);
364 $h[5] = $this->addmod2n($h[5], $_f);
365 $h[6] = $this->addmod2n($h[6], $_g);
366 $h[7] = $this->addmod2n($h[7], $_h);
367 }
368
369 // Convert the 32-bit words into human readable hexadecimal format.
370 $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]);
371
372 return ($this->toUpper) ? strtoupper($hexStr) : $hexStr;
373 }
374
375 }
376 }
377
378 if (!function_exists('str_split'))
379 {
380 /**
381 * Splits a string into an array of strings with specified length.
382 * Compatability with older verions of PHP
383 */
384 function str_split($string, $split_length = 1)
385 {
386 $sign = ($split_length < 0) ? -1 : 1;
387 $strlen = strlen($string);
388 $split_length = abs($split_length);
389
390 if (($split_length == 0) || ($strlen == 0)) {
391 return false;
392 } elseif ($split_length >= $strlen) {
393 return array($string);
394 } else {
395 $length = $split_length;
396 $result = array();
397 for ($i = 0; $i < $strlen; $i++)
398 {
399 $i = (($sign < 0) ? $i + $length : $i);
400 $result[] = substr($string, $sign*$i, $length);
401 $i--;
402 $i = (($sign < 0) ? $i : $i + $length);
403
404 $length = (($i + $split_length) > $strlen)
405 ? ($strlen - ($i + 1))
406 : $split_length;
407 }
408 return $result;
409 }
410 }
411 }
412
413 /**
414 * Main routine called from an application using this include.
415 *
416 * General usage:
417 * require_once('sha256.inc.php');
418 * $hashstr = sha256('abc');
419 *
420 * Note:
421 * PHP Strings are limitd to (2^31)-1, so it is not worth it to
422 * check for input strings > 2^64 as the FIPS180-2 defines.
423 */
424 function _nano_sha256($str, $ig_func = true) {
425 $obj = new nanoSha2((defined('_NANO_SHA2_UPPER')) ? true : false);
426 return $obj->hash($str, $ig_func);
427 }
428 // 2009-07-23: Added check for function as the Suhosin plugin adds this routine.
429 if (!function_exists('sha256')) {
430 function sha256($str, $ig_func = true) { return _nano_sha256($str, $ig_func); }
431 }
432
433 // support to give php4 the hash() routine which abstracts this code.
434 if (!function_exists('hash'))
435 {
436 define('_NO_HASH_DEFINED',true);
437 function hash($algo, $data)
438 {
439 if (empty($algo) || !is_string($algo) || !is_string($data)) {
440 return false;
441 }
442
443 if (function_exists($algo)) {
444 return $algo($data);
445 }
446 }
447 }
448
449 ?>