PHP Classes

File: shaobj.js

Recommend this page to a friend!
  Classes of Chris Monson   SHA   shaobj.js   Download  
File: shaobj.js
Role: ???
Content type: text/plain
Description: Pure Javascript Implementation of SHA
Class: SHA
Author: By
Last change:
Date: 24 years ago
Size: 9,947 bytes
 

Contents

Class file image Download
//////////////////////////////////////////////////////////////////////////// // 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) // March 17, 2000 // License changed (I'm an idiot) June 26, 2000 //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // USAGE: //------------------------------------------------------------------------ // // Simple text hash: // // sha = new SHA; // hasharray = sha.hash_text( '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.block_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: // I have done little optimization. Actually, I haven't done any at // all on this code. I wrote it because I wanted to do a secure // challenge response login over an insecure connection. To do that, // I needed a secure hash algorithm on the client and on the server. // JavaScript was the obvious choice for the client side code, and it // works very well for hashing things like passwords and random tokens. // It is relatively small and it runs fast enough that I don't notice // the download time nor the run time on a PII 266 over a 28.8 // connection. // // If anyone wants to make changes to this, they are, of course, // absolutely welcome to do so, provided the GPL is honored, which // includes giving the changes back to me so that I can distribute them // back to the Free Software community. // // There may be bugs in this software. If so, also let me know and // I'll happily fix them as quickly as I can. Patches are always // more welcome than criticism, of course. // //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // SHA Object //////////////////////////////////////////////////////////////////////////// function SHA () { // Set up the methods this.init = SHA_init; this.f00_19 = SHA_f00_19; this.f20_39 = SHA_f20_39_60_79; this.f40_59 = SHA_f40_59; this.f60_79 = SHA_f20_39_60_79; this.circ_shl = SHA_circ_shl; this.pad_block = SHA_pad_block; this.expand_block = SHA_expand_block; this.to_string = SHA_to_string; this.block_to_string = SHA_block_to_string; this.bytes_to_words = SHA_bytes_to_words; this.process_block = SHA_process_block; this.update = SHA_update; this.finalize = SHA_finalize; this.hash_text = SHA_hash_text; this.hash_bytes = SHA_hash_bytes; // Initialize all variables this.init(); } //////////////////////////////////////////////////////////////////////////// // SHA Implementation //////////////////////////////////////////////////////////////////////////// function SHA_init() { this.A = 0x67452301 this.B = 0xefcdab89 this.C = 0x98badcfe this.D = 0x10325476 this.E = 0xc3d2e1f0 this.a = this.A this.b = this.B this.c = this.C this.d = this.D this.e = this.E this.K0_19 = 0x5a827999 this.K20_39 = 0x6ed9eba1 this.K40_59 = 0x8f1bbcdc this.K60_79 = 0xca62c1d6 // Buffer for padding and updating this.buffer = new Array() // Current number of bytes in the buffer this.buffsize = 0 // Total size processed so far this.totalsize = 0 } function SHA_f00_19( x, y, z ) { return (x & y) | (~x & z); } function SHA_f20_39_60_79( x, y, z ) { return (x ^ y ^ z); } function SHA_f40_59( x, y, z ) { return (x & y) | (x & z) | (y & z); } function SHA_circ_shl( n, amt ) { var leftmask = 0xFFFFFFFF; leftmask <<= 32 - amt; var rightmask = 0xFFFFFFFF; rightmask <<= amt; rightmask = ~rightmask; var remains = n & leftmask; remains >>= 32 - amt; remains &= rightmask; return (n << amt) | remains; } // This padding function is limited to a size of 2^32 bits, rather than 2^64 // as dictated by the spec function SHA_pad_block( last_block, size ) { // Returns a block that is a multiple of 512 bits (64 bytes) long. // 'size' is the total number of bytes in the message var newblock = new Array() // Adds padding to a block. var blksize = last_block.length var 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. var i for (i=0; i<blksize; ++i) { newblock[i] = last_block[i] } // Add 0x80 newblock[blksize] = 0x80 // Add the zeros while ((newblock.length % 64) != 56) { newblock[newblock.length] = 0; } // Add the size (in bytes) for (i=0; i<8; ++i) { newblock[newblock.length] = (i<4) ? 0 : (bits >> ((7-i)*8)) & 0xff } return newblock } // Converts the message block of 16 words into a block of 80 words function SHA_expand_block( block ) { var nblk = new Array() var i for (i=0; i<16; ++i) { nblk[i] = block[i] } 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 SHA_to_string( val ) { var str = "" for (var i=0; i<8; ++i) { var shift = (7-i) * 4; var nibble = (val >> shift) & 0x0f str += nibble.toString( 16 ) } return str.toUpperCase() } function SHA_block_to_string( val ) { var str = "" for (var v in val) { str += this.to_string( val[v] ) } return str } // Requires the block to be 64 bytes long function SHA_bytes_to_words( block ) { var nblk = new Array() var i for (i=0; i<16; ++i) { var 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 } /* Each message block is 16 32-bit words. It is expected that the array will be of 32-bit words, not of bytes. */ function SHA_process_block( block ) { var blk = this.expand_block( block ); var i for (i=0; i<80; ++i) { with (this) { var temp = circ_shl( a, 5 ); if (i<20) { temp += f00_19( b, c, d ) + e + blk[i] + K0_19; } else if (i<40) { temp += f20_39( b, c, d ) + e + blk[i] + K20_39; } else if (i<60) { temp += f40_59( b, c, d ) + e + blk[i] + K40_59; } else { temp += f60_79( b, c, d ) + e + blk[i] + K60_79; } e = d; d = c; c = circ_shl( b, 30 ); b = a; a = temp; } } with (this) { A += a B += b C += c D += d E += e } } // Pass in a byte array, and update will call process_block as needed function SHA_update( bytes ) { // If there are bytes in the buffer and the number of bytes here // is sufficient to make a block, then process that initial block var index=0 // Process each full block while ((bytes.length - index) + this.buffsize >= 64) { // Copy the needed parts into the hash buffer for( var 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 this.buffsize = 0 } // Add the remaining bytes into the buffer var remaining = bytes.length - index for( var i=0; i<remaining; ++i) { this.buffer[this.buffsize + i] = bytes[index + i] } this.buffsize += remaining this.totalsize += bytes.length } // Finalize returns the hash value after doing things like padding function SHA_finalize() { // Clear out the hash buffer var last_block = new Array() for( var i=0; i<this.buffsize; ++i) { last_block[i] = this.buffer[i] } this.buffsize = 0 // Pad the last block last_block = this.pad_block( last_block, this.totalsize ) // Process this last piece // We do NOT call update here, since it updates the total size count, // and that is not desired. The process_block function is called // instead var index = 0 while (index < last_block.length) { this.process_block( this.bytes_to_words( last_block.slice( index, index + 64 ) ) ) index += 64 } var temp = new Array(); with (this) { temp[0] = A temp[1] = B temp[2] = C temp[3] = D temp[4] = E } return temp } function SHA_hash_bytes( bytes ) { this.init() this.update( bytes ) return this.finalize() } function SHA_hash_text( text ) { // Create a byte array from the text (chop off the MSB of each char) var bytes = new Array() for (var i=0; i<text.length; ++i) { bytes[i] = text.charCodeAt(i) & 0xff } return this.hash_bytes( bytes ) }