/*
Title: The Secure Hash Algorithm (SHA-1)

Category: Computer Security

Description:
	The Secure Hash Algorithm takes a message of less than 264 bits 
	in length and produces a 160-bit message digest which is designed
	so that it should be computationaly expensive to find a text which
	matches a given hash. ie if you have a hash for document A, H(A),
	it is difficult to find a document B which has the same hash, and
	even more difficult to arrange that document B says what you want
	it to say.

Notice:
	The 160-bit message digest is returned as 40 hex characters.
	Each pair represents 1 byte.

For further information on SHA, see: 
	www.asianlaws.org

*/

// global vars

// Define four constants used in the algorithm
var k = new Array(3)
k[0] = SHA1_Add(0, 0x5a827999)
k[1] = SHA1_Add(0, 0x6ed9eba1)
k[2] = SHA1_Add(0, 0x8f1bbcdc)
k[3] = SHA1_Add(0, 0xca62c1d6)

var StrHexCharacters = "0123456789abcdef" // hex characters

// -----------------------------------------------------------------------------
function SHA1_Hash(pStrMessage)
{
	  
	var W = new Array(80)

	var M = SHA1_MakeBlocks(pStrMessage)

	// Initialize 5 32-bit variables
	var A = SHA1_Add(0, 0x67452301)
	var B = SHA1_Add(0, 0xefcdab89)
	var C = SHA1_Add(0, 0x98badcfe)
	var D = SHA1_Add(0, 0x10325476)
	var E = SHA1_Add(0, 0xc3d2e1f0)

	/*
		first, the five variables are copied into different
		variables: a gets A, b gets B, c gets C, d gets D, 
		and e gets E
	*/

	var a = A
	var b = B
	var c = C
	var d = D
	var e = E
	
	/*
		The main loop processes the message 512 bits at a
		time and continues for as many 512-bit blocks as 
		are in the message.
		
		(16 bytes = 512 bits)
		
	*/
	for(var i = 0; i < M.length; i += 16)
	{
	
		for(var t = 0; t < 80; t++)
		{
			/*
				The message block is transformed from 16 32-bit words
				(M[0] to M[15]) to 90 32-bit words (W[0] to W[79]
				using the following algorithm:
			*/
			if(t < 16)
			{
				W[t] = M[i + t]
			}
			else
			{
				// t = 16 to 79
				W[t] = SHA1_LeftCircularShift(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1)
			}
			
			/*
				each operation performs a nonliniear function of three
				of a, b, c, d, and e and then does shifting and adding
				similar to MD5
			*/
			/*
				As an interesting aside, the original SHA specification
				did not have the left circular shift.  The change
				"corrects a technical flaw that made the standard less
				secure than had been thought".  The NSA has refused to
				elaborate on the exact nature of the flaw.
			*/
			temp = SHA1_Add(SHA1_Add(SHA1_LeftCircularShift(a, 5), SHA_f(t, b, c, d)), SHA1_Add(SHA1_Add(e, W[t]), SHA_K(t)))
			
			e = d
			d = c
			c = SHA1_LeftCircularShift(b, 30)
			b = a
			a = temp
		}

		/*
			After all of this, a, b, c, d, and e are added to A, B, C, D,
			and E respecitively, and the algorithm continues with the next
			block of data.
		*/
		A = SHA1_Add(a, A)
		B = SHA1_Add(b, B)
		C = SHA1_Add(c, C)
		D = SHA1_Add(d, D)
		E = SHA1_Add(e, E)
	}

	// The final output is the concatenation of A, B, C, D, and E
	return(SHA1_Hex(A) + SHA1_Hex(B) + SHA1_Hex(C) + SHA1_Hex(D) + SHA1_Hex(E))
}
// -----------------------------------------------------------------------------
function SHA1_Hex(pLngValue)
{
	var lStrHex = ''
	var lLngPositionIndex
	for(var lLngPositionIndex = 7; lLngPositionIndex >= 0; lLngPositionIndex--)
	{
		lStrHex += StrHexCharacters.charAt((pLngValue >> (lLngPositionIndex * 4)) & 0x0f)
	}
	return(lStrHex)
}
// -----------------------------------------------------------------------------
function SHA1_MakeBlocks(pStrMessage)
{
	var lLngMaxBlock = ((pStrMessage.length + 8) >> 6) + 1
	var lStrBlockAry = new Array(lLngMaxBlock * 16)
	var lLngIndex
	/*
		We convert our message into 16-word blocks
		
		1 word    =  4 bytes =  32 bits
		16 words  = 64 bytes = 512 bits
		
		This will make it easier for us to proces the data in the
		main loop.
	*/
	for(lLngIndex = 0; lLngIndex < lLngMaxBlock * 16; lLngIndex++) 
	{
		lStrBlockAry[lLngIndex] = 0
	}
	
	for(lLngIndex = 0; lLngIndex < pStrMessage.length; lLngIndex++)
	{
		lStrBlockAry[lLngIndex >> 2] |= pStrMessage.charCodeAt(lLngIndex) << (24 - (lLngIndex % 4) * 8)
	}

	/*
		First, the message is padded to make it a multiple of 512
		bits long.  Padding is exactly the same as in MD5: First
		append a one, then as many zeros as necessary to make it
		64 bits short of a multiple of 512, and finally a 64-bit
		representation of the length of the message before padding.
	*/
	
	lStrBlockAry[lLngIndex >> 2] |= 0x80 << (24 - (lLngIndex % 4) * 8)
	lStrBlockAry[lLngMaxBlock * 16 - 1] = pStrMessage.length * 8

	return(lStrBlockAry)
}
// -----------------------------------------------------------------------------
function SHA1_Add(pLngValue1, pLngValue2)
{
	/*
		Add two numbers, but allow wrapping to negative numbers
	*/
	var lLngA = (pLngValue1 & 0xFFFF) + (pLngValue2 & 0xFFFF)
	var lLngB = (pLngValue1 >> 16) + (pLngValue2 >> 16) + (lLngA >> 16)
	var lLngResult = (lLngB << 16) | (lLngA & 0xFFFF)
	return(lLngResult)
}
// -----------------------------------------------------------------------------
function SHA1_LeftCircularShift(pLngValue, pLngBits)
{
	return(pLngValue << pLngBits) | (pLngValue >>> (32 - pLngBits))
}
// -----------------------------------------------------------------------------
function SHA_f(t, x, y, z)
{
	/*
		Each operation performs a nonlinear function of three
		of a, b, c, d, and e, and then does shifting and adding
		similar to MD5
	*/

	// 0 to 19
	if(t < 20) return((x & y) | ((~x) & z))
	// 20 to 39
	if(t < 40) return(x ^ y ^ z)
	// 40 to 59
	if(t < 60) return((x & y) | (x & z) | (y & z))
	// 60 to 79
	return x ^ y ^ z
  
  }
// -----------------------------------------------------------------------------
function SHA_K(t)
{
	// 0 to 19
	if(t < 20) return(k[0])
	// 20 to 39
	if(t < 40) return(k[1])
	// 40 to 59
	if(t < 60) return(k[2])
	// 60 to 79
	return(k[3])
}
// -----------------------------------------------------------------------------
