国密加密算法sm4

概述

SM4加密算法属于对称加密算法,2012年3月,国家密码管理局正式公布了包含SM4分组密码算法在内的《祖冲之序列密码算法》等6项密码行业标准。与DES和AES算法类似,SM4算法是一种分组密码算法。其分组长度为128bit,密钥长度也为128bit。加密算法与密钥扩展算法均采用32轮非线性迭代结构,以字(32位)为单位进行加密运算,每一次迭代运算均为一轮变换函数F。SM4算法加/解密算法的结构相同,只是使用轮密钥相反,其中解密轮密钥是加密轮密钥的逆序。

SM4算法结构图:(图片来源网上)

参数介绍

​ 1、字节:由8位2进制数表示 ,字:由32位2进制数表示;

​ 2、S盒:固定的8bit输入、输出转换数组;

​ 3、加密密钥长度为128bit,表示为MK=(MK0,MK1,MK2,MK3),其中MKi为字。轮密钥表示为rki(i=0,1,2,3……31)为字。FK = (FK0,FK1,FK2,FK3)为系统 参数,CK = (CK0,CK1,CK2,……,CK31)为固定参数,都为字。

加密

加密原理这里就不讲了,网上有不少详细的文章,下面直接开始算法的实现。

在开始加密算法之前,先介绍几个宏定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//将字符型数组b的第i到第i+3位的二进制拼接成一个4*8=32bit的整数,存入n中
#define GET_ULONG_BE(n,b,i) \
{ \
(n) = ( (unsigned long) (b)[(i) ] << 24 ) \
| ( (unsigned long) (b)[(i) + 1] << 16 ) \
| ( (unsigned long) (b)[(i) + 2] << 8 ) \
| ( (unsigned long) (b)[(i) + 3] ); \
}
#endif
//将整数n的32位的二进制表示转换为4个char的数组,存入数组b的第i到第i+3位
#ifndef PUT_ULONG_BE
#define PUT_ULONG_BE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
}
#endif
//循环左移 的巧妙实现(SHL(x,n)可以得到左移n位之后的结果,然后与右移的结果((x) >> (32 - n))逐位或来将右边空缺的n位补齐,效率比较高。)
#define SHL(x,n) (((x) & 0xFFFFFFFF) << n)
#define ROTL(x,n) (SHL((x),n) | ((x) >> (32 - n)))
//交换
#define SWAP(a,b) { unsigned long t = a; a = b; b = t; t = 0; }

密钥调试算法

先建立一个结构体来保存上下文信息,即加密模式和各轮子密钥:(这个结构体我是定义在sm4.h头文件中)

1
2
3
4
5
6
typedef struct
{
int mode; /*!< encrypt/decrypt */
unsigned long sk[32]; /*!< SM4 subkeys */
}
sm4_context;

首先需要设置密钥,调用sm4_setkey_enc(&ctx,key);函数,这个函数会设置mode为加密,并调用sm4_setkey(ctx->sk,key);函数来完成密钥的操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void sm4_setkey_enc(sm4_context *ctx,unsigned char key[16]){
ctx->mode = SM4_ENCRYPT;
sm4_setkey(ctx->sk,key);
}
static void sm4_setkey(unsigned long SK[32],unsigned char key[16]){
unsigned long MK[4];
unsigned long k[36];
unsigned long i = 0;
//先通过宏将初始的密钥转换为4个32位bit的整数,并为计算各轮密钥预先准备好初始值
GET_ULONG_BE(MK[0],key,0);
GET_ULONG_BE(MK[1],key,4);
GET_ULONG_BE(MK[2],key,8);
GET_ULONG_BE(MK[3],key,12);
k[0] = MK[0]^FK[0];
k[1] = MK[1]^FK[1];
k[2] = MK[2]^FK[2];
k[3] = MK[3]^FK[3];
for(;i<32;i++){
k[i+4] = k[i]^sm4CaliRk(k[i+1]^k[i+2]^k[i+3]^CK[i]);
SK[i] = k[i+4];
}
}

对于第i轮的密钥SK[i],其是由k[i]和对k[i+1]^k[i+2]^k[i+3]^CK[i]的复合变换T‘异或得到的:

SK[i] = k[i+4] = k[i]^sm4CaliRk(k[i+1]^k[i+2]^k[i+3]^CK[i]);函数sm4CaliRk就是变换T’,先进行Sbox的非线性替换,然后进行线性变换,线性变换L为:rk = bb^(ROTL(bb, 13))^(ROTL(bb, 23));

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static unsigned long sm4CaliRk(unsigned long ka){ //复合变换T
unsigned long bb = 0; //unsigned long 4字节( 32bit )
unsigned long rk = 0;
unsigned char a[4];
unsigned char b[4];
PUT_ULONG_BE(ka,a,0) //换转成8bit一个字符
b[0] = sm4Sbox(a[0]);
b[1] = sm4Sbox(a[1]);
b[2] = sm4Sbox(a[2]);
b[3] = sm4Sbox(a[3]);
GET_ULONG_BE(bb,b,0) //将变换结果转换为32bit的整数
//对得到的32位整数bb进行线性变换
rk = bb^ROTL(bb,13)^ROTL(bb,23);
return rk;
}

至此,密钥就已经生成了

加密过程

调用函数void sm4_crypt_ecb( sm4_context *ctx, int mode, int length, unsigned char *input, unsigned char *output)对密文input进行电码本模式加密(ECB),加密的核心是调用了static void sm4_one_round( unsigned long sk[32], unsigned char input[16], unsigned char output[16] )函数对第一块密文进行加密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
void sm4_crypt_ecb( sm4_context *ctx,
int mode,
int length,
unsigned char *input,
unsigned char *output)
{
while( length > 0 )
{
sm4_one_round( ctx->sk, input, output );
input += 16;
output += 16;
length -= 16;
}

}

static void sm4_one_round( unsigned long sk[32],
unsigned char input[16],
unsigned char output[16] )
{
unsigned long i = 0;
unsigned long ulbuf[36];

memset(ulbuf, 0, sizeof(ulbuf));
GET_ULONG_BE( ulbuf[0], input, 0 )
GET_ULONG_BE( ulbuf[1], input, 4 )
GET_ULONG_BE( ulbuf[2], input, 8 )
GET_ULONG_BE( ulbuf[3], input, 12 )
while(i<32)
{
ulbuf[i+4] = sm4F(ulbuf[i], ulbuf[i+1], ulbuf[i+2], ulbuf[i+3], sk[i]);
// #ifdef _DEBUG
// printf("rk(%02d) = 0x%08x, X(%02d) = 0x%08x \n",i,sk[i], i, ulbuf[i+4] );
// #endif
i++;
}
PUT_ULONG_BE(ulbuf[35],output,0);
PUT_ULONG_BE(ulbuf[34],output,4);
PUT_ULONG_BE(ulbuf[33],output,8);
PUT_ULONG_BE(ulbuf[32],output,12);
}

sm4_one_round()函数中,先将128位的输入input转为四个32位的整数,放入ulbuf[4]中,然后迭代地调用函数static unsigned long sm4F(unsigned long x0, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long rk)进行32轮加密,第一轮加密都需要使用之前的128位的结果ulbuf[i], ulbuf[i+1], ulbuf[i+2], ulbuf[i+3]和该轮的密钥 sk[i],产生出该轮的密文ulbuf[i+4],最后的密文存储在ulbuf[35]~ulbuf[32]中,转换为字符数组形式放入output 中。

1
2
3
4
5
//一轮加密 
static unsigned long sm4F(unsigned long x0, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long rk)
{
return (x0^sm4Lt(x1^x2^x3^rk));
}

sm4Lt()是一个合成变换,由非线性变换t和线性变换L复合而成:首先将输入的整数 ka 转换为8比特一个的字符,然后使用S盒进行线性变换,再将变换结果转为32比特的整数,最后对得到的32位整数bb进行线性变换:c =bb^(ROTL(bb, 2))^(ROTL(bb, 10))^(ROTL(bb, 18))^(ROTL(bb, 24));

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
static unsigned long sm4Lt(unsigned long ka)
{
unsigned long bb = 0;
unsigned long c = 0;
unsigned char a[4];
unsigned char b[4];
PUT_ULONG_BE(ka,a,0)
// b[0] = sm4Sbox(a[0]);
// b[1] = sm4Sbox(a[1]);
// b[2] = sm4Sbox(a[2]);
// b[3] = sm4Sbox(a[3]);
b[0] = Sbox[a[0]];
b[1] = Sbox[a[1]];
b[2] = Sbox[a[2]];
b[3] = Sbox[a[3]];
GET_ULONG_BE(bb,b,0)
c =bb^(ROTL(bb, 2))^(ROTL(bb, 10))^(ROTL(bb, 18))^(ROTL(bb, 24));
return c;
}

整个加密过程就结束了,不过上面提到的是ECB的加密模式:又称电子密码本模式:Electronic codebook,是最简单的块密码加密模式,加密前根据加密块大小(如AES为128位)分成若干块,之后将每块使用相同的密钥单独加密,解密同理。这种加密不能很好地隐藏数据模式。

SM4常见的也有另一种加密模式:CBC:密码分组链接(CBC,Cipher-block chaining)模式,由IBM于1976年发明,每个明文块先与前一个密文块进行异或后,再进行加密。在这种方法中,每个密文块都依赖于它前面的所有明文块。同时,为了保证每条消息的唯一性,在第一个块中需要使用初始化向量IV。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//CBC模式加解密 
void sm4_crypt_cbc( sm4_context *ctx,
int mode,
int length,
unsigned char iv[16],
unsigned char *input,
unsigned char *output )
{
int i;
unsigned char temp[16];

if( mode == SM4_ENCRYPT )
{
while( length > 0 )
{
for( i = 0; i < 16; i++ )
output[i] = (unsigned char)( input[i] ^ iv[i] );

sm4_one_round( ctx->sk, output, output );
memcpy( iv, output, 16 );

input += 16;
output += 16;
length -= 16;
}
}
else /* SM4_DECRYPT */
{
while( length > 0 )
{
memcpy( temp, input, 16 );
sm4_one_round( ctx->sk, input, output );

for( i = 0; i < 16; i++ )
output[i] = (unsigned char)( output[i] ^ iv[i] );

memcpy( iv, temp, 16 );

input += 16;
output += 16;
length -= 16;
}
}
}

解密过程

解密前,首先要通过void sm4_setkey_dec( sm4_context *ctx, unsigned char key[16] )函数设定解密时使用的key,这个函数还会将密钥的顺序倒置,然后调用sm4_crypt_ecb()即可解密。

实际上,SM4的解密变换与加密变换结构相同,不同的仅仅是轮密钥的使用顺序相反。

完整的代码

sm4.h文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/**
* \file sm4.h
*/
#ifndef XYSSL_SM4_H
#define XYSSL_SM4_H

#define SM4_ENCRYPT 1
#define SM4_DECRYPT 0
#ifndef GET_ULONG_BE
//将字符型数组b的第i到第i+3位的二进制拼接成一个4*8=32bit的整数,存入n中
#define GET_ULONG_BE(n,b,i) \
{ \
(n) = ( (unsigned long) (b)[(i) ] << 24 ) \
| ( (unsigned long) (b)[(i) + 1] << 16 ) \
| ( (unsigned long) (b)[(i) + 2] << 8 ) \
| ( (unsigned long) (b)[(i) + 3] ); \
}
#endif
//将整数n的32位的二进制表示转换为4个char的数组,存入数组b的第i到第i+3位
#ifndef PUT_ULONG_BE
#define PUT_ULONG_BE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
}
#endif
//循环左移 的巧妙实现(SHL(x,n)可以得到左移n位之后的结果,然后与右移的结果((x) >> (32 - n))逐位或来将右边空缺的n位补齐,效率比较高。)
#define SHL(x,n) (((x) & 0xFFFFFFFF) << n)
#define ROTL(x,n) (SHL((x),n) | ((x) >> (32 - n)))

#define SWAP(a,b) { unsigned long t = a; a = b; b = t; t = 0; }

/**
* \brief SM4 context structure
*/
typedef struct
{
int mode; /*!< encrypt/decrypt */
unsigned long sk[32]; /*!< SM4 subkeys */
}
sm4_context;


#ifdef __cplusplus
extern "C" {
#endif

/**
* \brief SM4 key schedule (128-bit, encryption)
*
* \param ctx SM4 context to be initialized
* \param key 16-byte secret key
*/
void sm4_setkey_enc( sm4_context *ctx, unsigned char key[16] );

/**
* \brief SM4 key schedule (128-bit, decryption)
*
* \param ctx SM4 context to be initialized
* \param key 16-byte secret key
*/
void sm4_setkey_dec( sm4_context *ctx, unsigned char key[16] );

/**
* \brief SM4-ECB block encryption/decryption
* \param ctx SM4 context
* \param mode SM4_ENCRYPT or SM4_DECRYPT
* \param length length of the input data
* \param input input block
* \param output output block
*/
void sm4_crypt_ecb( sm4_context *ctx,
int mode,
int length,
unsigned char *input,
unsigned char *output);

/**
* \brief SM4-CBC buffer encryption/decryption
* \param ctx SM4 context
* \param mode SM4_ENCRYPT or SM4_DECRYPT
* \param length length of the input data
* \param iv initialization vector (updated after use)
* \param input buffer holding the input data
* \param output buffer holding the output data
*/
void sm4_crypt_cbc( sm4_context *ctx,
int mode,
int length,
unsigned char iv[16],
unsigned char *input,
unsigned char *output );

#ifdef __cplusplus
}
#endif

#endif /* sm4.h */

sm4.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
#include <iostream>
#include <string.h>
#include "sm4.h"

using namespace std;


//S盒
const unsigned char Sbox[256] = {
0xd6,0x90,0xe9,0xfe,0xcc,0xe1,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,0x71,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,0xe7,0xa0,0xc4,0xc8,0x9e,
0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1,
0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3,
0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f,
0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51,
0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8,
0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0,
0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84,
0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48
};
//CK为固定参数
const unsigned int CK[32] = {
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279 };
//FK为系统参数
static const unsigned long FK[4] = {0xa3b1bac6,0x56aa3350,0x677d9197,0xb27022dc};

static unsigned char sm4Sbox(unsigned char inch)
{
unsigned char *pTable = (unsigned char *)Sbox;
unsigned char retVal = (unsigned char)(pTable[inch]);
return retVal;
}
//已知加密密钥MK,求轮转密钥rk
static unsigned long sm4CaliRk(unsigned long ka){ //复合变换T
unsigned long bb = 0; //unsigned long 4字节( 32bit )
unsigned long rk = 0;
unsigned char a[4];
unsigned char b[4];
PUT_ULONG_BE(ka,a,0) //换转成8bit一个字符
b[0] = sm4Sbox(a[0]);
b[1] = sm4Sbox(a[1]);
b[2] = sm4Sbox(a[2]);
b[3] = sm4Sbox(a[3]);
GET_ULONG_BE(bb,b,0) //将变换结果转换为32bit的整数
//对得到的32位整数bb进行线性变换
rk = bb^ROTL(bb,13)^ROTL(bb,23);
return rk;
}
static void sm4_setkey(unsigned long SK[32],unsigned char key[16]){
unsigned long MK[4];
unsigned long k[36];
unsigned long i = 0;
GET_ULONG_BE(MK[0],key,0);
GET_ULONG_BE(MK[1],key,4);
GET_ULONG_BE(MK[2],key,8);
GET_ULONG_BE(MK[3],key,12);
k[0] = MK[0]^FK[0];
k[1] = MK[1]^FK[1];
k[2] = MK[2]^FK[2];
k[3] = MK[3]^FK[3];
for(;i<32;i++){
k[i+4] = k[i]^sm4CaliRk(k[i+1]^k[i+2]^k[i+3]^CK[i]);
SK[i] = k[i+4];
}
}
void sm4_setkey_enc(sm4_context *ctx,unsigned char key[16]){
ctx->mode = SM4_ENCRYPT;
sm4_setkey(ctx->sk,key);
}

static unsigned long sm4Lt(unsigned long ka)
{
unsigned long bb = 0;
unsigned long c = 0;
unsigned char a[4];
unsigned char b[4];
PUT_ULONG_BE(ka,a,0)
// b[0] = sm4Sbox(a[0]);
// b[1] = sm4Sbox(a[1]);
// b[2] = sm4Sbox(a[2]);
// b[3] = sm4Sbox(a[3]);
b[0] = Sbox[a[0]];
b[1] = Sbox[a[1]];
b[2] = Sbox[a[2]];
b[3] = Sbox[a[3]];
GET_ULONG_BE(bb,b,0)
c =bb^(ROTL(bb, 2))^(ROTL(bb, 10))^(ROTL(bb, 18))^(ROTL(bb, 24));
return c;
}
//一轮加密
static unsigned long sm4F(unsigned long x0, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long rk)
{
return (x0^sm4Lt(x1^x2^x3^rk));
}
static void sm4_one_round( unsigned long sk[32],
unsigned char input[16],
unsigned char output[16] )
{
unsigned long i = 0;
unsigned long ulbuf[36];

memset(ulbuf, 0, sizeof(ulbuf));
GET_ULONG_BE( ulbuf[0], input, 0 )
GET_ULONG_BE( ulbuf[1], input, 4 )
GET_ULONG_BE( ulbuf[2], input, 8 )
GET_ULONG_BE( ulbuf[3], input, 12 )
while(i<32)
{
ulbuf[i+4] = sm4F(ulbuf[i], ulbuf[i+1], ulbuf[i+2], ulbuf[i+3], sk[i]);
// #ifdef _DEBUG
// printf("rk(%02d) = 0x%08x, X(%02d) = 0x%08x \n",i,sk[i], i, ulbuf[i+4] );
// #endif
i++;
}
PUT_ULONG_BE(ulbuf[35],output,0);
PUT_ULONG_BE(ulbuf[34],output,4);
PUT_ULONG_BE(ulbuf[33],output,8);
PUT_ULONG_BE(ulbuf[32],output,12);
}
//ECB模式
void sm4_crypt_ecb( sm4_context *ctx,
int mode,
int length,
unsigned char *input,
unsigned char *output)
{
while( length > 0 )
{
sm4_one_round( ctx->sk, input, output );
input += 16;
output += 16;
length -= 16;
}

}
//ECB模式解密密钥
void sm4_setkey_dec( sm4_context *ctx, unsigned char key[16] )
{
int i;
ctx->mode = SM4_ENCRYPT;
sm4_setkey( ctx->sk, key );
for( i = 0; i < 16; i ++ )
{
SWAP( ctx->sk[ i ], ctx->sk[ 31-i] );
}
}
//CBC模式加解密
void sm4_crypt_cbc( sm4_context *ctx,
int mode,
int length,
unsigned char iv[16],
unsigned char *input,
unsigned char *output )
{
int i;
unsigned char temp[16];

if( mode == SM4_ENCRYPT )
{
while( length > 0 )
{
for( i = 0; i < 16; i++ )
output[i] = (unsigned char)( input[i] ^ iv[i] );

sm4_one_round( ctx->sk, output, output );
memcpy( iv, output, 16 );

input += 16;
output += 16;
length -= 16;
}
}
else /* SM4_DECRYPT */
{
while( length > 0 )
{
memcpy( temp, input, 16 );
sm4_one_round( ctx->sk, input, output );

for( i = 0; i < 16; i++ )
output[i] = (unsigned char)( output[i] ^ iv[i] );

memcpy( iv, temp, 16 );

input += 16;
output += 16;
length -= 16;
}
}
}
int main()
{
unsigned char key[16] = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
unsigned char input[16] = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
unsigned char output[16];
sm4_context ctx;
unsigned long i;
//encrypt
sm4_setkey_enc(&ctx,key);
sm4_crypt_ecb(&ctx,1,16,input,output);
//加密结果
printf("加密结果:\n");
for(i = 0;i< 16;i ++){
printf("%02x ",output[i]);
}
printf("\n");
sm4_setkey_dec(&ctx,key);
sm4_crypt_ecb(&ctx,0,16,output,output);
//解密结果
printf("解密结果:\n");
for(i = 0;i< 16;i ++){
printf("%02x ",output[i]);
}
printf("\n");
return 0;
}

参数文章:https://blog.csdn.net/cg129054036/article/details/83012721

https://blog.csdn.net/cg129054036/article/details/83016958

https://blog.csdn.net/archimekai/article/details/53095993

0%