SMS4分組加密體制的分析及其實現(xiàn)

SMS4是國內公布的無線局域網(wǎng)分組加密算法,由于其安全性高、加密速度快的優(yōu)點,經常被應用到社會的各個領域。下面我就給大家介紹一下這種分組加密算法。

一、SMS4加密算法簡介

分組加密算法SMS4的分組長度為128比特,密鑰長度為128比特。加密算法與密鑰擴展算法都采用32輪非線性迭代結構。解密過程與加密過程的結構相似,只是輪密鑰的使用順序相反。SMS4算法將明文和密文均看成4個32比特字,即明文(X0,X1,X2,X30∈(Z2324,密文(Y0,Y1,Y2,Y3)∈(Z2324,各輪子密鑰為一個32比特字:rki∈Z232(i=1,2,...,31)。輪函數(shù)F作用于前4輪的輸出結果Xi,Xi+1,Xi+2,Xi+3和當前子密鑰rki,輸出一個32比特字Xi+4=F(Xi,Xi+1,Xi+2,Xi+3,rki),Xi+T,Xi+1+Xi+2+Xi+3+rki)(i=1,2,...,31)。最后4輪輸出的逆序作為密文(Y0,Y1,Y1,Y2)=R(X32,X33,X34,X35)=(X35,X34,X33,X32),其中R為反序變換。

輪函數(shù)中使用的子密鑰由主密鑰

MK=(MK0,MK1,MK2,MK3)、系統(tǒng)參數(shù)FK=(FK0,F(xiàn)K1,F(xiàn)K2,F(xiàn)K3)和固定參數(shù)CKi(i,0,1,...,31)根據(jù)以下密鑰擴展算法生成(FKi,CKi均為32比特字):

首先,(K0,K1,K2,K3,...,MK0+FK0,MK1+FK1,MK2+FK2,MK3+FK3);

然后,對于i=0,1,...,31,rki=Ki+4=F′(Ki=Ki+1=Ki+2=Ki+3=CKi)=Ki+T′(Ki=1+Ki+2+Ki=3+CKi)。

不難看到,密鑰擴展算法結構F′與加密算法輪函數(shù)結構F相似,只是其中的T′置換與T置換變換略有不同。輪函數(shù)F中Z232→Z232上的可逆置換T由非線性變換τ和線性變換L復合而成,即T(·)=L(τ(·)),τ由4個并行S盒構成,τ(a0,a1,a2,a3)=(Sbox(a0),Sbox(a1),Sbox(a2),Sbox(a3))=(b0,b1,b2,b3)(ai,bi∈Z28);L對τ的輸出B∈Z232實施移位和異或操作:L(B)=B+(B<<<2)+(B<<<10)+(B<<<18)+(B<<<24)=C,B=b0b1b2b3。而密鑰擴展算法的可逆置換T′由同樣的非線性變換τ和簡化的線性變換L′(B)=B+(B<<<13)+(B<<<23)復合而成。

二、SMS4算法的代碼實現(xiàn)

本文采用C++編寫SMS4算法的程序:

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

SMS4體制的安全性在于S盒的設置,S盒是分組密碼中的重要組成部分,是大多數(shù)分組密碼中唯一的非線性結構,在很大程度上決定分組密碼的安全性。通過分析,SMS4加密算法S盒擁有一些較好的安全特性。

小知識之分組加密

分組密碼是將明文消息編碼表示后的數(shù)字(簡稱明文數(shù)字)序列,劃分成長度為n的組(可看成長度為n的矢量),每組分別在密鑰的控制下變換成等長的輸出數(shù)字(簡稱密文數(shù)字)序列。