[cvs] / gkbweb / htdocs / shared / inc / sha.inc  

cvs: gkbweb/htdocs/shared/inc/sha.inc


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 :     ?>

Tobias McNulty

Powered by ViewCVS 1.0-dev
(Powered by ViewCVS)

ViewCVS and CVS Help