| 1 : |
tmcnulty
|
1.1
|
<?php
|
| 2 : |
|
|
////////////////////////////////////////////////////////////////////////////
|
| 3 : |
|
|
// SHA implementation v1.0
|
| 4 : |
|
|
// Based on the SHA algorithm as given in "Applied Cryptography"
|
| 5 : |
|
|
// Code written by Chris Monson (chris@bouncingchairs.net)
|
| 6 : |
|
|
// Most recent version available on http://bouncingchairs.net
|
| 7 : |
|
|
// Licensed under the GNU LGPL (http://www.gnu.org/copyleft/lesser.html)
|
| 8 : |
|
|
// April 11, 2000
|
| 9 : |
|
|
// License changed (I'm an idiot) June 26, 2000
|
| 10 : |
|
|
////////////////////////////////////////////////////////////////////////////
|
| 11 : |
|
|
|
| 12 : |
|
|
////////////////////////////////////////////////////////////////////////////
|
| 13 : |
|
|
// USAGE:
|
| 14 : |
|
|
//------------------------------------------------------------------------
|
| 15 : |
|
|
//
|
| 16 : |
|
|
// Simple text hash:
|
| 17 : |
|
|
//
|
| 18 : |
|
|
// $sha = new SHA;
|
| 19 : |
|
|
// $hasharray = $sha->hash_text( 'hash me!' );
|
| 20 : |
|
|
//
|
| 21 : |
|
|
// This returns an array of 5 32-bit integers.
|
| 22 : |
|
|
// The SHA->hash_bytes function does the same thing, but requires
|
| 23 : |
|
|
// an array of bytes as input. Note that the input values will be
|
| 24 : |
|
|
// truncated if they are larger than 8 bits.
|
| 25 : |
|
|
//
|
| 26 : |
|
|
//------------------------------------------------------------------------
|
| 27 : |
|
|
//
|
| 28 : |
|
|
// There are also some hash to string conversion functions. The
|
| 29 : |
|
|
// naming convention admittedly could be better, but it works :).
|
| 30 : |
|
|
//
|
| 31 : |
|
|
// $sha->hash_to_string( $hasharray )
|
| 32 : |
|
|
//
|
| 33 : |
|
|
// Converts the hash array to an uppercase hex string.
|
| 34 : |
|
|
//
|
| 35 : |
|
|
//------------------------------------------------------------------------
|
| 36 : |
|
|
//
|
| 37 : |
|
|
// Hashing very large blocks a piece at a time:
|
| 38 : |
|
|
//
|
| 39 : |
|
|
// $sha = new SHA;
|
| 40 : |
|
|
// $sha->init();
|
| 41 : |
|
|
// while (blocks_to_process()) {
|
| 42 : |
|
|
// $sha->update( next_byte_array() )
|
| 43 : |
|
|
// }
|
| 44 : |
|
|
// $hasharray = $sha->finalize()
|
| 45 : |
|
|
//
|
| 46 : |
|
|
////////////////////////////////////////////////////////////////////////////
|
| 47 : |
|
|
|
| 48 : |
|
|
////////////////////////////////////////////////////////////////////////////
|
| 49 : |
|
|
// NOTES:
|
| 50 : |
|
|
// This is basically a rip off of SHAPerl.pm, which I also wrote.
|
| 51 : |
|
|
// I discovered, much to my chagrin, that PHP does not have even
|
| 52 : |
|
|
// the crappy 32-bit int support that Perl has, so I had to employ
|
| 53 : |
|
|
// some funny tricks in the code to get it to use all 32 bits.
|
| 54 : |
|
|
// One of the most obvious of these is using an 'add' method instead
|
| 55 : |
|
|
// of just adding numbers together. Any numbers over 32 bits don't get
|
| 56 : |
|
|
// bit-truncated. They get corralled, which is not what I wanted.
|
| 57 : |
|
|
// Another trick I had to employ was splitting large numeric constants
|
| 58 : |
|
|
// into two pieces. Apparently, you can't specify 0xffffffff. It gets
|
| 59 : |
|
|
// set to 0. Everything up to 0x7fffffff works fine. So, I used
|
| 60 : |
|
|
// some shifting and bitwise operators to get the needed constants.
|
| 61 : |
|
|
//
|
| 62 : |
|
|
// A word on optimization: it isn't optimized. My chief concern was
|
| 63 : |
|
|
// to get it working, and it is fast enough for my needs. If, however,
|
| 64 : |
|
|
// you intend to try to brute force some hash values with this, either
|
| 65 : |
|
|
// it will need some serious optimizations done, or you should be
|
| 66 : |
|
|
// using one of the freely available C implementations.
|
| 67 : |
|
|
//
|
| 68 : |
|
|
////////////////////////////////////////////////////////////////////////////
|
| 69 : |
|
|
class SHA {
|
| 70 : |
|
|
var $A, $B, $C, $D, $E; // result variables
|
| 71 : |
|
|
var $ta, $tb, $tc, $td, $te; // temp variables
|
| 72 : |
|
|
var $K0_19, $K20_39, $K40_59, $K60_79;
|
| 73 : |
|
|
|
| 74 : |
|
|
var $buffer;
|
| 75 : |
|
|
var $buffsize;
|
| 76 : |
|
|
var $totalsize;
|
| 77 : |
|
|
|
| 78 : |
|
|
function SHA () {
|
| 79 : |
|
|
$this->init();
|
| 80 : |
|
|
}
|
| 81 : |
|
|
|
| 82 : |
|
|
function init () {
|
| 83 : |
|
|
// The long constants can't be used for some dumb reason.
|
| 84 : |
|
|
$this->A = 0x6745 << 16 | 0x2301;
|
| 85 : |
|
|
$this->B = 0xefcd << 16 | 0xab89;
|
| 86 : |
|
|
$this->C = 0x98ba << 16 | 0xdcfe;
|
| 87 : |
|
|
$this->D = 0x1032 << 16 | 0x5476;
|
| 88 : |
|
|
$this->E = 0xc3d2 << 16 | 0xe1f0;
|
| 89 : |
|
|
$this->ta = $this->A;
|
| 90 : |
|
|
$this->tb = $this->B;
|
| 91 : |
|
|
$this->tc = $this->C;
|
| 92 : |
|
|
$this->td = $this->D;
|
| 93 : |
|
|
$this->te = $this->E;
|
| 94 : |
|
|
$this->K0_19 = 0x5a82 << 16 | 0x7999;
|
| 95 : |
|
|
$this->K20_39 = 0x6ed9 << 16 | 0xeba1;
|
| 96 : |
|
|
$this->K40_59 = 0x8f1b << 16 | 0xbcdc;
|
| 97 : |
|
|
$this->K60_79 = 0xca62 << 16 | 0xc1d6;
|
| 98 : |
|
|
|
| 99 : |
|
|
$this->buffer = array();
|
| 100 : |
|
|
$this->buffsize = 0;
|
| 101 : |
|
|
$this->totalsize = 0;
|
| 102 : |
|
|
}
|
| 103 : |
|
|
|
| 104 : |
|
|
function bytes_to_words( $block ) {
|
| 105 : |
|
|
$nblk = array();
|
| 106 : |
|
|
for( $i=0; $i<16; ++$i) {
|
| 107 : |
|
|
$index = $i * 4;
|
| 108 : |
|
|
$nblk[$i] = 0;
|
| 109 : |
|
|
$nblk[$i] |= ($block[$index] & 0xff) << 24;
|
| 110 : |
|
|
$nblk[$i] |= ($block[$index+1] & 0xff) << 16;
|
| 111 : |
|
|
$nblk[$i] |= ($block[$index+2] & 0xff) << 8;
|
| 112 : |
|
|
$nblk[$i] |= ($block[$index+3] & 0xff);
|
| 113 : |
|
|
}
|
| 114 : |
|
|
return $nblk;
|
| 115 : |
|
|
}
|
| 116 : |
|
|
|
| 117 : |
|
|
function pad_block( $block, $size ) {
|
| 118 : |
|
|
// Returns a block that is a multiple of 512 bits long
|
| 119 : |
|
|
$blksize = sizeof( $block );
|
| 120 : |
|
|
$bits = $size * 8;
|
| 121 : |
|
|
|
| 122 : |
|
|
// Always pad with 0x80, then add as many zeros as necessary to
|
| 123 : |
|
|
// make the message 64 bits short of 512. Then add the 64-bit size.
|
| 124 : |
|
|
$newblock = $block;
|
| 125 : |
|
|
$newblock[] = 0x80; // push 0x80 onto the end
|
| 126 : |
|
|
// Add the zeros
|
| 127 : |
|
|
while((sizeof($newblock) % 64) != 56) {
|
| 128 : |
|
|
$newblock[] = 0;
|
| 129 : |
|
|
}
|
| 130 : |
|
|
// Add the size
|
| 131 : |
|
|
for ($i=0; $i<8; ++$i) {
|
| 132 : |
|
|
$newblock[] = ($i<4) ? 0 : ($bits >> ((7-$i)*8)) & 0xff;
|
| 133 : |
|
|
}
|
| 134 : |
|
|
|
| 135 : |
|
|
return $newblock;
|
| 136 : |
|
|
}
|
| 137 : |
|
|
|
| 138 : |
|
|
function circ_shl( $num, $amt ) {
|
| 139 : |
|
|
$leftmask = 0xffff | (0xffff << 16);
|
| 140 : |
|
|
$leftmask <<= 32 - $amt;
|
| 141 : |
|
|
$rightmask = 0xffff | (0xffff << 16);
|
| 142 : |
|
|
$rightmask <<= $amt;
|
| 143 : |
|
|
$rightmask = ~$rightmask;
|
| 144 : |
|
|
|
| 145 : |
|
|
$remains = $num & $leftmask;
|
| 146 : |
|
|
$remains >>= 32 - $amt;
|
| 147 : |
|
|
$remains &= $rightmask;
|
| 148 : |
|
|
|
| 149 : |
|
|
$res = ($num << $amt) | $remains;
|
| 150 : |
|
|
|
| 151 : |
|
|
return $res;
|
| 152 : |
|
|
}
|
| 153 : |
|
|
|
| 154 : |
|
|
function f0_19( $x, $y, $z ) {
|
| 155 : |
|
|
return ($x & $y) | (~$x & $z);
|
| 156 : |
|
|
}
|
| 157 : |
|
|
|
| 158 : |
|
|
function f20_39( $x, $y, $z ) {
|
| 159 : |
|
|
return ($x ^ $y ^ $z);
|
| 160 : |
|
|
}
|
| 161 : |
|
|
|
| 162 : |
|
|
function f40_59( $x, $y, $z ) {
|
| 163 : |
|
|
return ($x & $y) | ($x & $z) | ($y & $z);
|
| 164 : |
|
|
}
|
| 165 : |
|
|
|
| 166 : |
|
|
function f60_79( $x, $y, $z ) {
|
| 167 : |
|
|
return $this->f20_39( $x, $y, $z );
|
| 168 : |
|
|
}
|
| 169 : |
|
|
|
| 170 : |
|
|
function expand_block( $block ) {
|
| 171 : |
|
|
$nblk = $block;
|
| 172 : |
|
|
for( $i=16; $i<80; ++$i ) {
|
| 173 : |
|
|
$nblk[$i] = $this->circ_shl(
|
| 174 : |
|
|
$nblk[$i-3] ^ $nblk[$i-8] ^ $nblk[$i-14] ^ $nblk[$i-16], 1
|
| 175 : |
|
|
);
|
| 176 : |
|
|
}
|
| 177 : |
|
|
|
| 178 : |
|
|
return $nblk;
|
| 179 : |
|
|
}
|
| 180 : |
|
|
|
| 181 : |
|
|
function print_bytes( $bytes ) {
|
| 182 : |
|
|
$len = sizeof( $bytes );
|
| 183 : |
|
|
for( $i=0; $i<$len; ++$i) {
|
| 184 : |
|
|
$str[] = sprintf( "%02x", $bytes[$i] );
|
| 185 : |
|
|
}
|
| 186 : |
|
|
|
| 187 : |
|
|
print( join( ", ", $str ) . "\n" );
|
| 188 : |
|
|
}
|
| 189 : |
|
|
|
| 190 : |
|
|
function wordstr( $word ) {
|
| 191 : |
|
|
return sprintf(
|
| 192 : |
|
|
"%04x%04x", ($word >> 16) & 0xffff, $word & 0xffff
|
| 193 : |
|
|
);
|
| 194 : |
|
|
}
|
| 195 : |
|
|
|
| 196 : |
|
|
function print_words( $words ) {
|
| 197 : |
|
|
$len = sizeof( $words );
|
| 198 : |
|
|
for( $i=0; $i<$len; ++$i) {
|
| 199 : |
|
|
$str[] = $this->wordstr( $words[$i] );
|
| 200 : |
|
|
}
|
| 201 : |
|
|
|
| 202 : |
|
|
print( join( ", ", $str ) . "\n" );
|
| 203 : |
|
|
}
|
| 204 : |
|
|
|
| 205 : |
|
|
function hash_to_string( $hash ) {
|
| 206 : |
|
|
$len = sizeof( $hash );
|
| 207 : |
|
|
for ($i=0; $i<$len; ++$i) {
|
| 208 : |
|
|
$astr[] = $this->wordstr( $hash[$i] );
|
| 209 : |
|
|
}
|
| 210 : |
|
|
return join( "", $astr );
|
| 211 : |
|
|
}
|
| 212 : |
|
|
|
| 213 : |
|
|
// Add simply adds two numbers. It is provided for compatibility on
|
| 214 : |
|
|
// platforms that only support a 31 bit add (there are a few, apparently)
|
| 215 : |
|
|
function add( $a, $b ) {
|
| 216 : |
|
|
$ma = ($a >> 16) & 0xffff;
|
| 217 : |
|
|
$la = ($a) & 0xffff;
|
| 218 : |
|
|
$mb = ($b >> 16) & 0xffff;
|
| 219 : |
|
|
$lb = ($b) & 0xffff;
|
| 220 : |
|
|
|
| 221 : |
|
|
$ls = $la + $lb;
|
| 222 : |
|
|
// Carry
|
| 223 : |
|
|
if ($ls > 0xffff) {
|
| 224 : |
|
|
$ma += 1;
|
| 225 : |
|
|
$ls &= 0xffff;
|
| 226 : |
|
|
}
|
| 227 : |
|
|
|
| 228 : |
|
|
// MS add
|
| 229 : |
|
|
$ms = $ma + $mb;
|
| 230 : |
|
|
$ms &= 0xffff;
|
| 231 : |
|
|
|
| 232 : |
|
|
// Works because the bitwise operators are 32 bit
|
| 233 : |
|
|
$result = ($ms << 16) | $ls;
|
| 234 : |
|
|
return $result;
|
| 235 : |
|
|
}
|
| 236 : |
|
|
|
| 237 : |
|
|
function process_block( $blk ) {
|
| 238 : |
|
|
$blk = $this->expand_block( $blk );
|
| 239 : |
|
|
|
| 240 : |
|
|
for( $i=0; $i<80; ++$i ) {
|
| 241 : |
|
|
$temp = $this->circ_shl( $this->ta, 5 );
|
| 242 : |
|
|
if ($i<20) {
|
| 243 : |
|
|
$f = $this->f0_19( $this->tb, $this->tc, $this->td );
|
| 244 : |
|
|
$k = $this->K0_19;
|
| 245 : |
|
|
}
|
| 246 : |
|
|
elseif ($i<40) {
|
| 247 : |
|
|
$f = $this->f20_39( $this->tb, $this->tc, $this->td );
|
| 248 : |
|
|
$k = $this->K20_39;
|
| 249 : |
|
|
}
|
| 250 : |
|
|
elseif ($i<60) {
|
| 251 : |
|
|
$f = $this->f40_59( $this->tb, $this->tc, $this->td );
|
| 252 : |
|
|
$k = $this->K40_59;
|
| 253 : |
|
|
}
|
| 254 : |
|
|
else {
|
| 255 : |
|
|
$f = $this->f60_79( $this->tb, $this->tc, $this->td );
|
| 256 : |
|
|
$k = $this->K60_79;
|
| 257 : |
|
|
}
|
| 258 : |
|
|
|
| 259 : |
|
|
$temp = $this->add( $temp, $f );
|
| 260 : |
|
|
$temp = $this->add( $temp, $this->te );
|
| 261 : |
|
|
$temp = $this->add( $temp, $blk[$i] );
|
| 262 : |
|
|
$temp = $this->add( $temp, $k );
|
| 263 : |
|
|
|
| 264 : |
|
|
$this->te = $this->td;
|
| 265 : |
|
|
$this->td = $this->tc;
|
| 266 : |
|
|
$this->tc = $this->circ_shl( $this->tb, 30 );
|
| 267 : |
|
|
$this->tb = $this->ta;
|
| 268 : |
|
|
$this->ta = $temp;
|
| 269 : |
|
|
}
|
| 270 : |
|
|
|
| 271 : |
|
|
$this->A = $this->add( $this->A, $this->ta );
|
| 272 : |
|
|
$this->B = $this->add( $this->B, $this->tb );
|
| 273 : |
|
|
$this->C = $this->add( $this->C, $this->tc );
|
| 274 : |
|
|
$this->D = $this->add( $this->D, $this->td );
|
| 275 : |
|
|
$this->E = $this->add( $this->E, $this->te );
|
| 276 : |
|
|
}
|
| 277 : |
|
|
|
| 278 : |
|
|
function update ( $bytes ) {
|
| 279 : |
|
|
$length = sizeof( $bytes );
|
| 280 : |
|
|
$index = 0;
|
| 281 : |
|
|
|
| 282 : |
|
|
// Process each full block
|
| 283 : |
|
|
while (($length - $index) + $this->buffsize >= 64) {
|
| 284 : |
|
|
for( $i=$this->buffsize; $i<64; ++$i) {
|
| 285 : |
|
|
$this->buffer[$i] = $bytes[$index + $i - $this->buffsize];
|
| 286 : |
|
|
}
|
| 287 : |
|
|
$this->process_block( $this->bytes_to_words( $this->buffer ) );
|
| 288 : |
|
|
$index += 64;
|
| 289 : |
|
|
$this->buffsize = 0;
|
| 290 : |
|
|
}
|
| 291 : |
|
|
|
| 292 : |
|
|
// Any remaining bytes that do not make up a full block need to be'
|
| 293 : |
|
|
// added into the buffer for the next update (or final)
|
| 294 : |
|
|
$remaining = $length - $index;
|
| 295 : |
|
|
for( $i=0; $i<$remaining; ++$i) {
|
| 296 : |
|
|
$this->buffer[$this->buffisze + $i] = $bytes[$index + $i];
|
| 297 : |
|
|
}
|
| 298 : |
|
|
$this->buffsize += $remaining;
|
| 299 : |
|
|
$this->totalsize += $length;
|
| 300 : |
|
|
}
|
| 301 : |
|
|
|
| 302 : |
|
|
function final() {
|
| 303 : |
|
|
// Pad and process the buffer
|
| 304 : |
|
|
for( $i=0; $i<$this->buffsize; ++$i) {
|
| 305 : |
|
|
$last_block[$i] = $this->buffer[$i];
|
| 306 : |
|
|
}
|
| 307 : |
|
|
$this->buffsize = 0;
|
| 308 : |
|
|
// Pad the block
|
| 309 : |
|
|
$last_block = $this->pad_block( $last_block, $this->totalsize );
|
| 310 : |
|
|
// Process the last one (or two) block(s)
|
| 311 : |
|
|
$index = 0;
|
| 312 : |
|
|
$length = sizeof( $last_block );
|
| 313 : |
|
|
while( $index < $length )
|
| 314 : |
|
|
{
|
| 315 : |
|
|
$block = array();
|
| 316 : |
|
|
for( $i=0; $i<64; ++$i) {
|
| 317 : |
|
|
$block[$i] = $last_block[$i + $index];
|
| 318 : |
|
|
}
|
| 319 : |
|
|
$this->process_block( $this->bytes_to_words( $block ) );
|
| 320 : |
|
|
$index += 64;
|
| 321 : |
|
|
}
|
| 322 : |
|
|
|
| 323 : |
|
|
$result[0] = $this->A;
|
| 324 : |
|
|
$result[1] = $this->B;
|
| 325 : |
|
|
$result[2] = $this->C;
|
| 326 : |
|
|
$result[3] = $this->D;
|
| 327 : |
|
|
$result[4] = $this->E;
|
| 328 : |
|
|
|
| 329 : |
|
|
return $result;
|
| 330 : |
|
|
}
|
| 331 : |
|
|
|
| 332 : |
|
|
function hash_bytes( $bytes ) {
|
| 333 : |
|
|
$this->init();
|
| 334 : |
|
|
$this->update( $bytes );
|
| 335 : |
|
|
return $this->final();
|
| 336 : |
|
|
}
|
| 337 : |
|
|
|
| 338 : |
|
|
function hash_string( $str ) {
|
| 339 : |
|
|
$len = strlen( $str );
|
| 340 : |
|
|
for($i=0; $i<$len; ++$i) {
|
| 341 : |
|
|
$bytes[] = ord( $str[$i] ) & 0xff;
|
| 342 : |
|
|
}
|
| 343 : |
|
|
return $this->hash_bytes( $bytes );
|
| 344 : |
|
|
}
|
| 345 : |
|
|
}
|
| 346 : |
|
|
?>
|