《SHA1算法.docx》由会员分享,可在线阅读,更多相关《SHA1算法.docx(13页珍藏版)》请在三一办公上搜索。
1、SHA1算法SHA1算法实现 源码文件:main.c, SHA1.h, SHA1.c加入工程编译即可 说明:该SHA1算法是8位单片机(51内核)Keil C51纯软件实现 目 录 1 SHA1算法说明 . 3 1.1. 源码算法使用方法 . 3 2 数据类型定义 . 3 3 函数接口说明 . 3 初始化SHA1模块 . 4 3.2 分步对消息进行计算 . 4 3.3 完成杂凑计算,取结果 . 4 3.4 一次性输入,计算,取结果 . 5 源码SHA1算法例程 . 5 3.1 1 SHA1算法说明 1.1. 源码算法使用方法 算法使用方法如下: 将main.c和SHA1.c,SHA1.h加入工
2、程编译即可; 1、 2 数据类型定义 typedef unsigned char typedef singed char U8; S8; typedef unsigned int U16; typedef signed int S16; U32; typedef unsigned long typedef signed long S32; typedef struct U32 count2; U32 hash5; U32 wbuf16; SHA1_Ctx; 3 函数接口说明 SHA1算法包含的函数列表如下: 表 3-1 SHA1算法库函数表 函数 void SHA1_Init(SHA1_Ctx
3、 * ctx) void SHA1_Process(SHA1_Ctx * ctx, U8 * message, U32 len) 描述 初始化SHA1模块 分步对消息进行计算 void SHA1_Done(SHA1_Ctx * ctx, U8 * digest) void SHA1_Hash(U8 * message, U32 len, U8 * digest) 完成杂凑计算,取结果 一次性输入,计算,取结果 3.1 初始化SHA1模块 SHA1_Init 初始化SHA1模块 函数原型 void SHA1_Init(SHA1_Ctx * ctx) 参数说明 ctx 注意事项 例程 输入,分步计
4、算的SHA1_Ctx结构体指针 对一较长消息进行分步杂凑计算时都要首先调用本函数 例程 见源码。 3.2 分步对消息进行计算 SHA1_Process 分步对消息进行计算 函数原型 void SHA1_Process(SHA1_Ctx * ctx, U8 * message, U32 len) 参数说明 ctx 输入,分步计算的SHA1_Ctx结构体指针 输入,当前处理消息的指针 输入,当前处理消息的字节长度 message len 注意事项 可以将很长的待杂凑消息分成几部分,依次循环调用此函数,每次调用时message取当前部分的起始地址 例程 例程 见源码。 3.3 完成杂凑计算,取结果
5、SHA1_Done 完成杂凑计算,取结果 函数原型 参数说明 void SHA1_Done(SHA1_Ctx * ctx, U8 * digest) ctx 输入,分步计算的SHA1_Ctx结构体指针 输出,杂凑的结果 digest 注意事项 1. 在调用SHA1_Process函数将待杂凑数据输入完毕后,调用本函数计算最终的杂凑结果 2. 由于SHA1的结果是160比特,即20字节,因此digest指向的空间至少应是20字节 例程 例程 见源码。 3.4 一次性输入,计算,取结果 SHA1_Hash 一次性输入,计算,取结果 函数原型 参数说明 void SHA1_Hash(U8 * mes
6、sage, U32 len, U8 * digest) message len 输入,待处理消息的指针 输入,待处理消息的字节长度 输出,杂凑的结果 digest 注意事项 1. 调用本函数进行一次性杂凑计算,效果与完整的调用一次“初始化-分步输入杂凑数据计算-完成杂凑计算”相同 2. 由于SHA1的结果是160比特,即20字节,因此digest指向的空间至少应是20字节 例程 例程 见源码。 源码SHA1算法例程 SHA1.h #ifndef SHA1_H #define SHA1_H typedef unsigned char typedef unsigned int typedef un
7、signed long typedef unsigned short UCHAR; UINT; ULONG; USHORT; typedef unsigned char U8; typedef unsigned int U16; typedef unsigned long U32; typedef char S8 ; typedef int S16; typedef long S32; /* type to hold the SHA1 context */ typedef struct U32 count2; U32 hash5; U32 wbuf16; SHA1_Ctx; void SHA1
8、_Init(SHA1_Ctx * ctx); void SHA1_Process(SHA1_Ctx * ctx, U8 * message, U32 len); void SHA1_Done(SHA1_Ctx * ctx, U8 * digest); void SHA1_Hash(U8 * message, U32 len, U8 * digest); #endif Main.c #include #include #include #include SHA1.h /void printbuf(U8 * buf, U32 len) / / int i; / printf(rn); / for(
9、i=0;ilen;i+) / printf(%02bx,bufi); /说明:print_buf函数需要根据所用单片机来实现,主要是观察数据使用,不影响算法,故注释掉。 void main U8 xdata InBuff1024; U8 xdata OutBuff64; SHA1_Ctx xdata ctx; U32 xdata i; / printf(rn SHA1 Test Demo rn); /* Speed Test */ / the message consists of 0x5a, its byte length is 30KB for(i=0; i1024; i+) InBuff
10、i = 0x5a; SHA1_Init(&ctx); / printf( rn Speed Test Begin!); for(i=0; i30; i+) SHA1_Process(&ctx, InBuff, 1024); / printf( rn Speed Test Finished!); SHA1_Done(&ctx, OutBuff); / printbuf(OutBuff, 20); /the results should be 2c950fdbababb179b4707e2a74f29a79922e39fe /* Validity Test 1 */ / the messages
11、all consist of 0x5a, its byte length is from 1 to 136 /printf(rnrn Validity Test 1 rn); for(i=0; i136; i+) InBuffi = 0x5a; for(i=1; i137; i+) SHA1_Hash(InBuff, i, OutBuff); / printbuf(OutBuff, 20); /* Validity Test 2 */ /The message consists of 0x5a, its byte length is 132, just for example, here ar
12、e 4 cases to /compute its message digest, /and the results all should be 729a731566090c14b961f6a12ba22a64fddfb492 /printf(rnrn Validity Test 2 ); for(i=0; i136; i+) InBuffi = 0x5a; /case 1 SHA1_Hash(InBuff, 132, OutBuff); /printf(rn Case 1: ); /printbuf(OutBuff, 20); /case 2 SHA1_Init(&ctx); SHA1_Pr
13、ocess(&ctx, InBuff, 1); SHA1_Process(&ctx, InBuff+1, 2); SHA1_Process(&ctx, InBuff+3, 61); SHA1_Process(&ctx, InBuff+64, 3); SHA1_Process(&ctx, InBuff+67, 65); SHA1_Done(&ctx, OutBuff); /printf(rn Case 2: ); /printbuf(OutBuff, 20); /case 3 SHA1_Init(&ctx); SHA1_Process(&ctx, InBuff, 12); SHA1_Proces
14、s(&ctx, InBuff+12, 43); SHA1_Process(&ctx, InBuff+55, 2); SHA1_Process(&ctx, InBuff+57, 3); SHA1_Process(&ctx, InBuff+60, 71); SHA1_Process(&ctx, InBuff+131, 1); SHA1_Done(&ctx, OutBuff); /printf(rn Case 3: ); /printbuf(OutBuff, 20); /case 4 SHA1_Init(&ctx); SHA1_Process(&ctx, InBuff, 66); SHA1_Proc
15、ess(&ctx, InBuff+66, 11); SHA1_Process(&ctx, InBuff+77, 47); SHA1_Process(&ctx, InBuff+124, 8); SHA1_Done(&ctx, OutBuff); /printf(rn Case 4: ); /printbuf(OutBuff, 20); /*/ while(1); SHA1.c #include #include #include SHA1.h /SHA1算法参数 U32 code SHA1_H05 = 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476,
16、 0xc3d2e1f0; U32 code SHA1_K4 = 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6; /对32比特的变量x循环左移n比特( 芯片是大端顺序,因此可直接用 U32 类型处理 ) U32 SHA1_ROTL(U32 * x, U8 n) return (*x)(32-n); /U64类型的大数a = a + len*8; 即a表示消息的比特长度, 这里参数len = 64 void SHA1_len_add(U32 * a, U16 len) a1 += (len3); if(a1 (lencount13) & 0x3f;
17、/每64字节的消息分组,计算最终得到的 abcde void SHA1_block(SHA1_Ctx * ctx) S8 data i,j; U32 xdata SHA1_abcde5, *W, temp, temp1; /initialize abcde memcpy(SHA1_abcde, ctx-hash, 20); /80 rounds for(i=0; iwbuf + (i&15); /当前使用的Wi。 注意: i%16 = i&15 if(i 15) (*W) = (*W) ctx-wbuf(i-3)&15 ctx-wbuf(i-8)&15 ctx-wbuf(i-14)&15; (
18、*W) = SHA1_ROTL(W, 1); /compute T switch(j = i/20) case 0 : temp = (SHA1_abcde1)&(SHA1_abcde2) (SHA1_abcde1)&(SHA1_abcde3); 与上面一起 break; case 2 : temp = (SHA1_abcde1)&(SHA1_abcde2) (SHA1_abcde1)&(SHA1_abcde3) (SHA1_abcde2)&(SHA1_abcde3);与上面一起 break; default : temp = (SHA1_abcde1) (SHA1_abcde2) (SHA1
19、_abcde3); temp1=SHA1_abcde4; SHA1_abcde4 = SHA1_abcde3; SHA1_abcde3 = SHA1_abcde2; SHA1_abcde2 = SHA1_ROTL(SHA1_abcde+1, 30); SHA1_abcde1 = SHA1_abcde0; SHA1_abcde0 = (SHA1_ROTL(SHA1_abcde, 5) + temp + SHA1_Kj + (*W) + temp1); /get ctx-hash for now for(i=0; ihashi += SHA1_abcdei; /初始化操作 void SHA1_In
20、it(SHA1_Ctx * ctx) memset(ctx-count, 0, 8); memcpy(ctx-hash, SHA1_H0, 20); /分次处理连贯的消息 void SHA1_Process(SHA1_Ctx * ctx, U8 * message, U32 len) U8 data filllen, leftlen, rightlen; while(len 0) leftlen = SHA1_block_len(ctx); /目前分组已有字节长度, 也即当前消息的填充下标 rightlen = 64 - leftlen; /剩余字节长度 filllen = lenwbuf)+
21、leftlen, message, filllen); /填充 SHA1_len_add(ctx-count, filllen); /长度加 message += filllen; len -= filllen; if(!SHA1_block_len(ctx) SHA1_block(ctx); /消息输入完毕,最后结果处理 void SHA1_Done(SHA1_Ctx * ctx, U8 * digest) U8 data len; len = SHA1_block_len(ctx); /len = 消息实际长度 % 64,其值为0到63,表示剩余字节数 *(U8 xdata *)(ctx-
22、wbuf)+len) = 0x80; /开始填充 /若消息长度是64字节的整数倍, 或若剩余字节数在1和55之间,则只需本分组填充即可; /若剩余字节数在56和63之间, 本分组和下个填充分组都要处理 memset(U8 xdata *)(ctx-wbuf)+len+1, 0, len55) SHA1_block(ctx); memset(U8 xdata *)ctx-wbuf, 0, 56); memcpy(ctx-wbuf+14, ctx-count, 8); /最后的消息长度填充(8字节) SHA1_block(ctx); memcpy(digest, ctx-hash, 20); /一次性计算接口 void SHA1_Hash(U8 * message, U32 len, U8 * digest) SHA1_Ctx xdata ctx; SHA1_Init(&ctx); SHA1_Process(&ctx, message, len); SHA1_Done(&ctx, digest);