PHP Classes

File: sha.php

Recommend this page to a friend!
  Classes of Chris Monson   SHA   sha.php   Download  
File: sha.php
Role: ???
Content type: text/plain
Description: Pure PHP implmentation of SHA
Class: SHA
Author: By
Last change:
Date: 23 years ago
Size: 11,491 bytes
 

Contents

Class file image Download
<?php if (!defined('SHA_Included')) { define('SHA_Included', 1); //////////////////////////////////////////////////////////////////////////// // SHA implementation v1.0 // Based on the SHA algorithm as given in "Applied Cryptography" // Code written by Chris Monson (chris@bouncingchairs.net) // Most recent version available on http://bouncingchairs.net // Licensed under the GNU LGPL (http://www.gnu.org/copyleft/lesser.html) // April 11, 2000 // License changed (I'm an idiot) June 26, 2000 //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // USAGE: //------------------------------------------------------------------------ // // Simple text hash: // // $sha = new SHA; // $hasharray = $sha->hash_string( 'hash me!' ); // // This returns an array of 5 32-bit integers. // The SHA.hash_bytes function does the same thing, but requires // an array of bytes as input. Note that the input values will be // truncated if they are larger than 8 bits. // //------------------------------------------------------------------------ // // There are also some hash to string conversion functions. The // naming convention admittedly could be better, but it works :). // // $sha->hash_to_string( $hasharray ) // // Converts the hash array to an uppercase hex string. // //------------------------------------------------------------------------ // // Hashing very large blocks a piece at a time: // // $sha = new SHA; // $sha->init(); // while (blocks_to_process) { // $sha->update( next_byte_array ) // } // $hasharray = $sha->finalize() // //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // NOTES: // This is basically a rip off of SHAPerl.pm, which I also wrote. // I discovered, much to my chagrin, that PHP does not have even // the crappy 32-bit int support that Perl has, so I had to employ // some funny tricks in the code to get it to use all 32 bits. // One of the most obvious of these is using an 'add' method instead // of just adding numbers together. Any numbers over 32 bits don't get // bit-truncated. They get corralled, which is not what I wanted. // Another trick I had to employ was splitting large numeric constants // into two pieces. Apparently, you can't specify 0xffffffff. It gets // set to 0. Everything up to 0x7fffffff works fine. So, I used // some shifting and bitwise operators to get the needed constants. // // A word on optimization: it isn't optimized. My chief concern was // to get it working, and it is fast enough for my needs. If, however, // you intend to try to brute force some hash values with this, either // it will need some serious optimizations done, or you should be // using one of the freely available C implementations. // //////////////////////////////////////////////////////////////////////////// class SHA { var $A, $B, $C, $D, $E; // result variables var $ta, $tb, $tc, $td, $te; // temp variables var $K0_19, $K20_39, $K40_59, $K60_79; var $buffer; var $buffsize; var $totalsize; function SHA () { $this->init(); } function init () { // The long constants can't be used for some dumb reason. $this->A = 0x6745 << 16 | 0x2301; $this->B = 0xefcd << 16 | 0xab89; $this->C = 0x98ba << 16 | 0xdcfe; $this->D = 0x1032 << 16 | 0x5476; $this->E = 0xc3d2 << 16 | 0xe1f0; $this->ta = $this->A; $this->tb = $this->B; $this->tc = $this->C; $this->td = $this->D; $this->te = $this->E; $this->K0_19 = 0x5a82 << 16 | 0x7999; $this->K20_39 = 0x6ed9 << 16 | 0xeba1; $this->K40_59 = 0x8f1b << 16 | 0xbcdc; $this->K60_79 = 0xca62 << 16 | 0xc1d6; $this->buffer = array(); $this->buffsize = 0; $this->totalsize = 0; } function bytes_to_words( $block ) { $nblk = array(); for( $i=0; $i<16; ++$i) { $index = $i * 4; $nblk[$i] = 0; $nblk[$i] |= ($block[$index] & 0xff) << 24; $nblk[$i] |= ($block[$index+1] & 0xff) << 16; $nblk[$i] |= ($block[$index+2] & 0xff) << 8; $nblk[$i] |= ($block[$index+3] & 0xff); } return $nblk; } function pad_block( $block, $size ) { // Returns a block that is a multiple of 512 bits long $blksize = sizeof( $block ); $bits = $size * 8; // Always pad with 0x80, then add as many zeros as necessary to // make the message 64 bits short of 512. Then add the 64-bit size. $newblock = $block; $newblock[] = 0x80; // push 0x80 onto the end // Add the zeros while((sizeof($newblock) % 64) != 56) { $newblock[] = 0; } // Add the size for ($i=0; $i<8; ++$i) { $newblock[] = ($i<4) ? 0 : ($bits >> ((7-$i)*8)) & 0xff; } return $newblock; } function circ_shl( $num, $amt ) { $leftmask = 0xffff | (0xffff << 16); $leftmask <<= 32 - $amt; $rightmask = 0xffff | (0xffff << 16); $rightmask <<= $amt; $rightmask = ~$rightmask; $remains = $num & $leftmask; $remains >>= 32 - $amt; $remains &= $rightmask; $res = ($num << $amt) | $remains; return $res; } function f0_19( $x, $y, $z ) { return ($x & $y) | (~$x & $z); } function f20_39( $x, $y, $z ) { return ($x ^ $y ^ $z); } function f40_59( $x, $y, $z ) { return ($x & $y) | ($x & $z) | ($y & $z); } function f60_79( $x, $y, $z ) { return $this->f20_39( $x, $y, $z ); } function expand_block( $block ) { $nblk = $block; for( $i=16; $i<80; ++$i ) { $nblk[$i] = $this->circ_shl( $nblk[$i-3] ^ $nblk[$i-8] ^ $nblk[$i-14] ^ $nblk[$i-16], 1 ); } return $nblk; } function print_bytes( $bytes ) { $len = sizeof( $bytes ); for( $i=0; $i<$len; ++$i) { $str[] = sprintf( "%02x", $bytes[$i] ); } print( join( ", ", $str ) . "\n" ); } function wordstr( $word ) { return sprintf( "%04x%04x", ($word >> 16) & 0xffff, $word & 0xffff ); } function print_words( $words ) { $len = sizeof( $words ); for( $i=0; $i<$len; ++$i) { $str[] = $this->wordstr( $words[$i] ); } print( join( ", ", $str ) . "\n" ); } function hash_to_string( $hash ) { $len = sizeof( $hash ); for ($i=0; $i<$len; ++$i) { $astr[] = $this->wordstr( $hash[$i] ); } return join( "", $astr ); } // Add simply adds two numbers. It is provided for compatibility on // platforms that only support a 31 bit add (there are a few, apparently) function add( $a, $b ) { $ma = ($a >> 16) & 0xffff; $la = ($a) & 0xffff; $mb = ($b >> 16) & 0xffff; $lb = ($b) & 0xffff; $ls = $la + $lb; // Carry if ($ls > 0xffff) { $ma += 1; $ls &= 0xffff; } // MS add $ms = $ma + $mb; $ms &= 0xffff; // Works because the bitwise operators are 32 bit $result = ($ms << 16) | $ls; return $result; } function process_block( $blk ) { $blk = $this->expand_block( $blk ); for( $i=0; $i<80; ++$i ) { $temp = $this->circ_shl( $this->ta, 5 ); if ($i<20) { $f = $this->f0_19( $this->tb, $this->tc, $this->td ); $k = $this->K0_19; } elseif ($i<40) { $f = $this->f20_39( $this->tb, $this->tc, $this->td ); $k = $this->K20_39; } elseif ($i<60) { $f = $this->f40_59( $this->tb, $this->tc, $this->td ); $k = $this->K40_59; } else { $f = $this->f60_79( $this->tb, $this->tc, $this->td ); $k = $this->K60_79; } $temp = $this->add( $temp, $f ); $temp = $this->add( $temp, $this->te ); $temp = $this->add( $temp, $blk[$i] ); $temp = $this->add( $temp, $k ); $this->te = $this->td; $this->td = $this->tc; $this->tc = $this->circ_shl( $this->tb, 30 ); $this->tb = $this->ta; $this->ta = $temp; } $this->A = $this->add( $this->A, $this->ta ); $this->B = $this->add( $this->B, $this->tb ); $this->C = $this->add( $this->C, $this->tc ); $this->D = $this->add( $this->D, $this->td ); $this->E = $this->add( $this->E, $this->te ); } function update ( $bytes ) { $length = sizeof( $bytes ); $index = 0; // Process each full block while (($length - $index) + $this->buffsize >= 64) { for( $i=$this->buffsize; $i<64; ++$i) { $this->buffer[$i] = $bytes[$index + $i - $this->buffsize]; } $this->process_block( $this->bytes_to_words( $this->buffer ) ); $index += 64; $this->buffsize = 0; } // Any remaining bytes that do not make up a full block need to be' // added into the buffer for the next update (or final) $remaining = $length - $index; for( $i=0; $i<$remaining; ++$i) { $this->buffer[$this->buffsize + $i] = $bytes[$index + $i]; } $this->buffsize += $remaining; $this->totalsize += $length; } function final() { // Pad and process the buffer for( $i=0; $i<$this->buffsize; ++$i) { $last_block[$i] = $this->buffer[$i]; } $this->buffsize = 0; // Pad the block $last_block = $this->pad_block( $last_block, $this->totalsize ); // Process the last one (or two) block(s) $index = 0; $length = sizeof( $last_block ); while( $index < $length ) { $block = array(); for( $i=0; $i<64; ++$i) { $block[$i] = $last_block[$i + $index]; } $this->process_block( $this->bytes_to_words( $block ) ); $index += 64; } $result[0] = $this->A; $result[1] = $this->B; $result[2] = $this->C; $result[3] = $this->D; $result[4] = $this->E; return $result; } function hash_bytes( $bytes ) { $this->init(); $this->update( $bytes ); return $this->final(); } function hash_string( $str ) { $len = strlen( $str ); for($i=0; $i<$len; ++$i) { $bytes[] = ord( $str[$i] ) & 0xff; } return $this->hash_bytes( $bytes ); } } } // If Included ?>