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