??When amessage of any length < 2^64 bits is input, the SHA-1 produces a 160-bit output called a message digest. (SHA-1算法輸入報文的最大長度不超過2^64位,產(chǎn)生的輸出是一個160位的報文摘要。)根據(jù)算法文檔,算法的實現(xiàn)主要由以下幾部分來組成。
RFC3174 中的第二部分,給出了一些術(shù)語,總結(jié)一下也就下面三點:
SHA-1算法把輸入消息當做 比特位字符串 來處理
輸入是按 512 位(16個字)的分組進行處理的
字 等于32位字符串,可以表示為8個十六進制數(shù)字的序列。(A word equals a 32-bit string which may be represented as a sequence of 8 hex digits. )
RFC3174 中的第三部分,給出了一些對于 字 的基本運算,總結(jié)一下:
按位邏輯字操作
X AND Y = bitwise logical “and” of X and Y.
X OR Y = bitwise logical “inclusive-or” of X and Y.
X XOR Y = bitwise logical “exclusive-or” of X and Y.
NOT X = bitwise logical “complement” of X.
X+Y定義如下:字 X 和 Y 代表兩個整數(shù) x 和y, 其中 0 <= x < 2^32 且 0 <= y < 2^32. 令整數(shù)z = (x + y) mod 2^32. 這時候 0 <= z < 2^32。將z轉(zhuǎn)換成字Z,那么就是 Z = X + Y。
#include<stdio.h>#include<string.h>#include"SHA1.h"typedefunion{unsignedchar c[64];unsignedlong l[16];} CHAR64LONG16;#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))/* blk0() and blk() perform the initial expand. *//* I got the idea of expanding during the round function from SSLeay */#ifdef LITTLE_ENDIAN#define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | (rol(block->l[i], 8) & 0x00FF00FF))#else#define blk0(i) block->l[i]#endif#define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1))/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */#define R0(v, w, x, y, z, i) \z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \w = rol(w, 30);#define R1(v, w, x, y, z, i) \z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \w = rol(w, 30);#define R2(v, w, x, y, z, i) \z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \w = rol(w, 30);#define R3(v, w, x, y, z, i) \z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \w = rol(w, 30);#define R4(v, w, x, y, z, i) \z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \w = rol(w, 30);staticvoidSHA1Transform(unsignedlong state[5],unsignedchar buffer[64]);/* Hash a single 512-bit block. This is the core of the algorithm. */staticvoidSHA1Transform(unsignedlong state[5],unsignedchar buffer[64]){unsignedlong a, b, c, d, e;CHAR64LONG16 *block;#ifdef SHA1HANDSOFFstaticunsignedchar workspace[64];block =(CHAR64LONG16 *)workspace;memcpy(block, buffer,64);#elseblock =(CHAR64LONG16 *)buffer;#endif/* Copy context-> state[] to working vars */a = state[0];b = state[1];c = state[2];d = state[3];e = state[4];/* 完成的就是RFC文檔中的H0~H4賦值給ABCDE的操作。接下來就是80輪運算的代碼。每20輪為一組,共分四組 *//* 第一組比較特殊,使用了R0和R1兩個宏函數(shù),其原因前面已經(jīng)介紹了。因為第0~15輪運算和16~79輪運算的時候消息塊M(i)和字塊W(i)的轉(zhuǎn)換是不一樣的。后面的20~39輪,40~59輪,60~79輪就是依次使用的R2,R3,R4來運算了 *//* 4 rounds of 20 operations each. Loop unrolled. */R0(a, b, c, d, e,0);R0(e, a, b, c, d,1);R0(d, e, a, b, c,2);R0(c, d, e, a, b,3);R0(b, c, d, e, a,4);R0(a, b, c, d, e,5);R0(e, a, b, c, d,6);R0(d, e, a, b, c,7);R0(c, d, e, a, b,8);R0(b, c, d, e, a,9);R0(a, b, c, d, e,10);R0(e, a, b, c, d,11);R0(d, e, a, b, c,12);R0(c, d, e, a, b,13);R0(b, c, d, e, a,14);R0(a, b, c, d, e,15);R1(e, a, b, c, d,16);R1(d, e, a, b, c,17);R1(c, d, e, a, b,18);R1(b, c, d, e, a,19);R2(a, b, c, d, e,20);R2(e, a, b, c, d,21);R2(d, e, a, b, c,22);R2(c, d, e, a, b,23);R2(b, c, d, e, a,24);R2(a, b, c, d, e,25);R2(e, a, b, c, d,26);R2(d, e, a, b, c,27);R2(c, d, e, a, b,28);R2(b, c, d, e, a,29);R2(a, b, c, d, e,30);R2(e, a, b, c, d,31);R2(d, e, a, b, c,32);R2(c, d, e, a, b,33);R2(b, c, d, e, a,34);R2(a, b, c, d, e,35);R2(e, a, b, c, d,36);R2(d, e, a, b, c,37);R2(c, d, e, a, b,38);R2(b, c, d, e, a,39);R3(a, b, c, d, e,40);R3(e, a, b, c, d,41);R3(d, e, a, b, c,42);R3(c, d, e, a, b,43);R3(b, c, d, e, a,44);R3(a, b, c, d, e,45);R3(e, a, b, c, d,46);R3(d, e, a, b, c,47);R3(c, d, e, a, b,48);R3(b, c, d, e, a,49);R3(a, b, c, d, e,50);R3(e, a, b, c, d,51);R3(d, e, a, b, c,52);R3(c, d, e, a, b,53);R3(b, c, d, e, a,54);R3(a, b, c, d, e,55);R3(e, a, b, c, d,56);R3(d, e, a, b, c,57);R3(c, d, e, a, b,58);R3(b, c, d, e, a,59);R4(a, b, c, d, e,60);R4(e, a, b, c, d,61);R4(d, e, a, b, c,62);R4(c, d, e, a, b,63);R4(b, c, d, e, a,64);R4(a, b, c, d, e,65);R4(e, a, b, c, d,66);R4(d, e, a, b, c,67);R4(c, d, e, a, b,68);R4(b, c, d, e, a,69);R4(a, b, c, d, e,70);R4(e, a, b, c, d,71);R4(d, e, a, b, c,72);R4(c, d, e, a, b,73);R4(b, c, d, e, a,74);R4(a, b, c, d, e,75);R4(e, a, b, c, d,76);R4(d, e, a, b, c,77);R4(c, d, e, a, b,78);R4(b, c, d, e, a,79);/* 完成的就是更新緩沖區(qū)H0~H4的內(nèi)容。然后把a~e清空為0 *//* Add the working vars back into context.state[] */state[0]+= a;state[1]+= b;state[2]+= c;state[3]+= d;state[4]+= e;/* Wipe variables */a = b = c = d = e =0;}/* SHA1Init - Initialize new context */voidSHA1Init(SHA1_CTX *context){/* SHA1 initialization constants */context->state[0]=0x67452301;context->state[1]=0xEFCDAB89;context->state[2]=0x98BADCFE;context->state[3]=0x10325476;context->state[4]=0xC3D2E1F0;context->count[0]= context->count[1]=0;}/* Run your data through this. */voidSHA1Update(SHA1_CTX *context,unsignedchar*data,unsignedint len){unsignedint i, j;/* j>>3獲得的就是字節(jié)數(shù),j = (j >> 3) & 63得到的就是低6位的值,也就是代表64個字節(jié)(512位)長度的消息。,因為我們每次進行計算都是處理512位的消息數(shù)據(jù)。 */j =(context->count[0]>>3)&63;/* context->count[ ]存儲的是消息的長度,超出context->count[0]的存儲范圍的部分存儲在context->count[1]中。len<<3就是len*8的意思,因為len的單位是字節(jié),而context->count[ ]存儲的長度的單位是位,所以要乘以8。 if ((context->count[0] += len << 3) < j) 的意思就是說如果加上len*8個位,context->count[0]溢出了,那么就要:context->count[1]++;進位。len<<3的單位是位,len>>29(len<<3 >>32)表示的就是len中要存儲在context->count[1]中的部分。 */if((context->count[0]+= len <<3)<(len <<3))context->count[1]++;context->count[1]+=(len >>29);/* 如果j+len的長度大于63個字節(jié),就分開處理,每64個字節(jié)處理一次,然后再處理后面的64個字節(jié),重復這個過程;否則就直接將數(shù)據(jù)附加到buffer末尾 */if((j + len)>63){memcpy(&context->buffer[j], data,(i =64- j));/* i=64-j,然后從data中復制i個字節(jié)的數(shù)據(jù)附加到context->buffer[j]末尾,也就是說給buffer湊成了64個字節(jié) */SHA1Transform(context->state, context->buffer);/* 執(zhí)行SHA1Transform()來開始一次消息摘要的計算 *//* 每64個字節(jié)處理一次 */for(; i +63< len; i +=64){SHA1Transform(context->state,&data[i]);}j =0;}else{i =0;}/* 如果前面的if不成立,那么也就是說原始數(shù)據(jù)context->buffer加上新的數(shù)據(jù)data的長度還不足以湊成64個字節(jié),所以直接附加上data就行了。相當于:memcpy(&context->buffer[j], &data[i], 0);如果前面的if成立,那么j是等于0的,而 i 所指向的偏移位置是 (└ len/64┘×64,len)之間。 └ ┘表示向下取整。*/memcpy(&context->buffer[j],&data[i], len - i);}/* Add padding and return the message digest. */voidSHA1Final(unsignedchar digest[20], SHA1_CTX *context){unsignedlong i, j;unsignedchar finalcount[8];for(i =0; i <8; i++){finalcount[i]=(unsignedchar)((context->count[(i >=4?0:1)]>>((3-(i &3))*8))&255);/* Endian independent */}/* 填充的時候是以字節(jié)為單位的,最少1個字節(jié),最多64個字節(jié)。并且第一位要填充1,后面都填充0。所以拿到一個消息我們首先要給他填充一個字節(jié)的10 000 000.SHA1Update() 函數(shù)就是完成的數(shù)據(jù)填充(附加)操作 */SHA1Update(context,(unsignedchar*)"\200 ",1);/* 循環(huán)測試數(shù)據(jù)模512是否與448同余。不滿足條件就填充全一個字節(jié)0。 *//* 使用 while ((context->count[0] & 511) != 448) 貌似更合適。但是,504后三位全0,511后三位全1。context->count中存儲的是消息的長度,它的單位是:位。前面我們提到了我們的數(shù)據(jù)是以字節(jié)來存儲的,所以context->count[ ]中的數(shù)據(jù)肯定是8個倍數(shù),所以后三位肯定是000。所以不管是000&000,還是000&111其結(jié)果都是0。 */while((context->count[0]&504)!=448){SHA1Update(context,(unsignedchar*)"\0 ",1);}/* 這將觸發(fā)SHA1Transform()函數(shù)的調(diào)用,該函數(shù)的功能就是進行運算,得出160位的消息摘要(message digest)并儲存在context-state[ ]中,它是整個SHA-1算法的核心 */SHA1Update(context, finalcount,8);/* Should cause a SHA1Transform() *//* 最后的這步轉(zhuǎn)換將消息摘要轉(zhuǎn)換成單字節(jié)序列。用代碼來解釋就是:將context-state[5]中儲存的20個字節(jié)(5×4字節(jié))的消息摘要取出,將其存儲在20個單字節(jié)的數(shù)組digest中。并且按大端序存儲(與之前分析context->count[ ]到finalcount[ ]轉(zhuǎn)換的思路相同) */for(i =0; i <20; i++){digest[i]=(unsignedchar)((context->state[i >>2]>>((3-(i &3))*8))&255);}/* Wipe variables */i = j =0;memset(context->buffer,0,64);memset(context->state,0,20);memset(context->count,0,8);memset(&finalcount,0,8);#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it 's own static vars */SHA1Transform(context->state, context->buffer);#endif}