// *********************************************************
// Filename:	sha1.js
// Date:		2004-07-08
//
// Purpose:		Computes a 160 bits hash value using the 
//				SHA-1 hashfunction for a string of chars. 
//
// Usage:		Function hex_sha1( charstring ) returns 
//				a hash value of the original message given 
//				in the input parameter charstring.
//
// Author:		Lars-Ove Johansson
//				Magnus Persson
// 
//  ********************************************************
 

// Some messages and their representive SHA1 hash value:
// abc															a9993e364706816aba3e25717850c26c9cd0d89d
// mager														f2b986f3c7cc34b110e846721b8c5e7eda2b6356
// larsove														235a6041e7b8408b39ed37c8b90034273eb43bd8
// 235a6041e7b8408b39ed37c8b90034273eb43bd8ASHHBEJKGBQWEYYMGDF	df075156de9b64ccba0def57a8835725e18f99da

	function hex_sha1( charstring )
	{
		var hexstring;
		var intarray;

		// Converts the plaintext string to a hex string.
		hexstring = str2hex( charstring );

		// Padding to get at least a length of 64 bits (8 characters).
		hexstring = padding( hexstring );

		// To compute the digest we need to convert it to integers
		// where each integer is the result of 1 word, or 8 hexs.
		intarray = hex2intarray( hexstring );


		// Calculate the message digest.
		intarray = Calculation(intarray);

		// Convert the 5 words (=40 hexs = 160 bits) in intarray to a hexstring.
		hexstring = intarray2hexstring( intarray );

		// Return the hashed string.
		return hexstring;		
		
	}

	// Converts each character to two hexadecimal "numbers".
	function str2hex(plaintext)
	{
		var hexstring = ""

		for( var i=0; i< plaintext.length; i++)
			hexstring += int2hex( plaintext.charCodeAt(i) );

		return hexstring;	
	}

	// Converts a integer in range 0..255 to a 2 digits hex number.
	// Use integer.toString(16) instead...!!!
	function int2hex( integer )
	{
		var lookup = "0123456789abcdef";
		var ilow; var ihigh; var slow; var shigh;
	
		ilow = integer % 16;
		ihigh = (integer - ilow) / 16;
		slow = lookup.charAt(ilow);
		shigh = lookup.charAt(ihigh);

		return shigh + slow;
	}

	// Adds a padding to the message to be hashed.
	function padding( hexstring )
	{
		// The last 64 bits or 16 hexs should tell the length of the original hexstring.
		// The first bit in the padding should be a 1 and the rest up to bit number 
		// 448 or hex number 112 should be 0.

		var ilength;
		var hlength;
		var zeros;

		// Gets the length in bits of the original hexstring.
		ilength = hexstring.length * 4;
		hlength = ilength.toString(16);

		// Adds the first zeros in the hex value of the length.
		while( hlength.length < 16 )
			hlength = '0' + hlength;

		// Counts the number of bits we need to use to get a message with 
		// a length that is a multiple of 512 and where the 64 bits reserved 
		// for the original message length will fit. Then we calculate the 
		// number of zeros we need to add to get this number of bits.
		zeros = (((ilength+64)-(ilength+64)%512)+512-64-ilength - 8)/4;
		
		// Adds the first 1 and the following 0:s
		hexstring += '8';
		for( var i=0; i<zeros; i++ )
			hexstring += '0';

		// Add the length at the end of the block.
		hexstring += hlength;
		return hexstring;
	}

	// Converts a string of words (8 hexs) to an array of integers.
	function hex2intarray( hexstring )
	{
		// Create an array with room for every word.
		var length = hexstring.length;
		var intarray = new Array(Math.floor(length/8));

		// Converts each block of 8 hexs to one decimal number 
		// and put this in the array.
		for(var i=0; i<length; i+=8)
			intarray[i/8] = parseInt( hexstring.substring(i,i+8), 16 );

		return intarray;
	}

	// The f-function specified by the SHA-1 standard.
	function f(t,B,C,D)
	{
		if(t < 20) 
			return (B & C) | ((~B) & D);
		else if(t < 40) 
			return B ^ C ^ D;
		else if(t < 60) 
			return (B & C) | (B & D) | (C & D);
		else
			return B ^ C ^ D;
	}

	// The constants specified for each t-value.
	function K(t)
	{
		if(t < 20)
			return 1518500249;
		else if(t < 40) 
			return 1859775393;
		else if(t < 60) 
			return -1894007588;
		else
			return -899497514;
	}

	// Calculate the message digest as specified in the SHA-1 standard.
	function Calculation(X)
	{
		var A;var B; var C; var D; var E; var TEMP;
		var H=new Array(1732584193,-271733879,-1732584194,271733878,-1009589776);
		var W = new Array(80);

		// Do the calculation on each block of 16 integers = 128 hexs = 512 bits;
		for(var j=0;j<X.length;j+=16)
		{
			// The first 16 integers should be the integers values for the original
			// padded message string.
			for( var i=0;i<16;i++)
				W[i] = X[i + j];

			for( var t=16; t<80; t++)
				W[t] = rol(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);  
		
			A = H[0];B = H[1];C = H[2];D = H[3];E = H[4];

			for( var t=0; t<80; t++)
			{
				TEMP = safe_add(safe_add(safe_add(safe_add(rol(A,5), f(t,B,C,D)), E), W[t]), K(t));
				
				E = D; 
				D = C; 
				C = rol(B,30); 
				B = A; 
				A = TEMP;		
			}	
			
			H[0] = safe_add(H[0], A); 
			H[1] = safe_add(H[1], B); 
			H[2] = safe_add(H[2], C); 
			H[3] = safe_add(H[3], D);
			H[4] = safe_add(H[4], E);
		}

		return H;
	}

	// Bitwise rotate left in a given number of steps.
	function rol(integer, steps)
	{
		return (integer << steps) | (integer >>> (32 - steps));
	}

	// Converts an array of integers to a hexstring.
	function intarray2hexstring(intarray)
	{
		var lookup = "0123456789abcdef";
		var hexstring = "";
		for(var i = 0; i < intarray.length * 4; i++)
			hexstring += lookup.charAt( (intarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF ) + lookup.charAt( (intarray[i>>2] >> ((3 - i%4)*8 )) & 0xF );

		return hexstring;
	}

	// In Safari adding big integers will fail, so lets use this fix from pajhome.org.
	function safe_add(x, y)
	{
		var lsw = (x & 0xFFFF) + (y & 0xFFFF);
		var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
		return (msw << 16) | (lsw & 0xFFFF);	
	}

