无线局域网产品使用的SMS4密码算法

本算法是一个分组算法。该算法的分组长度为128比特,密钥长度为128比特。加密算法与密钥扩展算法都采用32轮非线性迭代结构。解密算法与加密算法的结构相同,只是轮密钥的使用顺序相反,解密轮密钥是加密轮密钥的逆序。
实验环境 
代码:
 
  1. #include<stdio.h> 
  2. #include<stdlib.h> 
  3. #include<string.h> 
  4.  
  5. const int TextNum = 4;//分组长度4*32 
  6. const int KeyNum = 32;//轮密钥的个数 
  7. const int RoundNum = 32;//轮数 
  8.  
  9. //const int DECRYPT = 1; 
  10. //unsigned int plain_text[TextNum]; 
  11. unsigned int X[TextNum]={0};//明文 
  12.  
  13. unsigned int Y[TextNum]={0};//密文 
  14. unsigned int MK[TextNum]={0};//密钥 
  15. unsigned int K[36]={0};//中间结果 
  16. unsigned int key[KeyNum]={0};//轮密钥 
  17. //刚开始将key放在了X与Y之间,貌似发生了内存的覆盖, 
  18. //计算了一次后保存的key,在后面没有操作,结果其值竟然发生了改变, 
  19. //而换了个地方之后,就没有这个问题了 
  20.  
  21. unsigned int S_Box_Table[16][16] = { 
  22. {0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x5}, 
  23. {0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x4,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x6,0x99}, 
  24. {0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0xb,0x43,0xed,0xcf,0xac,0x62}, 
  25. {0xe4,0xb3,0x1c,0xa9,0xc9,0x8,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6}, 
  26. {0x47,0x7,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8}, 
  27. {0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0xf,0x4b,0x70,0x56,0x9d,0x35}, 
  28. {0x1e,0x24,0xe,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x1,0x21,0x78,0x87}, 
  29. {0xd4,0x0,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x2,0xe7,0xa0,0xc4,0xc8,0x9e}, 
  30. {0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1}, 
  31. {0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3}, 
  32. {0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0xd,0x53,0x4e,0x6f}, 
  33. {0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x3,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51}, 
  34. {0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8}, 
  35. {0xa,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0}, 
  36. {0x89,0x69,0x97,0x4a,0xc,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x9,0xc5,0x6e,0xc6,0x84}, 
  37. {0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48}}; 
  38.  
  39. unsigned int FK[TextNum] = {0xA3B1BAC6,0x56AA3350,0x677D9197,0xB27022DC}; 
  40. unsigned int CK[RoundNum] = { 
  41. 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 
  42. 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, 
  43. 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 
  44. 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, 
  45. 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 
  46. 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, 
  47. 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 
  48. 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279}; 
  49.  
  50. void encrypt();//加、解密 
  51. unsigned int T(unsigned int A); 
  52. void S_Box( unsigned int &A, unsigned int &B);//S盒置换 
  53. void genKeys(char type);//密钥编排 
  54. unsigned int T2(unsigned int A); 
  55. void getMessage(int &flag);//读入文件 
  56. int comp_diff(unsigned int A,unsigned int B, int len);//比较A和B得到不同bit的个数 
  57.  
  58. FILE *fp; 
  59.  
  60. int main(int argc, char *argv[]) 
  61.     char mode; 
  62.     char filename[256]; 
  63.     unsigned char keyString[20]; 
  64.     if(argc == 1) 
  65.     { 
  66.         printf("参数个数有错误!程序需在控制台下运行\n"); 
  67.         printf("假设生成的可执行文件为sms4.exe\n"); 
  68.         printf("考虑加解密时,输入的是ASCII字符串,十六进制仅作样例\n"); 
  69.         printf("样例测试请输入:sms4 s\n"); 
  70.         printf("加密e.txt,使用密钥1234567890abcdef,输入:sms4 e e.txt 1234567890abcdef\n"); 
  71.         printf("解密ESe.txt,使用密钥1234567890abcdef,输入:sms4 d ESe.txt 1234567890abcdef\n"); 
  72.         exit(0); 
  73.     }  
  74.     mode = *argv[1]; 
  75.     if(mode!='s'
  76.     {        
  77.         if(argc != 4) 
  78.         { 
  79.             printf("参数有错误!\n"); 
  80.             exit(0); 
  81.         } 
  82.         strcpy(filename,argv[2]); 
  83.         if(strlen(argv[3])!= 16) 
  84.         { 
  85.             printf("密钥长度不正确!"); 
  86.             exit(0); 
  87.         } 
  88.         strcpy((char *)keyString,argv[3]); 
  89.          
  90.         if((fp=fopen(filename,"rb")) == NULL) 
  91.         { 
  92.             printf("文件无法打开"); 
  93.             exit(0); 
  94.         } 
  95.          
  96.         int inc = 0,index = 0; 
  97.         for(index =0 ; index < 4; index++) 
  98.         { 
  99.             MK[index] = 0 ; 
  100.             for(inc = 0 ;inc < 4; inc++) 
  101.                 MK[index] |= (((unsigned int)keyString[index * 4 + inc])<<((3-inc)<<3)); 
  102.         } 
  103.         FILE *fpOut; 
  104.         char fileOut[200]; 
  105.         if(mode == 'e'
  106.             strcat(strcpy(fileOut,"ES\0"),filename); 
  107.         else 
  108.             strcat(strcpy(fileOut,"DS\0"),filename+2); 
  109.         fpOut= fopen(fileOut,"wb"); 
  110.         int flag = 1;//判断是否结束的标志 
  111.         genKeys(mode);//生成密钥序列 
  112.         while(flag) 
  113.         {    
  114.             getMessage(flag); 
  115.             if(flag == 0) 
  116.                 break
  117.              
  118.             encrypt();//加密或解密 
  119.             for(index = 0 ; index < 4; index++) 
  120.             { 
  121.                 Y[index] = (Y[index]>>24)|((Y[index]&0x00ff0000)>>8)|((Y[index]&0x0000ff00)<<8)|((Y[index]&0x000000ff)<<24); 
  122.                 fwrite(Y + index,1 , 4 ,fpOut); 
  123.             } 
  124.         } 
  125.         if(mode == 'e'
  126.             printf("加密完成,密文已输出到%s中\n",fileOut); 
  127.         else 
  128.             printf("解密完成,明文已输出到%s中\n",fileOut); 
  129.         fclose(fp); 
  130.         fclose(fpOut); 
  131.     } 
  132.     else        //实际测试时,样例测试这部分没用,应该删除 
  133.     { 
  134.         printf("样例测试,显示为16进制:\n"); 
  135.         X[0] = 0x01234567; 
  136.         X[1] = 0x89abcdef; 
  137.         X[2] = 0xfedcba98; 
  138.         X[3] = 0x76543210; 
  139.         printf("明文:%08x %08x %08x %08x\n",X[0],X[1],X[2],X[3]); 
  140.         MK[0] = 0x01234567; 
  141.         MK[1] = 0x89abcdef; 
  142.         MK[2] = 0xfedcba98; 
  143.         MK[3] = 0x76543210; 
  144.         printf("密钥:%08x %08x %08x %08x\n",MK[0],MK[1],MK[2],MK[3]); 
  145.         genKeys('e'); 
  146.         encrypt(); 
  147.         printf("加密一次,密文:%08x %08x %08x %08x\n",Y[0],Y[1],Y[2],Y[3]); 
  148.          
  149.         int index = 0 ; 
  150.         for (index = 0; index < 1000000; index++) 
  151.         {    
  152.             encrypt(); 
  153.             X[0] = Y[0]; 
  154.             X[1] = Y[1]; 
  155.             X[2] = Y[2]; 
  156.             X[3] = Y[3]; 
  157.         } 
  158.         printf("相同密钥加密百万次,密文:%08x %08x %08x %08x\n",Y[0],Y[1],Y[2],Y[3]); 
  159.          
  160.         printf("*****************************************************************\n"); 
  161.         X[0] = 0x01234567; 
  162.         X[1] = 0x89abcdef; 
  163.         X[2] = 0xfedcba98; 
  164.         X[3] = 0x76543210; 
  165.         printf("明文:%08x %08x %08x %08x\n",X[0],X[1],X[2],X[3]); 
  166.         int index_i = 0, index_j = 0; 
  167.         unsigned int con = 0x01; 
  168.         unsigned int cipher[TextNum] = {Y[0],Y[1],Y[2],Y[3]}; 
  169.         unsigned int count_diff_sum = 0; 
  170.         unsigned int diff = 0; 
  171.         for(index_i = 0; index_i < 4; index_i++) 
  172.         { 
  173.             for(index_j = 31 ; index_j >= 0 ; index_j--)//原来有问题 
  174.             { 
  175.                 X[index_i] ^= (con << index_j); 
  176.                 encrypt(); 
  177.                 int index_t = 0; 
  178.                 for(index_t = 0; index_t < 4; index_t++) 
  179.                 { 
  180.                     diff = comp_diff(cipher[index_t],Y[index_t],32); 
  181.                     printf("%d ",diff); 
  182.                     count_diff_sum += diff; 
  183.                 } 
  184.                 X[index_i] ^= (con << index_j); 
  185.             } 
  186.             printf("\n"); 
  187.         } 
  188.         printf("明文输入改变1位,密文输出平均改变 %d 位(十进制)\n",count_diff_sum/128); 
  189.          
  190.         printf("*****************************************************************\n"); 
  191.         unsigned int S_in = X[2]&0x000000ff; 
  192.         printf("S box输入为%x \n", S_in); 
  193.         unsigned int S_out = 0; 
  194.         unsigned int S_ans = 0; 
  195.         S_Box(S_in,S_ans); 
  196.         S_ans &= 0x000000ff; 
  197.         printf("S box输出为%x \n", S_ans); 
  198.         count_diff_sum = 0; 
  199.         diff = 0; 
  200.         for(index_j = 7 ; index_j >= 0 ; index_j--) 
  201.         { 
  202.             S_in ^= (con << index_j); 
  203.             S_Box(S_in,S_out); 
  204.             S_out &= 0x000000ff; 
  205.             diff = comp_diff(S_out,S_ans,8); 
  206.             printf("%d ",diff); 
  207.             count_diff_sum += diff; 
  208.             S_in ^= (con << index_j); 
  209.         } 
  210.         printf("\nS盒输入改变1位,S盒输出平均改变 %d 位(十进制)\n",count_diff_sum/8); 
  211.          
  212.         printf("*****************************************************************\n"); 
  213.         S_in = X[1]; 
  214.         printf("L 输入为%08x \n", S_in); 
  215.         S_out = 0; 
  216.         S_ans = 0; 
  217.         S_ans = (S_in ^ ((S_in<<2)|(S_in>>30))^((S_in<<10)|(S_in>>22))^((S_in<<18)|(S_in>>14))^((S_in<<24)|(S_in>>8))); 
  218.         printf("L 输出为%08x \n", S_ans); 
  219.         count_diff_sum = 0; 
  220.         diff = 0; 
  221.         for(index_j = 31 ; index_j >= 0 ; index_j--) 
  222.         { 
  223.             S_in ^= (con << index_j); 
  224.             S_ans = (S_in ^ ((S_in<<2)|(S_in>>30))^((S_in<<10)|(S_in>>22))^((S_in<<18)|(S_in>>14))^((S_in<<24)|(S_in>>8))); 
  225.          
  226.             diff = comp_diff(S_out,S_ans,32); 
  227.             printf("%d ",diff); 
  228.             count_diff_sum += diff; 
  229.              
  230.             S_in ^= (con << index_j); 
  231.         } 
  232.         printf("\nL 输入改变1位,L 输出平均改变 %d 位(十进制)\n",count_diff_sum/32); 
  233.          
  234.         printf("*****************************************************************\n"); 
  235.         S_in = X[1]&0x000000ff; 
  236.         printf("S_box 输入为%x \n", S_in); 
  237.         S_ans = S_in; 
  238.         S_out = 0; 
  239.         index_i = 0; 
  240.         for(index_i = 0; index_i < 1000000; index_i++) 
  241.         { 
  242.             S_Box(S_in,S_out); 
  243.             S_out &= 0x000000ff; 
  244.             if(S_out == S_ans) 
  245.             { 
  246.                 printf("连续施加S盒变换,变换 %d 次时出现输出等于输入(十进制)\n", index_i+1); 
  247.                 break
  248.             } 
  249.             else 
  250.                 S_in = S_out; 
  251.         } 
  252.         if(index_i == 1000000) 
  253.             printf("连续施加S盒变换,变换 %d 次也没有出现输出等于输入,应该为无穷多次\n", index_i); 
  254.         return 0; 
  255.     } 
  256.     return 0; 
  257.  
  258. int comp_diff(unsigned int A,unsigned int B, int len)//统计两个int型的不同的bit的个数,len为统计的长度 
  259.     unsigned int C = A^B; 
  260.     int index = 0,ans = 0; 
  261.     unsigned int con = 0x01; 
  262.     for(index = 0; index < len ; index++ ) 
  263.     { 
  264.         if(C&(con << index)) 
  265.             ans++; 
  266.     } 
  267.     return ans; 
  268.  
  269. void getMessage(int &flag)//读取输入 
  270.     memset(X,0,sizeof(X)); 
  271.     int inflag = 1; 
  272.     int index = 0; 
  273.     while(inflag && index < 4) 
  274.     { 
  275.         X[index] = 0; 
  276.         inflag = fread((void *)(X + index),1,4,fp); 
  277.         if(index == 0 && inflag == 0) 
  278.             flag = 0; 
  279.         index++; 
  280.     } 
  281.      
  282.     for(index = 0 ; index < 4; index++) 
  283.     { 
  284.         X[index] = (X[index]>>24)|((X[index]&0x00ff0000)>>8)|((X[index]&0x0000ff00)<<8)|((X[index]&0x000000ff)<<24); 
  285.     } 
  286.  
  287. void encrypt()//加密或解密 
  288.     int index = 0; 
  289.     for(index = 0 ; index < RoundNum; index++) 
  290.     { 
  291.         X[index + 4] = (X[index]^T(X[index+1]^X[index+2]^X[index+3]^key[index])); 
  292.     } 
  293.     Y[0] = X[35]; 
  294.     Y[1] = X[34]; 
  295.     Y[2] = X[33]; 
  296.     Y[3] = X[32]; 
  297.  
  298. unsigned int T(unsigned int A) 
  299.     unsigned int B,C; 
  300.     S_Box(A, B); 
  301.     C = (B ^ ((B<<2)|(B>>30))^((B<<10)|(B>>22))^((B<<18)|(B>>14))^((B<<24)|(B>>8))); 
  302.     return C; 
  303. void S_Box( unsigned int &A, unsigned int &B)//S box置换 
  304.     int index = 3; 
  305.     unsigned short Temp = 0; 
  306.     unsigned int ans = 0; 
  307.     B = 0; 
  308.     for (index = 3 ; index >= 0; index--) 
  309.     { 
  310.         Temp = (A>>(index<<3))&0x00ff; 
  311.         ans = (unsigned short)S_Box_Table[Temp>>4][Temp&0x0f]; 
  312.         B|=(ans<<(index<<3)); 
  313.     } 
  314.  
  315. void genKeys(char type)//密钥编排 
  316.     K[0] = MK[0]^FK[0]; 
  317.     K[1] = MK[1]^FK[1]; 
  318.     K[2] = MK[2]^FK[2]; 
  319.     K[3] = MK[3]^FK[3]; 
  320.     int index = 0 ; 
  321.     for ( index = 0 ; index < RoundNum; index++) 
  322.     { 
  323.         K[index + 4] = K[index] ^ T2(K[index+1]^K[index+2]^K[index+3]^CK[index]); 
  324.         key[index] = K[index + 4]; 
  325.     } 
  326.     if(type == 'd')//解密时,将密钥反序 
  327.     { 
  328.         unsigned int Temp = 0 ; 
  329.         for (index = 0 ; index < RoundNum/2; index++) 
  330.         { 
  331.             Temp = key[index]; 
  332.             key[index] = key[31 - index]; 
  333.             key[31 - index] = Temp; 
  334.         } 
  335.     } 
  336.     // for( index =0 ;index < RoundNum; index++) 
  337.         // printf("%0x ", key[index]); 
  338.     // printf("\n"); 
  339. unsigned int T2(unsigned int A) 
  340.     unsigned int B,C; 
  341.     S_Box(A, B); 
  342.     C = (B ^ ((B<<13)|(B>>19))^((B<<23)|(B>>9))); 
  343.     //优先级,||与|是不同的 
  344.     return C; 
程序在命令行下运行