安全散列算法SHA1,主要用于数字签名。输入数据的最大长度为2^64,输出为160位的散列函数值。

SHA1代码:

 

  1. #include<stdio.h> 
  2. #include<stdlib.h> 
  3. #include<time.h> 
  4.  
  5. unsigned int H[5] = {0x67452301,0xefcdab89,0x98badcfe,0x10325476,0xc3d2e1f0}; 
  6. unsigned int K[4] = {0x5a827999,0x6ed9eba1,0x8f1bbcdc,0xca62c1d6}; 
  7.  
  8. unsigned int M[16]; 
  9. unsigned int W[80]; 
  10. unsigned char LastString[512/8*2];//将最后多余部分拿出,和补的位存放于此 
  11. unsigned int A,B,C,D,E; 
  12.  
  13. FILE * fp; 
  14. fpos_t pos; //文件长度 
  15. int flag ;  
  16. int LastRoundCount; 
  17.  
  18. int GetMessage(unsigned long long rLen); 
  19. void SetW(); 
  20. void Round(); 
  21.  
  22. int main(int argc, char *argv[]) 
  23.     if(argc == 1) 
  24.     { 
  25.         printf("请输入要hash的文件名!\n"); 
  26.         exit(0); 
  27.     } 
  28.     fp = fopen(argv[1],"rb"); 
  29.      
  30.     clock_t start, finish;  //计时 
  31.     start = clock();   
  32.      
  33.     fseek(fp, 0, SEEK_END); 
  34.     fgetpos(fp, &pos); 
  35.     unsigned long long realLen = pos; 
  36.      
  37.     memset(LastString,0x00,strlen(LastString)*sizeof(unsigned char));//初始化 
  38.      
  39.     int LastOut = realLen%(512/8); 
  40.     fseek(fp,-1*LastOut,SEEK_END); 
  41.      
  42.     int i; 
  43.     fread(LastString,LastOut,1,fp);//将多余部分复制到LastString 
  44.     LastString[LastOut] = 0x80;  
  45.      
  46.     LastRoundCount = 1; 
  47.     flag = 0; 
  48. //  unsigned long long copyLen = realLen<<3; 
  49.     if(LastOut <=55)            //将长度放在末尾 
  50.     { 
  51.         flag = 1; 
  52.     //  memcpy(LastString+512/8-8,&copyLen,8); 
  53.         for( i = 8; i >= 1; i--) 
  54.             LastString[512/8 - i] = (char)((realLen<<3)>>((i-1)*8));   
  55.     } 
  56.     else 
  57.     { 
  58.         flag = 2; 
  59.     //  memcpy(LastString+512/8*2-8,&copyLen,8); 
  60.         for( i = 1; i <= 8; i++) 
  61.             LastString[512/8*2 - i] = (char)((realLen<<3)>>((i-1)*8));   
  62.     } 
  63.  
  64.     realLen -= LastOut; //长度变短 
  65.  
  66.     fseek(fp,0,SEEK_SET); 
  67.      
  68.     while(GetMessage(realLen)) 
  69.     { 
  70.         SetW(); 
  71.         Round(); 
  72. //      printf("."); 
  73.     } 
  74.      
  75.     printf("SHA1:  "); 
  76.     for(i = 0 ; i < 5; i++) 
  77.         printf("%08x ",H[i]); 
  78.     printf("\n");  
  79.      
  80.     finish = clock();   
  81.     double duration = (double)(finish - start) / CLOCKS_PER_SEC;  
  82.     printf("Cal time: %f seconds\n",duration); 
  83.     fclose(fp); 
  84.     return 0; 
  85.  
  86. int GetMessage(unsigned long long rLen) 
  87.     fgetpos(fp, &pos); 
  88.  
  89.     if(pos + 16 * 4 <= rLen) 
  90.     { 
  91.         fread(M,4,16,fp);//注意M的读入,读入之后M的四个字节是反过来的,应该是编码方式的问题,big-edi和little-edi 
  92.         return 1;           //所以后面存到W时要移位操作,此处这样操作,读入速度变快 
  93.     } 
  94.      
  95.     if(LastRoundCount <= flag) 
  96.     { 
  97.         memcpy(M,(LastString+512/8*(LastRoundCount - 1)),64);//最后的一段或是两段 
  98.         LastRoundCount++; 
  99.         return 1; 
  100.     } 
  101.     else 
  102.         return 0; //false; 
  103.  
  104. void SetW() 
  105.     int index = 0; 
  106.     for(index = 0; index <=15;index++) 
  107.     {   //编码方式,M的四个字节的顺序是反过来的,将其移位 
  108.         W[index] = (M[index]>>24)|(M[index]<<24)|((M[index]&0x00ff0000)>>8)|((M[index]&0x0000ff00)<<8); 
  109.     }  
  110.  
  111.     for(index = 16;index<=79;index++) 
  112.     { 
  113.         unsigned int temp = W[index -16]^W[index - 14]^W[index - 8]^W[index - 3]; 
  114.         W[index] = (temp<<1)|(temp>>(32 -1)); 
  115.     } 
  116.  
  117. void Round() 
  118.     A = H[0]; 
  119.     B = H[1]; 
  120.     C = H[2]; 
  121.     D = H[3]; 
  122.     E = H[4]; 
  123.     int index = 0; 
  124.     unsigned int temp; 
  125.     for(index = 0;index <=79;index++) 
  126.     { 
  127.         if(index >= 0 && index <=19) 
  128.             temp = E + ((B&C)|(~B&D)) + ((A<<5)|(A>>(32-5))) + W[index] + K[0]; 
  129.         else if(index >= 20 && index <=39) 
  130.             temp = E + (B^C^D) + ((A<<5)|(A>>(32-5))) + W[index] + K[1]; 
  131.         else if(index >= 40 && index <=59) 
  132.             temp = E + ((B&C)|(C&D)|(B&D)) + ((A<<5)|(A>>(32-5))) + W[index] + K[2]; 
  133.         else if(index >= 60 && index <=79) 
  134.             temp = E + (B^C^D) + + ((A<<5)|(A>>(32-5))) + W[index] + K[3]; 
  135.  
  136.         E = D; 
  137.         D = C; 
  138.         C = (B<<30)|(B>>(32-30)); 
  139.         B = A; 
  140.         A = temp; 
  141.     } 
  142.  
  143.     H[0]+=A; 
  144.     H[1]+=B; 
  145.     H[2]+=C; 
  146.     H[3]+=D; 
  147.     H[4]+=E; 
  148.  

实验环境:gcc编译器

若使用VC++,则需将unsigned long long 替换为 unsigned __int64,输入输出函数参数可能需改变。

对于任意长度的输入,散列函数得到的输出长度是一样的,这是散列函数的特点。

微小改变带来巨大差别,这是散列函数的另一个特点。