OpenSSL入门-对称密码

安装

来这里下载二进制https://wiki.openssl.org/index.php/Binaries 并进行安装,不要选择Lite版,且注意将动态链接库放在安装目录下。

新建一个Visual Studio项目,项目属性中的VC++目录下有个包含目录,添加OpenSSL的include目录,库目录添加lib目录对应模式的子目录。链接器设置中输入的附加依赖项添加:

1
2
3
libssl.lib
libcrypto.lib
ws2_32.lib

最后将bin目录下的libcrypto-3-x64.dll和libssl-3-x64.dll拷贝到工程目录和生成的可执行文件目录下。

能运行以下代码就算成功:

1
2
3
4
5
6
7
#include <iostream>
#include "openssl/evp.h"
int main(void) {
OpenSSL_add_all_algorithms();
std::cout << "Hello World!\n";
return 0;
};

RC4

RC4_set_key来生成密钥流:

1
2
3
4
5
void RC4_SET_KEY(
RC4_KEY* key, //输出生成的密钥流
int len, //data长度
const unsigned char* data //用户设置的密钥
);

RC4实现加密或解密:

1
2
3
4
5
6
void RC4(
RC4_KEY* key, //密钥流
unsigned long len, //indata长度
const unsigned char* indata, //输入的数据
unsigned char* outdata //结果
);

例如:

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
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <openssl/rc4.h>
int main(int argc, char* argv[]) {
RC4_KEY key; //密钥流结构体
const char* data = "Hello,World!!";
int length = strlen(data);
RC4_set_key(&key, length, (unsigned char*)data);
const char* indata = "This is plain text !!!!";
int len = strlen(indata);
printf("strlen(indata)=%d\n", len);
char* outdata;//分配密文空间
outdata = (char*)malloc(sizeof(unsigned char) * (len + 1));
memset(outdata, 0, len + 1);//初始为0
printf("\tindata=%s\n", indata);
RC4(&key, strlen(indata), (unsigned char*)indata, (unsigned char*)outdata);
printf("\toutdata=%s\n", outdata);
printf("strlen(outdata)=%d\n", strlen(outdata));
char* plain;//分配明文空间
plain = (char*)malloc(sizeof(unsigned char) * (len + 1));
memset(plain, 0, len + 1);//初始化为0
RC4_set_key(&key, length, (unsigned char*)data);
RC4(&key, strlen(outdata), (unsigned char*)outdata, (unsigned char*)plain);
printf("\tplain=%s\n", plain);
printf("strlen(plain)=%d\n", strlen(plain));
return 0;
};

C语言版:

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
#include "pch.h"
#include <iostream>
//RC4算法对数据的加密和解密
#include <stdio.h>
#define MAX_CHAR_LEN 10000
void produceKeystream(int textlength, unsigned char key[],int keylength, unsigned char keystream[]){
unsigned int S[256];
int i, j = 0, k;
unsigned char tmp;
for (i = 0; i < 256; i++)
S[i] = i;
for (i = 0; i < 256; i++) {
j = (j + S[i] + key[i % keylength]) % 256;
tmp = S[i];
S[i] = S[j];
S[j] = tmp;
}
i = j = k = 0;
while (k < textlength) {
i = (i + 1) % 256;
j = (j + S[i]) % 256;
tmp = S[i];
S[i] = S[j];
S[j] = tmp;
keystream[k++] = S[(S[i] + S[j]) % 256];
}
}
void rc4encdec(int textlength, unsigned char plaintext[],unsigned char keystream[],unsigned char ciphertext[]){
int i;
for (i = 0; i < textlength; i++)
ciphertext[i] = keystream[i] ^ plaintext[i];
}
int main(int argc, char *argv[]){
unsigned char plaintext[MAX_CHAR_LEN];
unsigned char chktext[MAX_CHAR_LEN];
unsigned char key[32];
unsigned char keystream[MAX_CHAR_LEN];
unsigned char ciphertext[MAX_CHAR_LEN];
unsigned c;
int i = 0, textlength, keylength;
FILE *fp;
if ((fp = fopen("明文.txt", "r")) == NULL) {
printf("file \"%s\" not found!\n", *argv);
return 0;
}
while ((c = getc(fp)) != EOF)
plaintext[i++] = c;
textlength = i;
fclose(fp);
/* input a key */
printf("passwd: ");
for (i = 0; (c = getchar()) != '\n'; i++)
key[i] = c;
key[i] = '\0';
keylength = i;
/* use key to generate a keystream */
produceKeystream(textlength, key, keylength, keystream);
/* use the keystream and plaintext to generate ciphertext */
rc4encdec(textlength, plaintext, keystream, ciphertext);
fp = fopen("密文.txt", "w");
for (int i = 0; i < textlength; i++)
putc(ciphertext[i], fp);
fclose(fp);
rc4encdec(textlength, ciphertext, keystream, chktext);
if (memcmp(chktext, plaintext, textlength) == 0)
puts("源明文和解密后的明文内容相同!加解密成功!!\n");
fp = fopen("解密后的明文.txt", "w");
for (int i = 0; i < textlength; i++)
putc(chktext[i], fp);
fclose(fp);
return 0;
}

DES/3DES

DES_ecb_encrypt实现ECB模式DES算法:

1
2
3
4
5
6
void DES_ecb_encrypt(
const_DES_cblock* input, //输入缓冲区
DES_cblock* output, //输出缓冲区
DES_key_schedule* ks, //密钥缓冲区
int enc //加密还是解密
);

上述参数ks需要由以下方法转换而来:

1
2
3
4
DES_cblock key;
DES_random_key(&key);
DES_key_schedule schedule;
DES_set_key_checked(&key,&schedule);

实现为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include <openssl/des.h>
int main(int argc, char** argv){
DES_cblock key;
//随机密钥
DES_random_key(&key);
DES_key_schedule schedule;
//转换成schedule
DES_set_key_checked(&key, &schedule);
const_DES_cblock input = "abc";
DES_cblock output;
printf("cleartext: %s\n", input);
//加密
DES_ecb_encrypt(&input, &output, &schedule, DES_ENCRYPT);
printf("Encrypted!\nciphertext: ");
int i;
for (i = 0; i < sizeof(input); i++)
printf("%02x", output[i]);
printf("\n");
//解密
DES_ecb_encrypt(&output, &input, &schedule, DES_DECRYPT);
printf("Decrypted!\ncleartext:%s\n", input);
return 0;
}

C语言版:

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
230
231
232
233
234
235
236
237
238
239
#include <stdio.h>
#include <memory.h>
#include <string.h>
typedef bool(*PSubKey)[16][48];
enum { ENCRYPT, DECRYPT }; //选择:加密;解密
static bool SubKey[2][16][48]; // 16圈子密钥
static bool Is3DES; // 3次DES标志
static char Tmp[256], deskey[16]; //暂存字符串,密钥串
static void DES(char Out[8], char In[8], const PSubKey pSubKey, bool Type);//标准DES加/解密
static void SetKey(const char* Key, int len);// 设置密钥
static void SetSubKey(PSubKey pSubKey, const char Key[8]);// 设置子密钥
static void F_func(bool In[32], const bool Ki[48]);// f 函数
static void S_func(bool Out[32], const bool In[48]);// S 盒代替
static void Transform(bool* Out, bool* In, const char* Table, int len);// 变换
static void Xor(bool* InA, const bool* InB, int len);// 异或
static void RotateL(bool* In, int len, int loop);// 循环左移
static void ByteToBit(bool* Out, const char* In, int bits);// 字节组转换成位组
static void BitToByte(char* Out, const bool* In, int bits);// 位组转换成字节组
// Type(选择)—ENCRYPT:加密,DECRYPT:解密
// 输出缓冲区(Out)的长度 >= ((datalen+7)/8)*8,即比datalen大的且是8的倍数的最小正整数
// In 可以= Out,此时加/解密后将覆盖输入缓冲区(In)的内容
// 当keylen>8时系统自动使用3次DES加/解密,否则使用标准DES加/解密.超过16字节后只取前16字节
//加密解密函数:
bool DES_Act(char* Out, char* In, long datalen, const char* Key, int keylen, bool Type = ENCRYPT);
int main() {
char plain_text[100] = { 0 }; // 设置明文
char key[100] = { 0 }; // 密钥设置
printf("请输入明文:\n");
gets_s(plain_text);
printf("\n 请输入密钥:\n");
gets_s(key);
char encrypt_text[255]; // 密文
char decrypt_text[255]; // 解密文
memset(encrypt_text, 0, sizeof(encrypt_text));//memset(a,b,c)函数,在a的地址开始到c的长度的字节都初始化为b
memset(decrypt_text, 0, sizeof(decrypt_text));
// 进行DES加密:
DES_Act(encrypt_text, plain_text, sizeof(plain_text), key, sizeof(key), ENCRYPT);
printf("\nDES加密后的密文:\n%s\n\n", encrypt_text);
// 进行DES解密:
DES_Act(decrypt_text, encrypt_text, sizeof(plain_text), key, sizeof(key), DECRYPT);
printf("\n解密后的输出:\n%s\n\n", decrypt_text);
return 0;
}
//下面是DES算法中用到的各种表:
// 初始置换IP表
const static char IP_Table[64] = {
58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7
};
// 逆初始置换IP1表
const static char IP1_Table[64] = {
40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31,
38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,
36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27,
34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25
};
// 扩展置换E表
static const char Extension_Table[48] = {
32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9,
8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,
24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1
};
// P盒置换表
const static char P_Table[32] = {
16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
};
// 密钥置换表
const static char PC1_Table[56] = {
57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4
};
// 压缩置换表
const static char PC2_Table[48] = {
14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
};
// 每轮移动的位数
const static char LOOP_Table[16] = {
1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1
};
// S盒设计
const static char S_Box[8][4][16] = {
// S盒1
14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13,
// S盒2
15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9,
// S盒3
10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12,
// S盒4
7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14,
// S盒5
2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3,
// S盒6
12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13,
// S盒7
4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12,
// S盒8
13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
};
//下面是DES算法中调用的函数:
// 字节转换函数
void ByteToBit(bool* Out, const char* In, int bits) {
for (int i = 0; i < bits; ++i)
Out[i] = (In[i >> 3] >> (i & 7)) & 1;
//In[i/8] 这个作用是取出1个字节:i=0~7的时候就取In[0], i=8~15的时候就取In[1],……
//In[i/8] >> (i%8),是把取出来的1个字节右移0~7位,也就是依次取出那个字节的每一个bit
//整个函数的作用是:把In里面的每个字节依次转换为8个bit,最后的结果存到Out里面
}
// 比特转换函数
void BitToByte(char* Out, const bool* In, int bits) {
memset(Out, 0, bits >> 3);//把每个字节都初始化为0
for (int i = 0; i < bits; ++i)
Out[i >> 3] |= In[i] << (i & 7);//i>>3位运算,按位右移三位等于i除以8,i&7按位与运算等于i求余8;
}
// 变换函数
void Transform(bool* Out, bool* In, const char* Table, int len) {
for (int i = 0; i < len; ++i)
Tmp[i] = In[Table[i] - 1];
memcpy(Out, Tmp, len);
}
// 异或函数的实现
void Xor(bool* InA, const bool* InB, int len) {
for (int i = 0; i < len; ++i)
InA[i] ^= InB[i];//异或运算,相同为0,不同为1
}
// 轮转函数
void RotateL(bool* In, int len, int loop) {
memcpy(Tmp, In, loop);//Tmp接受左移除的loop个字节
memcpy(In, In + loop, len - loop);//In更新即剩下的字节向前移动loop个字节
memcpy(In + len - loop, Tmp, loop);//左移除的字节添加到In的len-loop的位置
}
// S函数的实现
void S_func(bool Out[32], const bool In[48]) { //将8组,每组6 bits的串,转化为8组,每组4 bits
for (char i = 0, j, k; i < 8; ++i, In += 6, Out += 4) {
j = (In[0] << 1) + In[5];//取第一位和第六位组成的二进制数为S盒的纵坐标
k = (In[1] << 3) + (In[2] << 2) + (In[3] << 1) + In[4];//取第二、三、四、五位组成的二进制数为S盒的横坐标
ByteToBit(Out, &S_Box[i][j][k], 4);
}
}
// F函数的实现
void F_func(bool In[32], const bool Ki[48]) {
static bool MR[48];
Transform(MR, In, Extension_Table, 48); //先进行 E 扩展
Xor(MR, Ki, 48); //再异或
S_func(In, MR); //各组字符串分别经过各自的 S 盒
Transform(In, In, P_Table, 32); //最后 P 变换
}
// 设置子密钥
void SetSubKey(PSubKey pSubKey, const char Key[8]) {
static bool K[64], * KL = &K[0], * KR = &K[28]; //将64位密钥串去掉8位奇偶位后,分成两份
ByteToBit(K, Key, 64); //转换格式
Transform(K, K, PC1_Table, 56);
for (int i = 0; i < 16; ++i) { // 由56位密钥产生48位子密钥
RotateL(KL, 28, LOOP_Table[i]); //两份子密钥分别进行左移转换
RotateL(KR, 28, LOOP_Table[i]);
Transform((*pSubKey)[i], K, PC2_Table, 48);
}
}
// 设置密钥
void SetKey(const char* Key, int len) {
memset(deskey, 0, 16);
memcpy(deskey, Key, len > 16 ? 16 : len);//memcpy(a,b,c)函数,将从b地址开始到c长度的字节的内容复制到a
SetSubKey(&SubKey[0], &deskey[0]);// 设置子密钥
Is3DES = len > 8 ? (SetSubKey(&SubKey[1], &deskey[8]), true) : false;
}
// DES加解密函数
void DES(char Out[8], char In[8], const PSubKey pSubKey, bool Type) {
static bool M[64], tmp[32], * Li = &M[0], * Ri = &M[32]; //64 bits明文 经过IP置换后,分成左右两份
ByteToBit(M, In, 64);
Transform(M, M, IP_Table, 64);
if (Type == ENCRYPT) { //加密
for (int i = 0; i < 16; ++i) { //加密时:子密钥 K0~K15
memcpy(tmp, Ri, 32);
F_func(Ri, (*pSubKey)[i]); // 调用F函数
Xor(Ri, Li, 32); //Li与Ri异或
memcpy(Li, tmp, 32);
}
}
else { //解密
for (int i = 15; i >= 0; --i) { // 解密时:Ki的顺序与加密相反
memcpy(tmp, Li, 32);
F_func(Li, (*pSubKey)[i]);
Xor(Li, Ri, 32);
memcpy(Ri, tmp, 32);
}
}
Transform(M, M, IP1_Table, 64); //最后经过逆初始置换IP-1,得到密文/明文
BitToByte(Out, M, 64);
}
// DES加解密函数(可以对长明文分段加密)
bool DES_Act(char* Out, char* In, long datalen, const char* Key, int keylen, bool Type) {
if (!(Out && In && Key && (datalen = (datalen + 7) & 0xfffffff8)))
return false;
SetKey(Key, keylen);
if (!Is3DES) { // 1次DES
for (long i = 0, j = datalen >> 3; i < j; ++i, Out += 8, In += 8)
DES(Out, In, &SubKey[0], Type);
}
else { // 3次DES 加密:加(key0)-解(key1)-加(key0) 解密::解(key0)-加(key1)-解(key0)
for (long i = 0, j = datalen >> 3; i < j; ++i, Out += 8, In += 8) {
DES(Out, In, &SubKey[0], Type);
DES(Out, Out, &SubKey[1], !Type);
DES(Out, Out, &SubKey[0], Type);
}
}
return true;
}

SM4

示例:

1
2
3
4
5
6
7
8
9
10
11
//test.cpp
extern int sm4ecbcheck();
extern int sm4cbccheck();
extern int sm4cfbcheck();
extern int sm4ofbcheck();
int main() {
sm4ecbcheck();
sm4cbccheck();
sm4cfbcheck();
sm4ofbcheck();
}

各种链接方式的测试:

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
//sm4check.cpp
#include "sm4.h"
#include <stdio.h>
#include <string.h>
int sm4ecbcheck() {
int i, len, ret = 0;
unsigned char key[16] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };
unsigned char plain[16] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };
unsigned char cipher[16] = { 0x68,0x1e,0xdf,0x34,0xd2,0x06,0x96,0x5e,0x86,0xb3,0xe9,0x4f,0x53,0x6e,0x42,0x46 };
unsigned char En_output[16];
unsigned char De_output[16];
unsigned char in[4096], out[4096], chk[4096];
sm4ecb(plain, En_output, 16, key, SM4_ENCRYPT);
if (memcmp(En_output, cipher, 16))
puts("ecb enc(len=16) memcmp failed");
else
puts("ecb enc(len=16) memcmp ok");
sm4ecb(cipher, De_output, SM4_BLOCK_SIZE, key, SM4_DECRYPT);
if (memcmp(De_output, plain, SM4_BLOCK_SIZE))
puts("ecb dec(len=16) memcmp failed");
else
puts("ecb dec(len=16) memcmp ok");
len = 32;
for (i = 0; i < 8; i++) {
memset(in, i, len);
sm4ecb(in, out, len, key, SM4_ENCRYPT);
sm4ecb(out, chk, len, key, SM4_DECRYPT);
if (memcmp(in, chk, len))
printf("ecb enc/dec(len=%d) memcmp failed\n", len);
else
printf("ecb enc/dec(len=%d) memcmp ok\n", len);
len = 2 * len;
}
return 0;
}
int sm4cbccheck() {
int i, len, ret = 0;
unsigned char key[16] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };//密钥
unsigned char iv[16] = { 0xeb,0xee,0xc5,0x68,0x58,0xe6,0x04,0xd8,0x32,0x7b,0x9b,0x3c,0x10,0xc9,0x0c,0xa7 }; //初始化向量
unsigned char plain[32] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,0x29,0xbe,0xe1,0xd6,0x52,0x49,0xf1,0xe9,0xb3,0xdb,0x87,0x3e,0x24,0x0d,0x06,0x47 }; //明文
unsigned char cipher[32] = { 0x3f,0x1e,0x73,0xc3,0xdf,0xd5,0xa1,0x32,0x88,0x2f,0xe6,0x9d,0x99,0x6c,0xde,0x93,0x54,0x99,0x09,0x5d,0xde,0x68,0x99,0x5b,0x4d,0x70,0xf2,0x30,0x9f,0x2e,0xf1,0xb7 }; //密文
unsigned char En_output[32];
unsigned char De_output[32];
unsigned char in[4096], out[4096], chk[4096];
sm4cbc(plain, En_output, sizeof(plain), key, iv, SM4_ENCRYPT);
if (memcmp(En_output, cipher, 16))
puts("cbc enc(len=32) memcmp failed");
else
puts("cbc enc(len=32) memcmp ok");
sm4cbc(cipher, De_output, SM4_BLOCK_SIZE, key, iv, SM4_DECRYPT);
if (memcmp(De_output, plain, SM4_BLOCK_SIZE))
puts("cbc dec(len=32) memcmp failed");
else
puts("cbc dec(len=32) memcmp ok");
len = 32;
for (i = 0; i < 8; i++) {
memset(in, i, len);
sm4cbc(in, out, len, key, iv, SM4_ENCRYPT);
sm4cbc(out, chk, len, key, iv, SM4_DECRYPT);
if (memcmp(in, chk, len))
printf("cbc enc/dec(len=%d) memcmp failed\n", len);
else
printf("cbc enc/dec(len=%d) memcmp ok\n", len);
len = 2 * len;
}
return 0;
}
int sm4cfbcheck() {
int i, len, ret = 0;
unsigned char key[16] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };//密钥
unsigned char iv[16] = { 0xeb,0xee,0xc5,0x68,0x58,0xe6,0x04,0xd8,0x32,0x7b,0x9b,0x3c,0x10,0xc9,0x0c,0xa7 }; //初始化向量
unsigned char in[4096], out[4096], chk[4096];
len = 16;
for (i = 0; i < 9; i++) {
memset(in, i, len);
sm4cfb(in, out, len, key, iv, SM4_ENCRYPT);
sm4cfb(out, chk, len, key, iv, SM4_DECRYPT);
if (memcmp(in, chk, len))
printf("cfb enc/dec(len=%d) memcmp failed\n", len);
else
printf("cfb enc/dec(len=%d) memcmp ok\n", len);
len = 2 * len;
}
return 0;
}
int sm4ofbcheck() {
int i, len, ret = 0;
unsigned char key[16] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };//密钥
unsigned char iv[16] = { 0xeb,0xee,0xc5,0x68,0x58,0xe6,0x04,0xd8,0x32,0x7b,0x9b,0x3c,0x10,0xc9,0x0c,0xa7 }; //初始化向量
unsigned char in[4096], out[4096], chk[4096];
len = 16;
for (i = 0; i < 9; i++) {
memset(in, i, len);
sm4ofb(in, out, len, key, iv);
sm4ofb(out, chk, len, key, iv);
if (memcmp(in, chk, len))
printf("ofb enc/dec(len=%d) memcmp failed\n", len);
else
printf("ofb enc/dec(len=%d) memcmp ok\n", len);
len = 2 * len;
}
return 0;
}

一些定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
//sm4.h
#pragma once
#define SM4_ENCRYPT 1
#define SM4_DECRYPT 0
#define SM4_BLOCK_SIZE 16
void SM4_KeySchedule(unsigned char MK[], unsigned int rk[]);//生成轮密钥
void SM4_Encrypt(unsigned char MK[], unsigned char PlainText[], unsigned char CipherText[]);
void SM4_Decrypt(unsigned char MK[], unsigned char CipherText[], unsigned char PlainText[]);
int SM4_SelfCheck();
void sm4ecb(unsigned char* in, unsigned char* out, unsigned int length, unsigned char* key, unsigned int enc);
void sm4cbc(unsigned char* in, unsigned char* out, unsigned int length, unsigned char* key, unsigned char* ivec, unsigned int enc);
void sm4cfb(const unsigned char* in, unsigned char* out, const unsigned int length, unsigned char* key, const unsigned char* ivec, const unsigned int enc);
void sm4ofb(const unsigned char* in, unsigned char* out, const unsigned int length, unsigned char* key, const unsigned char* ivec);

主加密逻辑:

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
//sm4.cpp
#include "sm4.h"
#include <stdio.h>
#include <string.h>
#define SM4_Rotl32(buf, n) (((buf)<<n)|((buf)>>(32-n)))
unsigned int SM4_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
};
unsigned int SM4_FK[4] = { 0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC };
unsigned char SM4_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
};
void SM4_KeySchedule(unsigned char MK[], unsigned int rk[]) {
unsigned int tmp, buf, K[36];
int i;
for (i = 0; i < 4; i++)
K[i] = SM4_FK[i] ^ ((MK[4 * i] << 24) | (MK[4 * i + 1] << 16) | (MK[4 * i + 2] << 8) | (MK[4 * i + 3]));
for (i = 0; i < 32; i++) {
tmp = K[i + 1] ^ K[i + 2] ^ K[i + 3] ^ SM4_CK[i];
//nonlinear operation
buf = (SM4_Sbox[(tmp >> 24) & 0xFF]) << 24 | (SM4_Sbox[(tmp >> 16) & 0xFF]) << 16 | (SM4_Sbox[(tmp >> 8) & 0xFF]) << 8 | (SM4_Sbox[tmp & 0xFF]);
//linear operation
K[i + 4] = K[i] ^ ((buf) ^ (SM4_Rotl32((buf), 13)) ^ (SM4_Rotl32((buf), 23)));
rk[i] = K[i + 4];
}
}
void SM4_Encrypt(unsigned char MK[], unsigned char PlainText[], unsigned char CipherText[]) {
unsigned int rk[32], X[36], tmp, buf;
int i, j;
SM4_KeySchedule(MK, rk);
for (j = 0; j < 4; j++)
X[j] = (PlainText[j * 4] << 24) | (PlainText[j * 4 + 1] << 16) | (PlainText[j * 4 + 2] << 8) | (PlainText[j * 4 + 3]);
for (i = 0; i < 32; i++) {
tmp = X[i + 1] ^ X[i + 2] ^ X[i + 3] ^ rk[i];
//nonlinear operation
buf = (SM4_Sbox[(tmp >> 24) & 0xFF]) << 24 | (SM4_Sbox[(tmp >> 16) & 0xFF]) << 16 | (SM4_Sbox[(tmp >> 8) & 0xFF]) << 8 | (SM4_Sbox[tmp & 0xFF]);
//linear operation
X[i + 4] = X[i] ^ (buf ^ SM4_Rotl32((buf), 2) ^ SM4_Rotl32((buf), 10) ^ SM4_Rotl32((buf), 18) ^ SM4_Rotl32((buf), 24));
}
for (j = 0; j < 4; j++) {
CipherText[4 * j] = (X[35 - j] >> 24) & 0xFF;
CipherText[4 * j + 1] = (X[35 - j] >> 16) & 0xFF;
CipherText[4 * j + 2] = (X[35 - j] >> 8) & 0xFF;
CipherText[4 * j + 3] = (X[35 - j]) & 0xFF;
}
}
void SM4_Decrypt(unsigned char MK[], unsigned char CipherText[], unsigned char PlainText[]) {
unsigned int rk[32], X[36], tmp, buf;
int i, j;
SM4_KeySchedule(MK, rk);
for (j = 0; j < 4; j++)
X[j] = (CipherText[j * 4] << 24) | (CipherText[j * 4 + 1] << 16) | (CipherText[j * 4 + 2] << 8) | (CipherText[j * 4 + 3]);
for (i = 0; i < 32; i++) {
tmp = X[i + 1] ^ X[i + 2] ^ X[i + 3] ^ rk[31 - i];
//nonlinear operation
buf = (SM4_Sbox[(tmp >> 24) & 0xFF]) << 24 | (SM4_Sbox[(tmp >> 16) & 0xFF]) << 16 | (SM4_Sbox[(tmp >> 8) & 0xFF]) << 8 | (SM4_Sbox[tmp & 0xFF]);
//linear operation
X[i + 4] = X[i] ^ (buf ^ SM4_Rotl32((buf), 2) ^ SM4_Rotl32((buf), 10) ^ SM4_Rotl32((buf), 18) ^ SM4_Rotl32((buf), 24));
}
for (j = 0; j < 4; j++) {
PlainText[4 * j] = (X[35 - j] >> 24) & 0xFF;
PlainText[4 * j + 1] = (X[35 - j] >> 16) & 0xFF;
PlainText[4 * j + 2] = (X[35 - j] >> 8) & 0xFF;
PlainText[4 * j + 3] = (X[35 - j]) & 0xFF;
}
}
int SM4_SelfCheck() {
int i;
//Standard data
unsigned char key[16] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };
unsigned char plain[16] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };
unsigned char cipher[16] = { 0x68,0x1e,0xdf,0x34,0xd2,0x06,0x96,0x5e,0x86,0xb3,0xe9,0x4f,0x53,0x6e,0x42,0x46 };
unsigned char En_output[16];
unsigned char De_output[16];
SM4_Encrypt(key, plain, En_output);
SM4_Decrypt(key, cipher, De_output);
for (i = 0; i < 16; i++)
if ((En_output[i] != cipher[i]) | (De_output[i] != plain[i])) {
printf("Self-check error");
return 1;
}
printf("sm4(16字节)自检成功!\n\n");
return 0;
}
void sm4ecb(unsigned char* in, unsigned char* out, unsigned int length, unsigned char* key, unsigned int enc) {
unsigned int len = length;
if ((in == NULL) || (out == NULL) || (key == NULL) || (length % SM4_BLOCK_SIZE != 0))
return;
if ((SM4_ENCRYPT != enc) && (SM4_DECRYPT != enc))
return;
while (len >= SM4_BLOCK_SIZE) {
if (SM4_ENCRYPT == enc)
SM4_Encrypt(key, in, out);
else
SM4_Decrypt(key, in, out);
len -= SM4_BLOCK_SIZE;
in += SM4_BLOCK_SIZE;
out += SM4_BLOCK_SIZE;
}
}
void sm4cbc(unsigned char* in, unsigned char* out, unsigned int length, unsigned char* key, unsigned char* ivec, unsigned int enc) {
unsigned int n;
unsigned int len = length;
unsigned char tmp[SM4_BLOCK_SIZE];
const unsigned char* iv = ivec;
unsigned char iv_tmp[SM4_BLOCK_SIZE];
if ((in == NULL) || (out == NULL) || (key == NULL) || (ivec == NULL) || (length % SM4_BLOCK_SIZE != 0))
return;
if ((SM4_ENCRYPT != enc) && (SM4_DECRYPT != enc))
return;
if (SM4_ENCRYPT == enc) {
while (len >= SM4_BLOCK_SIZE) {
for (n = 0; n < SM4_BLOCK_SIZE; ++n)
out[n] = in[n] ^ iv[n];
SM4_Encrypt(key, out, out);
iv = out;
len -= SM4_BLOCK_SIZE;
in += SM4_BLOCK_SIZE;
out += SM4_BLOCK_SIZE;
}
}
else if (in != out) {
while (len >= SM4_BLOCK_SIZE) {
SM4_Decrypt(key, in, out);
for (n = 0; n < SM4_BLOCK_SIZE; ++n)
out[n] ^= iv[n];
iv = in;
len -= SM4_BLOCK_SIZE;
in += SM4_BLOCK_SIZE;
out += SM4_BLOCK_SIZE;
}
}
else {
memcpy(iv_tmp, ivec, SM4_BLOCK_SIZE);
while (len >= SM4_BLOCK_SIZE) {
memcpy(tmp, in, SM4_BLOCK_SIZE);
SM4_Decrypt(key, in, out);
for (n = 0; n < SM4_BLOCK_SIZE; ++n)
out[n] ^= iv_tmp[n];
memcpy(iv_tmp, tmp, SM4_BLOCK_SIZE);
len -= SM4_BLOCK_SIZE;
in += SM4_BLOCK_SIZE;
out += SM4_BLOCK_SIZE;
}
}
}
void sm4cfb(const unsigned char* in, unsigned char* out, const unsigned int length, unsigned char* key, const unsigned char* ivec, const unsigned int enc) {
unsigned int n = 0;
unsigned int l = length;
unsigned char c;
unsigned char iv[SM4_BLOCK_SIZE];
if ((in == NULL) || (out == NULL) || (key == NULL) || (ivec == NULL))
return;
if ((SM4_ENCRYPT != enc) && (SM4_DECRYPT != enc))
return;
memcpy(iv, ivec, SM4_BLOCK_SIZE);
if (enc == SM4_ENCRYPT) {
while (l--) {
if (n == 0)
SM4_Encrypt(key, iv, iv);
iv[n] = *(out++) = *(in++) ^ iv[n];
n = (n + 1) % SM4_BLOCK_SIZE;
}
}
else {
while (l--) {
if (n == 0)
SM4_Encrypt(key, iv, iv);
c = *(in);
*(out++) = *(in++) ^ iv[n];
iv[n] = c;
n = (n + 1) % SM4_BLOCK_SIZE;
}
}
}
void sm4ofb(const unsigned char* in, unsigned char* out, const unsigned int length, unsigned char* key, const unsigned char* ivec) {
unsigned int n = 0;
unsigned int l = length;
unsigned char iv[SM4_BLOCK_SIZE];
if ((in == NULL) || (out == NULL) || (key == NULL) || (ivec == NULL))
return;
memcpy(iv, ivec, SM4_BLOCK_SIZE);
while (l--) {
if (n == 0)
SM4_Encrypt(key, iv, iv);
*(out++) = *(in++) ^ iv[n];
n = (n + 1) % SM4_BLOCK_SIZE;
}
}

OpenSSL对称加解密通用

EVP_CIPHER_CTX_init初始化密码算法上下文EVP_CIPHER_CTX结构体:

1
2
3
void EVP_CIPHER_CTX_init(
EVP_CIPHER_CTX* a
);

结构体为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct evp_cipher_ctx_st {
const EVP_CIPHER* cipher; //密码算法上下文结构体指针
ENGINE* engine; //密码算法引擎
int encrypt; //标记加密或解密
int buf_len; //运算剩余数据长度
unsigned char oiv[EVP_MAX_IV_LENGTH]; //初始IV
unsigned char iv[EVP_MAX_IV_LENGTH]; //当前IV
unsigned char buf[EVP_MAX_BLOCK_LENGTH]; //部分块
int num; //ECB/OFB/CTR模式用
void* app_data; //应用数据
int key_len; //可能更改为可变长度密码
unsigned long flags; //各种标记
void* cipher_data; //EVP数据
int final_used;
int block_mask;
unsigned char final[EVP_MAX_BLOCK_LENGTH];
};

EVP_EncryptInit_ex用于加密初始化:

1
2
3
4
5
6
7
int EVP_EncryptInit_ex(
EVP_CIPHER_CTX* ctx, //初始化后的算法上下文结构体指针
const EVP_CIPHER* cipher, //具体加密函数
ENGINE* impl, //加密算法引擎 NULL默认
const unsigned char* key, //加密密钥
const unsigned char* iv //初始向量 CBC有效
); //成功1 失败0

cipher可取函数有:

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
EVP_enc_null();

//DES
EVP_des_cbc();
EVP_des_ecb();
EVP_des_cfb();
EVP_des_ofb();

//3DES 俩密钥
EVP_des_ede_cbc();
EVP_des_ede_ecb();
EVP_des_ede_ofb();
EVP_des_ede_cfb();

//3DES 仨密钥
EVP_des_ede3_cbc();
EVP_des_ede3_ecb();
EVP_des_ede3_ofb();
EVP_des_ede3_cfb();

//DESX
EVP_desx_cbc();

//RC4
EVP_rc4();

//40位RC4
EVP_rc4_40();

//IDEA
EVP_idea_cbc();
EVP_idea_ecb();
EVP_idea_cfb();
EVP_idea_ofb();

//RC2
EVP_rc2_cbc();
EVP_rc2_ecb();
EVP_rc2_cfb();
EVP_rc2_ofb();

//定长RC2
EVP_rc2_40_cbc();
EVP_rc2_64_cbc();

//Blowfish
EVP_bf_cbc();
EVP_bf_ecb();
EVP_bf_cfb();
EVP_bf_ofb();

//CAST
EVP_cast5_cbc();
EVP_cast5_ebc();
EVP_cast5_cfb();
EVP_cast5_ofb();

//RC5
EVP_rc5_32_12_16_cbc();
EVP_rc5_32_12_16_ecb();
EVP_rc5_32_12_16_cfb();
EVP_rc5_32_12_16_ofb();

//AES
EVP_aes_128_cbc();
EVP_aes_128_ecb();
EVP_aes_128_cfb();
EVP_aes_128_ofb();
EVP_aes_192_cbc();
EVP_aes_192_ecb();
EVP_aes_192_cfb();
EVP_aes_192_ofb();
EVP_aes_256_cbc();
EVP_aes_256_ecb();
EVP_aes_256_cfb();
EVP_aes_256_ofb();

EVP_EncryptUpdate加密:

1
2
3
4
5
6
7
int EVP_EncryptUpdate(
EVP_CIPHER_CTX* ctx,
unsigned char* out, //输出密文缓冲区
int* outl, //输出密文长度
const unsigned char* in, //明文缓冲区
int inl //明文长度
);

EVP_EncryptFinal_ex用于结束数据加密,并输出最后剩余的密文。当明文长度不为分组长度倍数时,EVP_EncryptUpdate仅返回整块,最后剩下的一个块由该函数返回。

1
2
3
4
5
int EVP_EncryptFinal_ex(
EVP_CIPHER_CTX* ctx,
unsigned char* out, //输出密文缓冲区
int* outl //密文长度
);//成功1 失败0

解密初始化用EVP_DecryptInit_ex

1
2
3
4
5
6
7
int EVP_DecryptInit_ex(
EVP_CIPHER_CTX* ctx,
const EVP_CIPHER* cipher, //解密算法
ENGINE* impl, //解密时用的加密引擎 NULL默认
const unsigned char* key, //解密密钥
const unsigned char* iv //初始向量
);//成功1 失败0

EVP_DecryptUpdate解密数据:

1
2
3
4
5
6
7
int EVP_DecryptUpdate(
EVP_CIPHER_CTX* ctx,
unsigned char* out, //明文缓冲区
int* outl, //明文缓冲区长度
const unsigned char* in, //密文缓冲区
int inl //密文缓冲区长度
);

EVP_DecryptFinal_ex结束解密,输出最后剩余的明文:

1
2
3
4
5
int EVP_DecryptFinal_ex(
EVP_CIPHER_CTX* ctx,
unsigned char* outm, //明文缓冲区
int* outl //明文缓冲区长度
);

EVP_CIPHER_CTX_cleanup清除对称算法上下文数据,如内存中密钥等。

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
#include <openssl/evp.h>
#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#define FAILURE -1
#define SUCCESS 0
int do_encrypt(const EVP_CIPHER* type, const char* ctype) {
unsigned char outbuf[1024];
int outlen, tmplen;
unsigned char key[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 };
unsigned char iv[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
char intext[] = "Helloworld";
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
FILE* out;
EVP_CIPHER_CTX_init(ctx);
EVP_EncryptInit_ex(ctx, type, NULL, key, iv);
if (!EVP_EncryptUpdate(ctx, outbuf, &outlen, (unsigned char*)intext, (int)strlen(intext))) {
printf("EVP_EncryptUpdate\n");
return FAILURE;
}
if (!EVP_EncryptFinal_ex(ctx, outbuf + outlen, &tmplen)) {
printf("EVP_EncryptFinal_ex\n");
return FAILURE;
}
outlen += tmplen;
EVP_CIPHER_CTX_cleanup(ctx);
out = fopen("./cipher.dat", "wb+");
fwrite(outbuf, 1, outlen, out);
fflush(out);
fclose(out);
return SUCCESS;
}
int do_decrypt(const EVP_CIPHER* type, const char* ctype) {
unsigned char inbuf[1024] = { 0 };
unsigned char outbuf[1024] = { 0 };
int outlen, inlen, tmplen;
unsigned char key[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 };
unsigned char iv[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
FILE* in = NULL;
EVP_CIPHER_CTX_init(ctx);
EVP_DecryptInit_ex(ctx, type, NULL, key, iv);
in = fopen("cipher.dat", "r");
inlen = fread(inbuf, 1, sizeof(inbuf), in);
fclose(in);
printf("Readlen: %d\n", inlen);
if (!EVP_DecryptUpdate(ctx, outbuf, &outlen, inbuf, inlen)) {
printf("EVP_DecryptUpdate\n");
return FAILURE;
}
if (!EVP_DecryptFinal_ex(ctx, outbuf + outlen, &tmplen)) {
printf("EVP_DecryptFinal_ex\n");
return FAILURE;
}
outlen += tmplen;
EVP_CIPHER_CTX_cleanup(ctx);
printf("Result: \n%s\n", outbuf);
return SUCCESS;
}
int main(int argc, char* argv[]) {
do_encrypt(EVP_des_cbc(), "des-cbc");
do_decrypt(EVP_des_cbc(), "des-cbc");
do_encrypt(EVP_des_ede_cbc(), "des-ede-cbc");
do_decrypt(EVP_des_ede_cbc(), "des-ede-cbc");
do_encrypt(EVP_des_ede3_cbc(), "des-ede3-cbc");
do_decrypt(EVP_des_ede3_cbc(), "des-ede3-cbc");
return 0;
}