SHA-1算法简介及JavaScript实现
一、SHA-1算法简介
消息认证作为一种重要的安全技术如今已被广泛地应用于网络信息交换领域,它的根本作用是允许通信的当事人验证所接受的消息为可信消息。如果消息、文件、文档或者其他的数据集合是真实的数据并且来自所声称的数据源,那么称这些数据集合是可信的。而在消息认证技术中通常都会用到一类特殊的数学算法-哈希算法,它占有极其重要的地位。哈希算法也即散列算法,其作用是对任何不定长的比特串(称为消息)计算出一个定长的比特串(称为消息摘要或散列值)。
目前常见的哈希算法有MD5、SHA-1和RIPEMD-160,而国内更倾向于MD5和SHA-1。就当前的情况来看,SHA-1由于其安全强度及运算效率方面的优势已经成为使用最为广泛的哈希算法了。
1.1 SHA-1算法概述
SHA-1算法由美国国家标准和技术协会(NIST)与美国国家安全局(NSA)设计,并且被美国政府采纳,成为美国国家标准。事实上SHA-1目前是全世界使用最为广泛的哈希算法,已经成为业界的事实标准。可以对长度不超过2^64比特的消息进行计算,输入以512位数据块为单位处理,产生160比特的消息摘要作为输出。该算法的处理流程大致分为5个步骤:
l 步骤1:附加填充比特。
对输入的数据进行填充,使得数据位长度对512求余的结果为448。填充比特串的最高位补一个1,其余位补0。附加填充总是要进行的,即使消息的长度满足所要求的长度。
l 步骤2:附加长度值。
将64比特加在报文后表示报文的原始长度,使报文长度为512比特的倍数。
l 步骤3:初始化MD缓存。
一个160位MD缓冲区用以保存中间和最终散列函数的结果。它可以表示为5个32位的寄存器(A,B,C,D,E)。初始化为:
A = 67452301 B = EFCDAB89 C = 98BADCFE
D = 10325476 E = C3D2E1F0
前四个与MD5相同,但存储为big-endian format。
l 步骤4:以512比特(16个字)分组处理消息。
此算法的核心就是称为压缩函数(compression function)的模块,这个模块包括4次循环,每次循环又包含20个处理步骤。4次循环具有相似的结构,但每次循环使用不同的基本逻辑函数,称为 f1,f2,f3,f4。



二、SHA-1算法的程序实现
算法采用JavaScript实现,JavaScript是一种流行的脚本语言,它是在浏览器中解释执行的,因此不需要编译。整个程序的形式是一个HTML网页文件,当打开此网页时,程序会在浏览器中解释执行。(部分参照网络源代码)
2.1 算法程序结构
整个程序由9个函数组成,分别介绍如下:
l function hex_sha1(s)
主函数根据输入的消息字符串计算消息摘要,返回十六进制表示的消息摘要。
l function core_sha1(blockArray)
计算消息摘要的核心函数,输入为已经附加填充位和附加长度值的消息。以数值数组表示,数组中的每一项均为32位bit表示的数值。输出为长度为5的数值数组,对应160位的消息摘要。
l function AlignSHA1(str)
对消息进行附加填充位和附加长度。输入为消息字符串,输出为已经附加填充位和附加长度值的消息。
l function sha1_ft(t, b, c, d)
根据t值返回相应得压缩函数中用到的f函数。
l function sha1_kt(t)
根据t值返回相应得压缩函数中用到的K值。
l function safe_add(x, y)
对输入的两个32位数值进行 mod 的加法。
l function rol(num, cnt)
对输入的32位的num二进制数进行循环左移。
l function binb2hex(binarray)
将输入的二进制数组转化为十六进制的字符串。
l function calcDigest()
根据用户输入的源消息计算消息摘要,JavaScript事件函数。
2.1 程序运行结果
用浏览器打开HTML页面,输入源消息字符串,点击计算按钮即可获得消息摘要,截图如下(图2.1):

图2.1 SHA-1程序运行结果
三、附件(SHA1算法程序源代码)
文件SHA1Test.html
<html>

<head>

<script language="JavaScript">


/**//*

* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS PUB 180-1

* By lizq

* 2006-11-11

*/


/**//*

* Configurable variables.

*/


var hexcase = 0; /**//* hex output format. 0 - lowercase; 1 - uppercase */


var chrsz = 8; /**//* bits per input character. 8 - ASCII; 16 - Unicode */



/**//*

* The main function to calculate message digest

*/

function hex_sha1(s)



{

return binb2hex(core_sha1(AlignSHA1(s)));

}




/**//*

* Perform a simple self-test to see if the VM is working

*/

function sha1_vm_test()



{

return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d";

}




/**//*

* Calculate the SHA-1 of an array of big-endian words, and a bit length

*/

function core_sha1(blockArray)



{

var x = blockArray; //append padding


var w = Array(80);

var a = 1732584193;

var b = -271733879;

var c = -1732584194;

var d = 271733878;

var e = -1009589776;


for(var i = 0; i < x.length; i += 16) //每次处理512位 16*32


{

var olda = a;

var oldb = b;

var oldc = c;

var oldd = d;

var olde = e;


for(var j = 0; j < 80; j++) //对每个512位进行80步操作


{

if(j < 16) w[j] = x[i + j];

else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);


var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),

safe_add(safe_add(e, w[j]), sha1_kt(j)));

e = d;

d = c;

c = rol(b, 30);

b = a;

a = t;

}


a = safe_add(a, olda);

b = safe_add(b, oldb);

c = safe_add(c, oldc);

d = safe_add(d, oldd);

e = safe_add(e, olde);

}

return new Array(a, b, c, d, e);


}




/**//*

* Perform the appropriate triplet combination function for the current iteration

* 返回对应F函数的值

*/

function sha1_ft(t, b, c, d)



{

if(t < 20) return (b & c) | ((~b) & d);

if(t < 40) return b ^ c ^ d;

if(t < 60) return (b & c) | (b & d) | (c & d);

return b ^ c ^ d; //t<80

}




/**//*

* Determine the appropriate additive constant for the current iteration

* 返回对应的Kt值

*/

function sha1_kt(t)



{

return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :

(t < 60) ? -1894007588 : -899497514;

}




/**//*

* Add integers, wrapping at 2^32. This uses 16-bit operations internally

* to work around bugs in some JS interpreters.

* 将32位数拆成高16位和低16位分别进行相加,从而实现 MOD 2^32 的加法

*/

function safe_add(x, y)



{

var lsw = (x & 0xFFFF) + (y & 0xFFFF);

var msw = (x >> 16) + (y >> 16) + (lsw >> 16);

return (msw << 16) | (lsw & 0xFFFF);

}




/**//*

* Bitwise rotate a 32-bit number to the left.

* 32位二进制数循环左移

*/

function rol(num, cnt)



{

return (num << cnt) | (num >>> (32 - cnt));

}




/**//*

* The standard SHA1 needs the input string to fit into a block

* This function align the input string to meet the requirement

*/


function AlignSHA1(str)
{

var nblk=((str.length+8)>>6)+1, blks=new Array(nblk*16);

for(var i=0;i<nblk*16;i++)blks[i]=0;

for(i=0;i<str.length;i++)

blks[i>>2]|=str.charCodeAt(i)<<(24-(i&3)*8);

blks[i>>2]|=0x80<<(24-(i&3)*8);

blks[nblk*16-1]=str.length*8;

return blks;

}




/**//*

* Convert an array of big-endian words to a hex string.

*/

function binb2hex(binarray)



{

var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";

var str = "";

for(var i = 0; i < binarray.length * 4; i++)


{

str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +

hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF);

}

return str;

}



/**//*

* calculate MessageDigest accord to source message that inputted

*/

function calcDigest()



{

var digestM = hex_sha1(document.SHAForm.SourceMessage.value);

document.SHAForm.MessageDigest.value = digestM;

}


</script>


<title>SHA-1算法JavaScript实现</title>


</head>


<body>

<center>

<BR/>

<BR/>

<H2>SHA-1算法JavaScript实现</H2>

<BR/>

<form name="SHAForm">

源消息:<input type="text" name="SourceMessage" size=40><BR>

消息摘要:<input type="text" name="MessageDigest" size=40>

<P>

<input type="button" value="计算消息摘要" onclick="calcDigest()">

</form>

</body>

</html>

Author: orangelizq
email: orangelizq@163.com
posted on 2007-09-30 10:46
桔子汁 阅读(5702)
评论(1) 编辑 收藏 所属分类:
Java技术