/*
	Calcurate SHA-1 Hash JavaScript

  	sha1hash.js

	Written by:	Takashi Miyagi

	Copyright (c) 2004 Technoworks Co., Ltd. All rights reserved.

	Last update:	2004/05/14
*/

var	H_VAL = new Array(
				0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0
			);
var	K_VAL = new Array(
				0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6
			);

var	H_WK_VAL = new Array(5);

var DataBuf;

/* 32bit rotate left */
function rotate_left32(val, bits)
{
	var	v1, v2;

	v1 = val << bits;
	v2 = val >>> (32 - bits);

	return (v1 | v2);
}

function word32_to_str(val)
{
	var	val_str = "";

	val_str += String.fromCharCode((val >>> 24) & 0xff);
	val_str += String.fromCharCode((val >>> 16) & 0xff);
	val_str += String.fromCharCode((val >>> 8) & 0xff);
	val_str += String.fromCharCode(val & 0xff);

	return val_str;
}

function str_to_word32(str)
{
	var	val = 0;

	val = str.charCodeAt(0) << 24;
	val |= str.charCodeAt(1) << 16;
	val |= str.charCodeAt(2) << 8;
	val |= str.charCodeAt(3);

	return val;
}


/* padding input string */
function sha1_str_padding(instr)
{
	var	inplen, padlen, modlen;
	var	inpbits;
	var	lenstr;
	var	i, idx;
	var	low, high;

	inplen = instr.length;

	DataBuf = instr;

	modlen = inplen % 64;

	if (modlen < 56) {
		padlen = 56 - modlen;
	} else {
		padlen = 64 - (modlen - 56);
	}
	if (padlen > 0) {
		DataBuf += "\x80";
		padlen--;
		while (padlen) {
			DataBuf += "\x00";
			padlen--;
		}
	}
	low = 0;
	high = 0;
	for (i = 0; i < inplen; i++) {
		low += 8;
		if (low <= 0) {
			high++;
			low = 0;
		}
	}
	lenstr = word32_to_str(high);
	lenstr += word32_to_str(low);

	DataBuf += lenstr;

	return (inplen + padlen + 8);
}

function f(t, b, c, d)
{
	var	val;

	if (0 <= t && t < 20) {
		val = (b & c) | ((~b) & d);
	} else if (20 <= t && t < 40) {
		val = b ^ c ^ d;
	} else if (40 <= t && t < 60) {
		val = (b & c) | (b & d) | (c & d);
	} else {
		val = b ^ c ^ d;
	}
	return val;
}

// 64byte(512bit) block function
function sh1_proc(instr)
{
	var	t, idx;
	var a, b, c, d, e;
	var	temp;
	var	str;
	var	w = new Array(80);

	for (t = 0; t < 16; t++) {
		idx = t * 4;
		str = instr.substring(idx, idx + 4);
		w[t] = str_to_word32(str);
		
	}
	for (t = 16; t < 80; t++) {
		w[t] = rotate_left32(w[t-3] ^ w[t-8] ^ w[t-14] ^ w[t-16], 1);
	}
	a = H_WK_VAL[0];
	b = H_WK_VAL[1];
	c = H_WK_VAL[2];
	d = H_WK_VAL[3];
	e = H_WK_VAL[4];

	for (t = 0; t < 80; t++) {
		idx = parseInt(t / 20);
		temp = rotate_left32(a, 5) +
						f(t, b, c, d) + e + w[t] + K_VAL[idx];
		e = d;
		d = c;
		c = rotate_left32(b, 30);
		b = a;
		a = temp;
	}
	H_WK_VAL[0] += a;
	H_WK_VAL[1] += b;
	H_WK_VAL[2] += c;
	H_WK_VAL[3] += d;
	H_WK_VAL[4] += e;
}

// String SHA-1 Hash Value (160bit)
function sha1hash(instr)
{
	var	len, i, j, k;
	var	str;
	var outstr = "";

	for (i = 0; i < 5; i++) {
		H_WK_VAL[i] = H_VAL[i];
	}
	// padding input string
	len = sha1_str_padding(instr);

	for (i = 0; i < len; i += 64) {
		str = DataBuf.substring(i, i + 64);
		sh1_proc(str);
	}
	outstr = word32_to_str(H_WK_VAL[0]);
	outstr += word32_to_str(H_WK_VAL[1]);
	outstr += word32_to_str(H_WK_VAL[2]);
	outstr += word32_to_str(H_WK_VAL[3]);
	outstr += word32_to_str(H_WK_VAL[4]);

	return outstr;
}

// SHA-1 Hash (160bits) Hex Str
function sha1hash_hexstr(instr)
{
	var hash_val = "";
	var	hex_str = "";
	var i;
	var	c;
	var s;

	hash_val = sha1hash(instr);

	for (i = 0; i < 20; i++) {
		c = hash_val.charCodeAt(i);
		s = c.toString(16);
		if (s.length < 2) {
			hex_str += "0";
		}
		hex_str += s;
	}
	return hex_str;
}
