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
桔子汁 閱讀(5713)
評論(1) 編輯 收藏 所屬分類:
Java技術