SM4分组密码算法

一:SM4概念

  • SM4分组密码算法,原名SMS4,是国家密码管理局于2012年发布的密码行业标准之一(http://www.gb688.cn/bzgk/gb/newGbInfo?hcno=7803DE42D3BC5E80B0C3E5D8E873D56A)。与DES和AES算法类似,SM4算法是一种分组密码算法。其分组长度为128bit,密钥长度也为128bit。加密算法与密钥扩展算法均采用32轮非线性迭代Feistel结构,以字(32位)为单位进行加密运算,每一次迭代运算均为一轮变换函数F。SM4算法加/解密算法的结构相同,只是使用的轮密钥相反,其中解密轮密钥是加密轮密钥的逆序。

二:名词解释

1:分组密码

  • 分组密码是将明文消息编码后的数字序列划分成长为N的分组,分别在密钥K=(k0,k1,k2 ……)的控制下变换成等长的数字序列(序列长为M,输入分组长度和输出分组长度可以不等)。

2:代换

  • 为保证加解密运算可逆,明文的每个分组在特定的加密算法作用之后应当产生唯一的密文分组,明文分组到密文分组之间的可逆变换称为代换。

3:S 盒

  • 如果明文和密文分组的长都为N比特,则每个明文分组都对应着2N种可能的取值,不同可逆代换的个数为(2N)!个,这也意味着密钥的长度为(2^N)!比特。从实际的角度来看,分组长度很大的可逆代换是不现实的,如果分组太小,又不能满足算法的安全性能。
  • 因此实际中常将分组分为较小的子段,可将长度为N的序列的代换拆分成m个较小的子代换,每个子代换称为代换盒,简称S盒或Sbox。SM4算法中,S盒的长度为8bit。

4:Feistel加密结构

  • Feistel加密算法的输入是长为2w的明文和一个密钥K=(K1,K2…,Kn)。将明文分组分成左右两半L和R,然后进行n轮迭代,迭代完成后,再将左右两半合并到一起以产生密文分组。其第i轮迭代的函数为:Li=Ri-1,Ri=Li-1+F(Ri-1,Ki)其中Ki是第i轮的子密钥,“+”表示异或运算,F表示轮函数。一般地,各轮的子密钥彼此各不相同,且轮函数F也各不相同。代换过程完成后,在交换左右两半数据,这一过程称为置换。
    在这里插入图片描述
    使用上述Feistel结构的密码有几个值得注意的特点:
  • 轮函数相对简单,需要将它迭代多轮,典型地,4、8、16和32轮较为常见。
  • 最重要的部分是加密和解密可以使用同样的结构:轮函数为这两种运 算的主体(加密和解密也可能有更多的区别。如,一些Feistel结构的密码对其初始轮和末尾轮有不同的形式,比如初始置换和末尾置换不同)。
  • 轮函数可以为非线性和不可逆的。在许多密码中,例如Caesar密码,核心函数都必须可逆:我们由此才能反过来解密。但是,对于Feistel结构的密码,我们不需要计算轮函数的逆。通常地,轮函数是置换、替代和其他函数的乘积密码。
  • 由于它只对一半比特进行运算,因而使用轮函数肯定能节约时间和空间,因此必须考虑–些问题:轮函数作用于一半比特,采用暴力破解需尝试的比特位更少。此外,由于轮函数的安全性决定了算法的安全性,它必须有足够的强度。

5 IV:初始化向量

三:SM4算法实现

1:SM4密码算法整体程序框图如下:
在这里插入图片描述
将数据分组生成明文,密钥通过多次轮函数迭代生成密文。

2 :SM4算法结构图:
在这里插入图片描述

3:参数产生
(1)字节由8位2进制数表示,字由32位2进制数表示;
(2)S盒为固定的8位输入和输出置换(查表法实现);
(3)加密密钥长度为128位,表示为MK=(MK0,MK1,MK2,MK3),其中MKi (i=0,1,2,3)长度为字(32位)。轮密钥表示为rki(i=0,1,2…,31)长度为字(32位)。FK=(FK0,FK1,FK2,FK3)为系统参数,CK=(CK0,CK1,…,CK31)为固定参数,长度都为字(32位)。

4:轮函数
整体的加密函数为:

X i + 4 = F ( X i , X i + 1 , X i + 2 , X i + 3 , r k ) = X i ⨁ T ( X i ⨁ X i + 1 ⨁ X i + 2 ⨁ X i + 3 ⨁ r k ) X_{i+4}=F(X_{i},X_{i+1},X_{i+2},X_{i+3},rk)=X_{i}\bigoplus T(X_{i}\bigoplus X_{i+1}\bigoplus X_{i+2}\bigoplus X_{i+3}\bigoplus rk) Xi+4=F(Xi,Xi+1,Xi+2,Xi+3,rk)=XiT(XiXi+1Xi+2Xi+3rk)

其中T为一个合成置换,由非线性变换和线性变换复合而成。
非线性变换由4个平行的S盒构成,S盒的数据均采用16进制,通过查表直接获得。
线性变换公式如下,其中B为非线性变换得到的字.
C = L ( B ) = B ⨁ ( B ≪ 2 ) ⨁ ( B ≪ 10 ) ⨁ ( B ≪ 18 ) ⨁ ( B ≪ 24 ) C=L(B)=B\bigoplus (B\ll 2)\bigoplus (B\ll 10)\bigoplus(B\ll 18)\bigoplus (B\ll 24) C=L(B)=B(B2)(B10)(B18)(B24)

5:密钥扩展(计算轮密钥)
已知加密密钥MK=(MK0,MK1,MK2,MK3),系统参数FK=(FK0,FK1,FK2,FK3),固定参数CK=(CK0,CK1,…,CK31).
rki为轮密钥,轮密钥由加密密钥生成。
首先
( K 0 , K 1 , K 2 , K 3 ) = ( M K 0 ⨁ F K 0 , M K 1 ⨁ ( K i + 1 ⨁ K i + 2 ⨁ K i + 3 ⨁ C K i ) (K_{0},K_{1},K_{2},K_{3})=(MK_{0}\bigoplus FK_{0},MK_{1}\bigoplus (K_{i+1}\bigoplus K_{i+2}\bigoplus K_{i+3}\bigoplus CK_{i}) (K0,K1,K2,K3)=(MK0FK0,MK1(Ki+1Ki+2Ki+3CKi)
然后对i=0,1,2,…,31:
r k i = K i + 4 = K i ⨁ T ′ ( K i + 1 ⨁ K i + 2 ⨁ K i + 3 ⨁ C K i ) rk_{i}=K_{i+4}=K_{i}\bigoplus{T}'(K_{i+1}\bigoplus K_{i+2}\bigoplus K_{i+3}\bigoplus CK_{i}) rki=Ki+4=KiT(Ki+1Ki+2Ki+3CKi)
密钥扩展变换与加密中的T变换基本相同,只是将其中的线性变换改为:
L ˙ ( B ) = B ⨁ ( B ≪ 13 ) ⨁ ( B ≪ 23 ) L\dot{}(B)=B\bigoplus(B\ll 13)\bigoplus (B\ll 23) L˙(B)=B(B13)(B23)
由于系统参数个固定参数是已知的,轮密钥即可求得。
6:加解密过程

加密最后一轮变换时,输出为:
( Y 0 , Y 1 , Y 2 , Y 3 ) = R ( X 32 , X 33 , X 34 , X 35 ) = ( X 35 , X 34 , X 33 , X 32 ) (Y_{0},Y_{1},Y_{2},Y_{3})=R(X_{32},X_{33},X_{34},X_{35})=(X_{35},X_{34},X_{33},X_{32}) (Y0,Y1,Y2,Y3)=R(X32,X33,X34,X35)=(X35,X34,X33,X32)
最后输出是加密的反序,解密时只是将轮密钥的使用顺序进行逆向进行。

四:迭代模式

1:ECB模式
在这里插入图片描述
优点:
1.简单;
2.有利于并行计算;
3.误差不会被传送;
缺点:
1.不能隐藏明文的模式;
2.可能对明文进行主动攻击;
2:CBC模式
在这里插入图片描述
优点:
1.不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。
缺点:
1.不利于并行计算;
2.误差传递;
3.需要初始化向量IV
3:CFB模式
在这里插入图片描述
优点:
1.隐藏了明文模式;
2.分组密码转化为流模式;
3.可以及时加密传送小于分组的数据;
缺点:
1.不利于并行计算;
2.误差传送:一个明文单元损坏影响多个单元;
3.唯一的IV;
4:OFB模式
在这里插入图片描述
优点:
1.隐藏了明文模式;
2.分组密码转化为流模式;
3.可以及时加密传送小于分组的数据;
缺点:
1.不利于并行计算;
2.对明文的主动攻击是可能的;
3.误差传送:一个明文单元损坏影响多个单元;
注:本程序中使用的是ECB模式

五:代码解读

  • 源代码共有7个函数,原型如下:
void four_uCh2uLong(u8 *in, u32 *out);             //四字节转换成u32
void uLong2four_uCh(u32 in, u8 *out);              //u32转换成四字节
unsigned long move(u32 data, int length);          //左移,保留丢弃位放置尾部
unsigned long func_key(u32 input);                 //先使用Sbox进行非线性变化,再将线性变换L置换为L'
unsigned long func_data(u32 input);                //先使用Sbox进行非线性变化,再进行线性变换L
void encode_fun(u8 len,u8 *key, u8 *input, u8 *output);   //加密函数
void decode_fun(u8 len,u8 *key, u8 *input, u8 *output);   //解密函数
  • 其中前五个函数为算法内部使用函数,用户无需调用。encode_fun为加密函数,decode_fun为解密函数。
  • 加密函数的原型为void encode_fun(u8 len,u8 *key, u8 *input, u8
    *output);,共有四个参数,u8 len为待加密数据数组的长度,可手动给出或者使用sizeof自动计算。
u8 *key为16字节的密钥数组,由用户给出
u8 *input为待加密数组(明文),长度应小于256字节
u8 *output为已加密数组(密文),长度应小于256字节
  • 解密函数的原型为void decode _fun(u8 len,u8 *key, u8 *input, u8 *output);,共有四个参数,u8 len为待解密数据数组的长度,可手动给出或者使用sizeof自动计算。
u8 *key为16字节的密钥数组,由用户给出
u8 *input为待解密数组(密文),长度应小于256字节
u8 *output为已解密数组(明文),长度应小于256字节
  • 例子1:
encode_fun(sizeof(Data_plain),key, Data_ plain, encode_ Result);//数据加密
decode_fun(sizeof(Data_plain),key, encode_Result, decode_Result);//数据解密

其中Data_plain为明文,key为密钥,encode_Result为密文,decode_Result为已解密的明文,对比decode_Result和Data_plain的值是否相等,就可以初步验证加解密是否正常。

  • 例子2:
u8 encode_Result[256]={0}; //定义加密输出缓存区
u8 decode_Result[256]={0}; //定义解密输出缓存区
u8 key[16] = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };
u8 Data plain[200] = {0x02,0x23,1 ,0,0,0,0,0,0,0,0,0,0,0,0,0};/定义200字节的原始输入数据(测试用)
encode_ fun(sizeof(Data plain),key, Data plain, encode_ Result);
//数据加密
decode_ _fun(sizeof(Data plain),key, encode Result, decode_ Result) 
//数据解密

其中encode_Result和decode_Result为用户定义的u8数组,长度不得小于待加密数据的长度。Key为密钥,用户自行给出。
源码解读1:

***********定义系统参数FK的取值***********
const u32 TBL SYS PARAMS[4]= {
0xa3b1bac6,
0x56aa33500x677d9197,
0xb27022dc
};
******定义固定参数CK的取值*******
const u32 TBL_FIX_PARAMS[32]={
0x00070e15,0x1c232a31,0x383f464d,0x545b6269,
0x70777e85,0x8c939aa1,0xa8afb6bd,0xc4cbd2d9,
0xe0e7eef5,0xfc030a11,0x181f262d,0x343b4249,
0x5057 5e65,0x6c737a81 ,0x888f969d,0xa4abb2b9,
0xc0c7ced5,0xdce3eaf1,0xf8ff060d,0x141b2229,
0x30373e45,0x4c535a61 ,0x686f767d,0x848b9299,
0xa0a7aeb5,0xbcc3cad1,0xd8dfe6ed,0xf4fb0209,
****Box参数列表***********
const u8 TBL_SBOX[256]={
0xd6,0x90,0xe9,0xfe,0xcc,0xe 1,0x3d,0xb7,0x16,0xb6,0x14,0xc2 ,0x28,0xfb,0x2c,0x05,
0x2b,0x67 ,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99,
0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62,
0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6,
0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8,
0x68,0x6b,0x81,0xb2,0x7 1,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35,
0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1 ,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87,
0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe 7,0xa0,0xc4,0xc8,0x9e,
0xea,0xbf,0x8a,0xd2,0x40,0xc 7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x6 1,0x15,0xa1,

其中FK CK SBox均为固定值,在库里面已经给出。
例程可通过百度文库获得:
链接:https://pan.baidu.com/s/1khJ9yahy7BF_6I617SqceA
提取码:lr37
库文件也可通过百度文库获得:
链接:https://pan.baidu.com/s/1uPdGYqnAxyPtLEANpwOygA
提取码:dwkv

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐