Base64

一种基于64个可打印的字符来表示二进制的数据的一种方法。

https://cloud.tencent.com/developer/article/1868972

动画演示

总的来说就是把原数据的二进制按3字节分块,后再按6位二进制分成4块,然后在每组二进制前面补00,变成8位(一块二进制内少于6位在末尾补0,三字节数据块内存在空字节就用等号补上。),按分块的二进制表示的值为索引到表中去寻找对应的元素。

解码时按4字节到表中寻找元素后计算索引按三字节恢复就行。

源码解读,来自

https://gitcode.com/g310773517/base64/overview?isLogin=1

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
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define _CRT_SECURE_NO_WARNINGS

//base64查询表
char* base64_encodetable = (char*)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

//base64反查询表
char base64_decodetable[128] = { //把结果的索引与结果进行映射,可以直接按下标查找
-1, -1, -1, -1, -1, -1, -1, -1, //0-7
-1, -1, -1, -1, -1, -1, -1, -1, //8-15
-1, -1, -1, -1, -1, -1, -1, -1, //16-23
-1, -1, -1, -1, -1, -1, -1, -1, //24-31
-1, -1, -1, -1, -1, -1, -1, -1, //32-39
-1, -1, -1, 62, -1, -1, -1, 63, //40-47, + /
52, 53, 54, 55, 56, 57, 58, 59, //48-55, 0-7
60, 61, -1, -1, -1, 0, -1, -1, //56-63, 8-9
-1, 0, 1, 2, 3, 4, 5, 6, //64-71, A-G
7, 8, 9, 10, 11, 12, 13, 14, //72-79, H-O
15, 16, 17, 18, 19, 20, 21, 22, //80-87, P-W
23, 24, 25, -1, -1, -1, -1, -1, //88-95, X-Z
-1, 26, 27, 28, 29, 30, 31, 32, //96-103, a-g
33, 34, 35, 36, 37, 38, 39, 40, //104-111, h-o
41, 42, 43, 44, 45, 46, 47, 48, //112-119, p-w
49, 50, 51, -1, -1, -1, -1, -1, //120-127, x-z
};

//数字字符串表
static char* num_table = (char*)"0123456789";

//char类型数转换为2进制字符串格式, 如2->"10", 6->"110"
static char* char2binstr(char value)
{
int i = 0;
char binstr[9] = {};

//取到每一位之后,查表得到对应的字符拼接成一个字符串
for (i = 0; i < 8; i++)
binstr[7 - i] = num_table[(value & (0x1 << i)) >> i];

return _strdup(binstr);
}

//2进制字符串格式数据转换为char类型数,如"10"->2, "110"->6
static char binstr2char(char* binstr)
{
int i = 0;
char value = 0;
int length = 0;

if (!binstr)
return 0;

length = strlen(binstr);

//取得2进制字符串的每一个字节,将其转化对应的数字,然后还原数据。
for (i = 0; i < length; i++)
value += (binstr[length - 1 - i] - 0x30) << i;

return value;
}

/*
* Base64编码说明
* Base64编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之后在6位的前面补两个0,形成8位一个字节的形式。
* 如果剩下的字符不足3个字节,则用0填充,输出字符使用'=',因此编码后输出的文本末尾可能会出现1或2个'='。
* Base64制定了一个编码表,以便进行统一转换。编码表的大小为2^6=64,这也是Base64名称的由来。
*/
static char* _base64_section_encode(char* src, int length)
{
int i = 0;
char dest[5] = "====";
char binstr[33] = "000000000000000000000000";
char tmp[7] = {};
char* tmp1 = NULL;

//每字节8位,每次转换3字节,不足3字节时,高位补0
//先拼接一个完整的24字节2进制字符串
for (i = 0; i < length; i++) {
tmp1 = char2binstr(src[i]);
strncpy((char*)binstr + i * 8, tmp1, 8);
free(tmp1);
}

//24字节,分4组,每组6字节,将每组转换为数字格式,每个数字查表得到对应码。
//3种情况:
// 1. 如果最后剩下1个数据,编码结果后加2个=,即查表2次,查表次数正好是数据字节数 + 1
// 2. 如果最后剩下2个数据,编码结果后加1个=,即查表3次
// 3. 如果没有剩下任何数据(剩下3个数据),就什么都不要加,即查表4次
for (i = 0; i < length + 1; i++) {
strncpy(tmp, binstr + 6 * i, 6);
dest[i] = base64_encodetable[binstr2char(tmp)];
}

return _strdup(dest);
}

//输入原始内容和长度,得到base64编码
char* base64_encode(char* src, int length)
{
int i = 0;
char* base64code = NULL;
int codelength = 0;
char* tmp = NULL;

//每3个字节一组转化为4字节(每6位一组得到4组,转换为新字符),不足3字节的填充到3字节进行转化。
//因此计算共有多少组转换后的4字节乘以4就是编码后的长度
codelength = ((length / 3) + (length % 3 > 0 ? 1 : 0)) * 4;
base64code = (char*)malloc(codelength + 1);
memset(base64code, 0, codelength + 1);

for (i = 0; i < length / 3; i++) {
tmp = _base64_section_encode(src + i * 3, 3);
strcat(base64code, tmp);
free(tmp);
}

if (length % 3) {
tmp = _base64_section_encode(src + length - (length % 3), length % 3);
strcat(base64code, tmp);
free(tmp);
}
return base64code;
}

//4字节反转化为3字节
static char* _base64_section_decode(char* dest)
{
int i = 0;
int j = 0;
static char src[3] = {};
char tmp[9] = {};

memset(src, 0, sizeof(src) / sizeof(src[0]));
for (i = 0; i < 3; i++) {
strncpy(tmp, dest + 8 * i, 8);
src[i] = binstr2char(tmp);
}

return src;
}

int base64_decode_length(char* src)
{
int length = 0;
int padding_count = 0;

if (src[strlen(src) - 1] == '=')
padding_count++;

if (src[strlen(src) - 2] == '=')
padding_count++;

length = strlen(src) / 4 * 3 - padding_count;
return 0;
}

//输入base64编码后文本,解码出原始内容
char* base64_decode(char* src, int* destlen)
{
int i = 0;
int j = 0;
char* binstr = NULL;
int binstr_length = 0;
char* tmp = NULL;
char* tmp1 = NULL;
char* dest = NULL;
int cnt = 0;

binstr_length = strlen(src) * 8 + 1;
binstr = (char*)malloc(binstr_length);
memset(binstr, 0, binstr_length);

*destlen = base64_decode_length(src);
dest = (char*)malloc(*destlen);
memset(dest, 0, *destlen);

for (i = 0; i < strlen(src) / 4; i++) {
for (j = 0; j < 4; j++) {
tmp1 = char2binstr(base64_decodetable[src[i * 4 + j]]);
strcat(binstr, tmp1 + 2);
free(tmp1);
}
}

for (i = 0; i < strlen(src) / 4; i++) {
//因为_base64_section_decode函数每次固定返回3字节数据,此处需要根据提前计算出来的解码总长度和已解码长度来判断最后1次需要拷贝的准确数据量。
tmp = _base64_section_decode(binstr + i * 24);
memmove(dest + i * 3, tmp, *destlen - cnt < 3 ? *destlen - cnt : 3);
cnt += 3;
}

free(binstr);

return dest;
}
int main() {
char a[10] = "systema";
char * b = base64_encode(a, strlen(a));
printf("%s", b);
}

一般形式(特征)

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
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

char* encodeBase64(char* str, int len ) {
char base64[65] = "stuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr";
//读取3个字节zxc,转换为二进制01111010 01111000 01100011
//转换为4个6位字节,011110 100111 100001 100011
//不足8位在前补0,变成00011110 00100111 00100001 00100011
//若剩余的字节数不足以构成4个字节,补等号
int encodeStrLen = 1 + (len / 3) * 4, k = 0;
encodeStrLen += len % 3 ? 4 : 0;
char* encodeStr = (char*)(malloc(sizeof(char) * encodeStrLen));
for (int i = 0; i < len; i++) {
if (len - i >= 3) {
encodeStr[k++] = base64[(unsigned char)str[i] >> 2];
unsigned char a = ((unsigned char)str[i] & 0x03) ;
unsigned char b = (unsigned char)str[++i];
unsigned char c = a << 4 | b >> 4;
encodeStr[k++] = base64[ c];
a = ((unsigned char)str[i] & 0x0f);
b = (unsigned char)str[++i];
c = a << 2 | b >> 6;
encodeStr[k++] = base64[c ];
encodeStr[k++] = base64[(unsigned char)str[i] & 0x3f];
}
else if (len - i == 2) {
encodeStr[k++] = base64[(unsigned char)str[i] >> 2];
encodeStr[k++] = base64[((unsigned char)str[i] & 0x03) << 4 | ((unsigned char)str[++i] >> 4)];
encodeStr[k++] = base64[((unsigned char)str[i] & 0x0f) << 2];
encodeStr[k++] = '=';
}
else {
encodeStr[k++] = base64[(unsigned char)str[i] >> 2];
encodeStr[k++] = base64[((unsigned char)str[i] & 0x03) << 4]; //末尾补两个等于号
encodeStr[k++] = '=';
encodeStr[k++] = '=';
}
}
encodeStr[k] = '\0';
return encodeStr;
}

/**
* 解码既编码的逆过程,先找出编码后的字符在编码之前代表的数字
* 编码中将3位个字符变成4个字符,得到这4个字符的每个字符代表的原本数字
* 因为在编码中间每个字符用base64码表进行了替换,所以这里要先换回来
* 在对换回来的数字进行位运算使其还原成3个字符
*/
int decodeBase64(char* str, int len) {
char base64[65] = "stuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr";
unsigned char ascill[129] = {0};
int k = 0;
printf("table\n");
for (int i = 0; i < 64; i++) {
ascill[base64[i]] = k++;
}
for (int i = 0; i < 129; i++) {
printf("%d,", ascill[i]);
}
printf("\n");
int decodeStrlen = len / 4 * 3 + 1;
char* decodeStr = (char*)malloc(sizeof(char) * decodeStrlen);
k = 0;
for (int i = 0; i < len; i++) {
unsigned char a, b, c;
a = ascill[str[i]];
b = ascill[str[++i]];
c = (a << 2) | (b >> 4);
decodeStr[k++] = c;
if (str[i + 1] == '=') {
break;
}
a = ascill[str[i]];
b = ascill[str[++i]];
c = (a << 4) |( b >> 2);
decodeStr[k++] = c;
if (str[i + 1] == '=') {
break;
}
a = ascill[str[i]];
b = ascill[str[++i]];
c = (a << 6) | (b);
decodeStr[k++] = c;
}
decodeStr[k] = '\0';
for (int i = 0; i <= k; i++) {
str[i] = decodeStr[i];
}
free(decodeStr);
return k;
}

int main() {
char input[100] = { };
char dec[100] = { };

}


Salsa20

需要的数据:8字节的随机数noce,128位或256位的密钥,不定长度明文/密文,一个16字节密钥拓展常量”expand 32-byte k”,一个常量[0x61707865, 0x3320646e, 0x79622d32, 0x6b206574]。

加密流程,密钥拓展->把拓展的密钥和随机数,计数器,常量排列成一个4x4的矩阵,每个元素4字节->行列分别多轮加密每行/列3个为一组加密->把矩阵拆分成单字节的盒->明文与盒异或

加解密脚本

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
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>

enum s20_status_t //返回加解密结果状态
{
S20_SUCCESS,
S20_FAILURE
};

enum s20_keylen_t //salsa20支持128和256位密钥
{
S20_KEYLEN_256,
S20_KEYLEN_128
};

static uint32_t rotl(uint32_t value, int shift) //32位数据位移交换操作
{
return (value << shift) | (value >> (32 - shift));
}

static void s20_quarterround(uint32_t* y0, uint32_t* y1, uint32_t* y2, uint32_t* y3) //行列加密逻辑
{
*y1 = *y1 ^ rotl(*y0 + *y3, 7);
*y2 = *y2 ^ rotl(*y1 + *y0, 9);
*y3 = *y3 ^ rotl(*y2 + *y1, 13);
*y0 = *y0 ^ rotl(*y3 + *y2, 18);
}

static void s20_rowround(uint32_t y[16]) //列加密
{
s20_quarterround(&y[0], &y[1], &y[2], &y[3]);
s20_quarterround(&y[5], &y[6], &y[7], &y[4]);
s20_quarterround(&y[10], &y[11], &y[8], &y[9]);
s20_quarterround(&y[15], &y[12], &y[13], &y[14]);
}

static void s20_columnround(uint32_t x[16]) //行加密
{
s20_quarterround(&x[0], &x[4], &x[8], &x[12]);
s20_quarterround(&x[5], &x[9], &x[13], &x[1]);
s20_quarterround(&x[10], &x[14], &x[2], &x[6]);
s20_quarterround(&x[15], &x[3], &x[7], &x[11]);
}

static void s20_doubleround(uint32_t x[16]) //行列加密,这次就是一轮加密
{
s20_columnround(x);
s20_rowround(x);
}

// Creates a little-endian word from 4 bytes pointed to by b
static uint32_t s20_littleendian(uint8_t* b) //端序转化,字节数据转小端序4字节
{
return b[0] +
((uint_fast16_t)b[1] << 8) +
((uint_fast32_t)b[2] << 16) +
((uint_fast32_t)b[3] << 24);
}

// Moves the little-endian word into the 4 bytes pointed to by b
static void s20_rev_littleendian(uint8_t* b, uint32_t w) //4字节按小端序转字节数据
{
b[0] = w;
b[1] = w >> 8;
b[2] = w >> 16;
b[3] = w >> 24;
}

// The core function of Salsa20
static void s20_hash(uint8_t seq[64])
{
int i;
uint32_t x[16];
uint32_t z[16];

for (i = 0; i < 16; ++i)
x[i] = z[i] = s20_littleendian(seq + (4 * i)); //转成4字节分组加密

for (i = 0; i < 10; ++i) //轮加密
s20_doubleround(z);

for (i = 0; i < 16; ++i) {
z[i] += x[i];
s20_rev_littleendian(seq + (4 * i), z[i]); //转成单字节生成盒
}
}

// The 16-byte (128-bit) key expansion function
static void s20_expand16(uint8_t* k, //密钥拓展
uint8_t n[16],
uint8_t keystream[64])
{
int i, j;
// The constants specified by the Salsa20 specification, 'tau'
// "expand 16-byte k"
uint8_t t[4][4] = {
{ 'e', 'x', 'p', 'a' },
{ 'n', 'd', ' ', '1' },
{ '6', '-', 'b', 'y' },
{ 't', 'e', ' ', 'k' }
};

// Copy all of 'tau' into the correct spots in our keystream block
for (i = 0; i < 64; i += 20)
for (j = 0; j < 4; ++j)
keystream[i + j] = t[i / 20][j];

// Copy the key and the nonce into the keystream block
for (i = 0; i < 16; ++i) {
keystream[4 + i] = k[i];
keystream[44 + i] = k[i];
keystream[24 + i] = n[i];
}

s20_hash(keystream);
}


// The 32-byte (256-bit) key expansion function
static void s20_expand32(uint8_t* k,
uint8_t n[16],
uint8_t keystream[64])
{
int i, j;
// The constants specified by the Salsa20 specification, 'sigma'
// "expand 32-byte k"
uint8_t o[4][4] = {
{ 'e', 'x', 'p', 'a' },
{ 'n', 'd', ' ', '3' },
{ '2', '-', 'b', 'y' },
{ 't', 'e', ' ', 'k' }
};

// Copy all of 'sigma' into the correct spots in our keystream block
for (i = 0; i < 64; i += 20)
for (j = 0; j < 4; ++j)
keystream[i + j] = o[i / 20][j];

// Copy the key and the nonce into the keystream block
for (i = 0; i < 16; ++i) {
keystream[4 + i] = k[i];
keystream[44 + i] = k[i + 16];
keystream[24 + i] = n[i];
}

s20_hash(keystream);
}

enum s20_status_t s20_crypt( //加解密函数
uint8_t* key, //密钥
enum s20_keylen_t keylen, //密钥长度
uint8_t nonce[8], //随机数
uint32_t si, //密钥偏移量,决定从什么时候使用密钥
uint8_t* buf, //要输入的数据
uint32_t buflen) //数去的长度
{
uint8_t keystream[64]; //密钥流,盒
uint8_t n[16] = { 0 }; //随机数和计数器
uint32_t i;

void (*expand)(uint8_t*, uint8_t*, uint8_t*) = NULL;
if (keylen == S20_KEYLEN_256)
expand = s20_expand32;
if (keylen == S20_KEYLEN_128)
expand = s20_expand16;

if (expand == NULL || key == NULL || nonce == NULL || buf == NULL)
return S20_FAILURE;

for (i = 0; i < 8; ++i)
n[i] = nonce[i]; //生成随机数与计数器

if (si % 64 != 0) {
s20_rev_littleendian(n + 8, si / 64);
(*expand)(key, n, keystream);
}

for (i = 0; i < buflen; ++i) {
if ((si + i) % 64 == 0) {
s20_rev_littleendian(n + 8, ((si + i) / 64));
(*expand)(key, n, keystream); //密钥拓展,生成盒
}

buf[i] ^= keystream[(si + i) % 64]; //与原数据异或加密
}

return S20_SUCCESS;
}

int main() {

uint8_t key[32] = { 0x59, 0x6F, 0x75, 0x74, 0x68, 0x20, 0x53, 0x74,0x72,0x65, 0x6E, 0x67, 0x74, 0x68, 0x65, 0x6E, 0x73,0x20, 0x74, 0x68, 0x65, 0x20, 0x4E, 0x61,0x74, 0x69, 0x6F, 0x6E };
uint8_t nonce[8] = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 };
unsigned char data[48] = {
0x5E, 0x13, 0xAA, 0xD3, 0x87, 0x75, 0x2B, 0x7A, 0x1B, 0x16, 0x04, 0xA3, 0x49, 0x7E, 0x1D, 0xD2,
0x6B, 0x5D, 0x58, 0x40, 0x5E, 0x44, 0x63, 0x59, 0x48, 0x51, 0x0D, 0x54, 0x5E, 0x58, 0x55, 0x58,
0xAD, 0x82, 0xAF, 0xDC, 0xE7, 0xAB, 0x58, 0x5D, 0xCE, 0xC1, 0xFD, 0xF7, 0xFF, 0x7F, 0x0, 0x0
};

printf("%d",s20_crypt(key, S20_KEYLEN_256, nonce, 0, (uint8_t*)data, 48));

for (int i = 0; i < 48; i++) {
printf("%c", data[i]);
}
}

参考ChaCha20加密 与 Salsa20加密 - TLSN - 博客园

[【动画密码学】Salsa20|流密码_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1Bj411q7Kr?spm_id_from=333.788.recommend_more_video.-1&vd_source=7b352c7cd2bdf055df2dc80c7bf5002c)

[alexwebr/salsa20: An implementation of the Salsa20 stream cipher in C99](https://github.com/alexwebr/salsa20)

ChaCha20

需要的数据:一个计数器counter一般为0,8字节的随机数noce,128位或256位的密钥,不定长度明文/密文,一个16字节密钥拓展常量”expand 32-byte k”,。

加密流程,密钥拓展->把拓展的密钥和随机数,计数器,常量排列成一个4x4的矩阵(顺序排列),每个元素4字节->列加密,斜对角加密,相比salsa20还多了一次异或->把矩阵拆分成单字节的盒->明文与盒异或.

加解密脚本

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
#include <stdint.h>
#include <string.h>
#include <stdio.h>

static inline void u32t8le(uint32_t v, uint8_t p[4]) {
p[0] = v & 0xff;
p[1] = (v >> 8) & 0xff;
p[2] = (v >> 16) & 0xff;
p[3] = (v >> 24) & 0xff;
}

static inline uint32_t u8t32le(uint8_t p[4]) {
uint32_t value = p[3];

value = (value << 8) | p[2];
value = (value << 8) | p[1];
value = (value << 8) | p[0];

return value;
}

static inline uint32_t rotl32(uint32_t x, int n) {
// http://blog.regehr.org/archives/1063
return x << n | (x >> (-n & 31));
}

// https://tools.ietf.org/html/rfc7539#section-2.1
static void chacha20_quarterround(uint32_t* x, int a, int b, int c, int d) {
x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 16);
x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 12);
x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 8);
x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 7);
}

static void chacha20_serialize(uint32_t in[16], uint8_t output[64]) {
int i;
for (i = 0; i < 16; i++) {
u32t8le(in[i], output + (i << 2));
}
}

static void chacha20_block(uint32_t in[16], uint8_t out[64], int num_rounds) { // num_rounds 一般为20
int i;
uint32_t x[16];

memcpy(x, in, sizeof(uint32_t) * 16);

for (i = num_rounds; i > 0; i -= 2) {
//odd round
chacha20_quarterround(x, 0, 4, 8, 12);
chacha20_quarterround(x, 1, 5, 9, 13);
chacha20_quarterround(x, 2, 6, 10, 14);
chacha20_quarterround(x, 3, 7, 11, 15);
//even round
chacha20_quarterround(x, 0, 5, 10, 15);
chacha20_quarterround(x, 1, 6, 11, 12);
chacha20_quarterround(x, 2, 7, 8, 13);
chacha20_quarterround(x, 3, 4, 9, 14);
}

for (i = 0; i < 16; i++) {
x[i] += in[i];
}

chacha20_serialize(x, out);
}

// https://tools.ietf.org/html/rfc7539#section-2.3
static void chacha20_init_state(uint32_t s[16], uint8_t key[32], uint32_t counter, uint8_t nonce[12]) {
int i;

// refer: https://dxr.mozilla.org/mozilla-beta/source/security/nss/lib/freebl/chacha20.c
// convert magic number to string: "expand 32-byte k"
s[0] = 0x61707865;
s[1] = 0x3320646e;
s[2] = 0x79622d32;
s[3] = 0x6b206574;

for (i = 0; i < 8; i++) {
s[4 + i] = u8t32le(key + i * 4);
}

s[12] = counter;

for (i = 0; i < 3; i++) {
s[13 + i] = u8t32le(nonce + i * 4);
}
}

void ChaCha20XOR(uint8_t key[32], uint32_t counter, uint8_t nonce[12], uint8_t* in, uint8_t* out, int inlen) {
int i, j;

uint32_t s[16];
uint8_t block[64];

chacha20_init_state(s, key, counter, nonce);

for (i = 0; i < inlen; i += 64) {
chacha20_block(s, block, 20);
s[12]++;

for (j = i; j < i + 64; j++) {
if (j >= inlen) {
break;
}
out[j] = in[j] ^ block[j - i];
}
}
}

int main(int argc, char** argv) {
int i;

uint8_t nonce[8] = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 };
unsigned char data[48] = {
0x5E, 0x13, 0xAA, 0xD3, 0x87, 0x75, 0x2B, 0x7A, 0x1B, 0x16, 0x04, 0xA3, 0x49, 0x7E, 0x1D, 0xD2,
0x6B, 0x5D, 0x58, 0x40, 0x5E, 0x44, 0x63, 0x59, 0x48, 0x51, 0x0D, 0x54, 0x5E, 0x58, 0x55, 0x58,
0xAD, 0x82, 0xAF, 0xDC, 0xE7, 0xAB, 0x58, 0x5D, 0xCE, 0xC1, 0xFD, 0xF7, 0xFF, 0x7F, 0x0, 0x0
};

uint8_t key[32] = { 0x59, 0x6F, 0x75, 0x74, 0x68, 0x20, 0x53, 0x74, 0x72, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x65, 0x6E,
0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4E, 0x61, 0x74, 0x69, 0x6F, 0x6E ,0x0,0x0,0x0,0x0 };

uint8_t encrypt[114];

ChaCha20XOR(key, 0, nonce, data, encrypt, 48);

for (int i = 0; i < 48; i++) {
printf("%c", encrypt[i]);
}


return 0;
}

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
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>

struct chacha20_context
{
uint32_t keystream32[16];
size_t position;

uint8_t key[32];
uint8_t nonce[12];
uint64_t counter;

uint32_t state[16];
};

void chacha20_init_context(struct chacha20_context* ctx, uint8_t key[], uint8_t nounc[], uint64_t counter);

void chacha20_xor(struct chacha20_context* ctx, uint8_t* bytes, size_t n_bytes);


static uint32_t rotl32(uint32_t x, int n)
{
return (x << n) | (x >> (32 - n));
}

static uint32_t pack4(const uint8_t* a)
{
uint32_t res = 0;
res |= (uint32_t)a[0] << 0 * 8;
res |= (uint32_t)a[1] << 1 * 8;
res |= (uint32_t)a[2] << 2 * 8;
res |= (uint32_t)a[3] << 3 * 8;
return res;
}

static void unpack4(uint32_t src, uint8_t* dst) {
dst[0] = (src >> 0 * 8) & 0xff;
dst[1] = (src >> 1 * 8) & 0xff;
dst[2] = (src >> 2 * 8) & 0xff;
dst[3] = (src >> 3 * 8) & 0xff;
}

static void chacha20_init_block(struct chacha20_context* ctx, uint8_t key[], uint8_t nonce[])
{
memcpy(ctx->key, key, sizeof(ctx->key));
memcpy(ctx->nonce, nonce, sizeof(ctx->nonce));

const uint8_t* magic_constant = (uint8_t*)"expand 32-byte k";
ctx->state[0] = pack4(magic_constant + 0 * 4);
ctx->state[1] = pack4(magic_constant + 1 * 4);
ctx->state[2] = pack4(magic_constant + 2 * 4);
ctx->state[3] = pack4(magic_constant + 3 * 4);
ctx->state[4] = pack4(key + 0 * 4);
ctx->state[5] = pack4(key + 1 * 4);
ctx->state[6] = pack4(key + 2 * 4);
ctx->state[7] = pack4(key + 3 * 4);
ctx->state[8] = pack4(key + 4 * 4);
ctx->state[9] = pack4(key + 5 * 4);
ctx->state[10] = pack4(key + 6 * 4);
ctx->state[11] = pack4(key + 7 * 4);
// 64 bit counter initialized to zero by default.
ctx->state[12] = 0;
ctx->state[13] = pack4(nonce + 0 * 4);
ctx->state[14] = pack4(nonce + 1 * 4);
ctx->state[15] = pack4(nonce + 2 * 4);

memcpy(ctx->nonce, nonce, sizeof(ctx->nonce));
}

static void chacha20_block_set_counter(struct chacha20_context* ctx, uint64_t counter)
{
ctx->state[12] = (uint32_t)counter;
ctx->state[13] = pack4(ctx->nonce + 0 * 4) + (uint32_t)(counter >> 32);
}

static void chacha20_block_next(struct chacha20_context* ctx) {
// This is where the crazy voodoo magic happens.
// Mix the bytes a lot and hope that nobody finds out how to undo it.
for (int i = 0; i < 16; i++) ctx->keystream32[i] = ctx->state[i];

#define CHACHA20_QUARTERROUND(x, a, b, c, d) \
x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 16); \
x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 12); \
x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 8); \
x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 7);

for (int i = 0; i < 10; i++)
{
CHACHA20_QUARTERROUND(ctx->keystream32, 0, 4, 8, 12)
CHACHA20_QUARTERROUND(ctx->keystream32, 1, 5, 9, 13)
CHACHA20_QUARTERROUND(ctx->keystream32, 2, 6, 10, 14)
CHACHA20_QUARTERROUND(ctx->keystream32, 3, 7, 11, 15)
CHACHA20_QUARTERROUND(ctx->keystream32, 0, 5, 10, 15)
CHACHA20_QUARTERROUND(ctx->keystream32, 1, 6, 11, 12)
CHACHA20_QUARTERROUND(ctx->keystream32, 2, 7, 8, 13)
CHACHA20_QUARTERROUND(ctx->keystream32, 3, 4, 9, 14)
}

for (int i = 0; i < 16; i++) ctx->keystream32[i] += ctx->state[i];

uint32_t* counter = ctx->state + 12;
// increment counter
counter[0]++;
if (0 == counter[0])
{
// wrap around occured, increment higher 32 bits of counter
counter[1]++;
// Limited to 2^64 blocks of 64 bytes each.
// If you want to process more than 1180591620717411303424 bytes
// you have other problems.
// We could keep counting with counter[2] and counter[3] (nonce),
// but then we risk reusing the nonce which is very bad.
assert(0 != counter[1]);
}
}

void chacha20_init_context(struct chacha20_context* ctx, uint8_t key[], uint8_t nonce[], uint64_t counter)
{
memset(ctx, 0, sizeof(struct chacha20_context));

chacha20_init_block(ctx, key, nonce);
chacha20_block_set_counter(ctx, counter);

ctx->counter = counter;
ctx->position = 64;
}

void chacha20_xor(struct chacha20_context* ctx, uint8_t* bytes, size_t n_bytes)
{
uint8_t* keystream8 = (uint8_t*)ctx->keystream32;
for (size_t i = 0; i < n_bytes; i++)
{
if (ctx->position >= 64)
{
chacha20_block_next(ctx);
for (int i = 0; i < 64; i++) {
printf("%.2x,", keystream8[i]);
}
ctx->position = 0;
}
bytes[i] ^= keystream8[ctx->position];
ctx->position++;
}
}


int main() {


uint8_t nonce[8] = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 };
unsigned char data[48] = {
0x5E, 0x13, 0xAA, 0xD3, 0x87, 0x75, 0x2B, 0x7A, 0x1B, 0x16, 0x04, 0xA3, 0x49, 0x7E, 0x1D, 0xD2,
0x6B, 0x5D, 0x58, 0x40, 0x5E, 0x44, 0x63, 0x59, 0x48, 0x51, 0x0D, 0x54, 0x5E, 0x58, 0x55, 0x58,
0xAD, 0x82, 0xAF, 0xDC, 0xE7, 0xAB, 0x58, 0x5D, 0xCE, 0xC1, 0xFD, 0xF7, 0xFF, 0x7F, 0x0, 0x0
};

uint8_t key[32] = { 0x59, 0x6F, 0x75, 0x74, 0x68, 0x20, 0x53, 0x74, 0x72, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x65, 0x6E,
0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4E, 0x61, 0x74, 0x69, 0x6F, 0x6E ,0x0,0x0,0x0,0x0};

struct chacha20_context ctx;

chacha20_init_context(&ctx, key, nonce, 0);
chacha20_xor(&ctx,(uint8_t*) data,48);

printf("\n");
for (int i = 0; i < 48; i++) {
printf("%.2x,", data[i]);
}
}

Ginurx/chacha20-c: ChaCha20 stream cipher implemented in C

ChaCha20加密 与 Salsa20加密 - TLSN - 博客园


RC4

https://blog.csdn.net/xiao__1bai/article/details/123357156

演示动画

对称加密算法,可以用写内存解决。

单字节加密。

大概流程:初始化盒S,用密钥初始化盒子T,用S和T的值做为索引组合交换盒S中的内容打乱S盒,遍历要加密的数据,再次用S盒中的数据作为下标和S盒内的数据进行交换打乱,把S盒中的数据相加作为索引在S盒中寻找数据与原数据进行异或。

代码解读

来自上面的链接

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
#include<stdio.h>

/*
程序实现时,需要注意的是,状态向量数组S和临时向量数组T
的类型应设为unsigned char,而不是char。因为在一些机器
下,将char默认做为signed char看待,在算法中计算下标i,j的
时候,会涉及char转int,如果是signed的char,那么将char的8
位拷贝到int的低8位后,还会根据char的符号为,在int的高位补
0或1。由于密钥是随机产生的,如果遇到密钥的某个字节的高
位为1的话,那么计算得到的数组下标为负数,就会越界。
*/
typedef struct _RC4INFO
{
unsigned char s_box[256];
unsigned char t_box[256];
}RC4_INFO,*PRC4_INFO; //定义 RC4 中要用到的 S-Box 和临时向量 T,封装在结构体中并给正常别名和指针别名。


/*
初始化函数 需要传入key 以及 keylen
主要有几个步骤
1.初始化Sbox
2.将key填充到Tbox中
3.组合sbox[i] 与 tbox[i] 然后进行交换
*/
void rc4_init(PRC4_INFO prc4,unsigned char key[],unsigned int keylen)
{
int i=0;
int j=0;
unsigned char tmp;
if(prc4==NULL)
{
return;
}

/*
初始化存储0-255字节的Sbox(其实就是一个数组)
填充key到256个字节数组中称为Tbox(你输入的key不满256个字节则初始化到256个字节)
*/
for(i=0;i<256;i++)
{
prc4->s_box[i] = i;
prc4->t_box[i] = key[i % keylen]; //如果密钥的长度是256字节,就直接把密钥的值赋给k,否则,轮转地将密钥的每个字节赋给k
}

//交换s[i]与s[j] i 从0开始一直到255下标结束. j是 s[i]与T[i]组合得出的下标
for(i=0;i<256;i++)
{
j=(j+prc4->s_box[i]+prc4->t_box[i])%256;
//开始交换
tmp=prc4->s_box[i];
prc4->s_box[i]=prc4->s_box[j];
prc4->s_box[j]=tmp;
}
}

/*
RC4加密其实就是遍历数据,将数据与sbox进行异或加密,而在此之前还需要交换一次sbox的数据
交换完之后 再把s[i] + s[j]的组合当做下标再去异或.
*/
void rc4_crypt(unsigned char data[],unsigned int datalen,unsigned char key[],unsigned int keylen) //参数分别是要加密的数据、要加密的数据长度、加密数据所用的Key、加密数据所用的key长度
{
int dn=0; //data[n]的意思
int i=0;
int j=0; //i j分别用于交换sbox[i] 和 sbox[j]
int t=0; //t = s[i] +s[j]
unsigned char tmp;

RC4_INFO rc4; //这里定义前面的结构题
rc4_init(&rc4,key,keylen); //在加密函数中调用初始化函数,就省去了其它代码中出现的要保存初始化 sBox 的现象了.

for(dn=0;dn<datalen;dn++)
{
//i确保S-box的每个元素都得到处理,j保证S-box的搅乱是随机的。
i=(i+1)%256;
j=(j+rc4.s_box[i])%256;

//交换 s_box[i] 和 s_box[j]
tmp=rc4.s_box[i];
rc4.s_box[i] = rc4.s_box[j];
rc4.s_box[j] = tmp;

//交换完之后 再把s[i] + s[j]的组合当做下标再去异或.
t = (rc4.s_box[i] + rc4.s_box[j]) % 256;
data[dn] ^= rc4.s_box[t];
}
}

void EntryBuffer(unsigned char data[],unsigned int datalen)
{
unsigned char key[]="pjrHeldsadf";
rc4_crypt(data,datalen,key,sizeof(key)/sizeof(key[0]));
}

int main()
{
char Hell[] = "黄河远上白云间";
printf("加密前:pData=%s\n\n", Hell);
EntryBuffer((unsigned char*)Hell,sizeof(Hell)/sizeof(Hell[0])); //加第一次调用就是加密
printf("加密后:pData=%s\n\n", Hell);
EntryBuffer((unsigned char*)Hell,sizeof(Hell)/sizeof(Hell[0])); //由于异或运算的对合性,RC4加密解密使用同一套算法。
printf("解密后:pData=%s\n\n", Hell);
return 0;
}

一般形式(特征)

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<stdio.h> 
#include<stdlib.h>
#include<string.h>

//s 表的长度取 256
#define size 256

unsigned char sbox[257] = { 0 };

// 初始化 s 表
void init_sbox(unsigned char* key) {
unsigned int i, j, k;
int tmp;

for (i = 0; i < size; i++) {
sbox[i] = i;
}

j =k = 0;
for (i = 0; i < size; i++) {
tmp = sbox[i];
j = (j + tmp + key[i % strlen((char*)key)]) % size; //注意此处的长度,自己计算一下密钥和数据的长度多次尝试
//这里就不创建T盒了,直接对密钥进行遍历
sbox[i] = sbox[j];
sbox[j] = tmp;
/*if (++k >= 12)
k = 0;*/
}
}

// 加解密函数
void enc_dec(unsigned char* key, unsigned char* data) {
int i, j, k, R, tmp;

init_sbox(key);

j = k = 0;
for (i = 0; i < strlen((char*)data); i++) {
j = (j + 1) % size;
k = (k + sbox[j]) % size;

tmp = sbox[j];
sbox[j] = sbox[k];
sbox[k] = tmp;

R = sbox[(sbox[j] + sbox[k]) % size];

data[i] ^= R;
}
}

int main() {
unsigned char key[100] = { 0x52, 0x69, 0x63, 0x61, 0x72, 0x64, 0x6F, 0x5F, 0x4D, 0x5F, 0x6C };//, 0x75 };
unsigned char data[100] = { 0xC2, 0xB0, 0x0E, 0xBE, 0xDB, 0xDF, 0x95, 0x2D, 0xCF, 0x4B, 0x74, 0x41, 0xF3, 0xC9, 0x43, 0xA7,
0x3C, 0x70, 0xC2, 0x2F, 0xFF, 0x8D, 0x65, 0x2C, 0x5C };
printf("key:%d,data:%d", strlen((char*)key), strlen((char*)data)); //查看一下key的长度是否异常,如果有异常请手动输入
printf("\n");
/*printf("输入你要加密的字符:");
scanf("%100s", data);
printf("输入密钥:");
scanf("%40s", key);
enc_dec(key, data);
printf("enc: %s\n", data);*/
enc_dec(key, data);
printf("dec: %s\n", data);
return 0;
}

TEA

https://blog.csdn.net/xiao__1bai/article/details/123307059

动画演示

位移与运算的关系

1
2
A >> n == A / pow(2,n)
A << n == A * pow(2,n)

加密流程:需要两个4字节的明文和四个4字节的密钥,以及一个delta值(通常为黄金分割数(5√-2)/2 与 232 的乘积0x9e3779b9即2654435769),把明文分组进行多轮与相加加密。且为分组加密,组与组间相互影响。

代码分析

(来自上面文章)

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
#include <stdio.h>
#include <stdint.h>

void encrypt (uint32_t *v,uint32_t *k ){
uint32_t v0=v[0],v1=v[1],sum=0,i;
uint32_t delta=0x9e3779b9; //2654435769
uint32_t k0=k[0],k1=k[1],k2=k[2],k3=k[3];
for(i=0;i<32;i++){
sum+=delta;
v0+=((v1 << 4) + k0)^(v1 + sum)^((v1 >> 5) + k1);
v1+=((v0 << 4) + k2)^(v0 + sum)^((v0 >> 5) + k3);
}
v[0]=v0;v[1]=v1;
}
void decrypt (uint32_t *v,uint32_t *k){
uint32_t v0=v[0],v1=v[1],sum=0xC6EF3720,i; //这里的sum是0x9e3779b9*32后截取32位的结果,截取很重要。//这里的数据类型可能会有符号,可以尝试改为int
uint32_t delta=0x9e3779b9;
uint32_t k0=k[0],k1=k[1],k2=k[2],k3=k[3];
for (i=0;i<32;i++){
v1-=((v0 << 4) + k2)^(v0 + sum)^((v0 >> 5) + k3);
v0-=((v1 << 4) + k0)^(v1 + sum)^((v1 >> 5) + k1);
sum-=delta;
}
v[0]=v0;v[1]=v1;
}

int main()
{
uint32_t v[2]={1,2},k[4]={2,2,3,4}; //若有多组数据,可以每两个进行加密。
printf("加密前的数据:%u %u\n",v[0],v[1]); //%u 以十进制形式输出无符号整数
encrypt(v,k);
printf("加密后数据:%u %u\n",v[0],v[1]);
decrypt(v,k);
printf("解密后数据:%u %u\n",v[0],v[1]);
return 0;
}

分组加密的分类

密码学:分组密码.(块密码:是一种对称密码算法)_分组加密-CSDN博客

CEB:明文的每个块都独立地加密成密文的每个块。

CBC:个明文块先与前一个密文块进行异或(XOR)后再进行加密。第1个块中需要使用初始化向量(第一组密文与初始向量异或)。

OFB:将之前一次的加密结果使用密钥再次进行加密(第1次对IV进行加密),产生的块作为密钥流,然后将其与明文块进行异或,得到密文。

CFB:类似OFB,只不过将上一组的密文作为下一组的输入来加密进行反馈。


XTEA

解析 TEA 加密算法(C语言、python):_tea加密-CSDN博客

演示动画

XTEA是TEA的升级版,增加了更多的密钥表,移位和异或操作

代码

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
#include<stdio.h>
#include<stdint.h>

void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]){
unsigned int i;
uint32_t v0=v[0],v1=v[1],sum=0,delta=0x9E3779B9;
for(i=0;i<num_rounds;i++){
v0+=(((v1 << 4)^(v1 >> 5)) + v1)^(sum + key[sum & 3]);
sum+=delta;
v1+=((( v0 << 4)^(v0 >> 5)) + v0)^(sum + key[(sum >> 11) & 3]);
}
v[0]=v0;v[1]=v1;
}

void decipher(unsigned int num_rounds,uint32_t v[2],uint32_t const key[4]){
unsigned int i;
uint32_t v0=v[0],v1=v[1],delta=0x9E3779B9,sum=delta*num_rounds;
for(i=0;i<num_rounds;i++){
v1-=(((v0 << 4)^(v0 >> 5)) + v0)^(sum + key[(sum >> 11) & 3]);
sum-=delta;
v0-=(((v1 << 4)^(v1 >> 5)) + v1)^(sum + key[sum & 3]);
}
v[0]=v0;v[1]=v1;
}

int main(){
uint32_t v[2]={1,2};
uint32_t const k[4]={2,2,3,4};
unsigned int r=32; //这里是加密轮数,自己设置
printf("加密前原始数据:%u %u\n",v[0],v[1]);
encipher(r,v,k);
printf("加密后原始数据:%u %u\n",v[0],v[1]);
decipher(r,v,k);
printf("解密后原始数据:%u %u\n",v[0],v[1]);
return 0;
}

XXTEA

解析 TEA 加密算法(C语言、python):_tea加密-CSDN博客

XXTEA在可变长度块上运行,这些块是32位大小的任意倍数(最小64位),使用128位密钥(16字节)。

加密流程:最开始是以v[n-1]和v[1]得出v[0],后面是用v[0]和v[2]得出v[1],以此类推三组作为一次加密,每次加密遍历一遍,一共加密6+52/n次。

代码分析

(来自上面的文章)

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
#include<stdio.h>
#include<stdint.h>
#define DELTA 0x933779b9
void btea(uint32_t *v,int n,uint32_t const key[4])
{
uint32_t y,z,sum,delta;
unsigned p,rounds,e;
delta = 0x933779b9;
rounds=6+52/n; //这里可以说是预定义值,n=2是rounds=32
sum=0;
z=v[n-1];
do
{
sum+=delta;
e=(sum>>2)&3;
for(p=0;p<n-1;p++) //注意这里的p是从0~n-1
{
y=v[p+1];
z=v[p]+=(((z >> 5 ^ y << 2)+(y >> 3 ^ z << 4))^((sum ^ y)+(key[(p & 3) ^ e] ^ z)));
}
y=v[0];
z=v[n-1]+=(((z >> 5 ^ y << 2)+(y >> 3 ^ z << 4))^((sum ^ y)+(key[(p & 3) ^ e] ^ z))); //这里的MX中传入的p=n-1
}
while(--rounds);
}
void dec_btea(uint32_t *v,int n,uint32_t const key[4])
{
uint32_t y,z,sum,delta;
unsigned p,rounds,e;
delta = 0x933779b9;
rounds=6+52/n;
sum=rounds*delta;
y=v[0];
do
{
e=(sum>>2)&3;
for(p=n-1;p>0;p--) //注意这里的p是从n-1~0,和上面是反过来的
{
z=v[p-1];
y=v[p]-=(((z >> 5 ^ y << 2)+(y >> 3 ^ z << 4))^((sum ^ y)+(key[(p & 3) ^ e] ^ z)));
}
z=v[n-1];
y=v[0]-=(((z >> 5 ^ y << 2)+(y >> 3 ^ z << 4))^((sum ^ y)+(key[(p & 3) ^ e] ^ z))); //这里的MX中传入的 p=0
sum-=delta;
}
while(--rounds);
}
}

int main()
{
uint32_t v[2]={1,2};
uint32_t const k[4]={2,2,3,4};
int n=2;
printf("加密前原始数据:%u %u\n",v[0],v[1]);
btea(v,n,k);
printf("加密后数据:%u %u\n",v[0],v[1]);
btea(v,-n,k);
printf("解密后数据:%u %u\n",v[0],v[1]);
return 0;

}

TEA系列的特征

TEA系列最明显的特征就是DELTA=0x933779b9,有时值不一样,但是delta是一定有的。还有就是那一串异或相加加密的代码。

在TEA和XTEA中每次加密只会涉及到两个密文,而XXTEA有三个密文。在XTEA和XXTEA中有&3,而TEA中没有。在XXTEA中的轮数是6+52/n。

AES

AES加密算法原理详解-CSDN博客

演示动画

AES 是一种对称密钥加密方法,依赖于分组密码,将数据分成块,对每个块进行加密以确保一致的安全性。AES 加密提供三种密钥长度——128 位、192 位和 256 位。包括4个操作:字节代换、行位移、列混合和轮密钥加。最后一轮迭代不执行列混合。AES的字节代换其实就是一个简单的查表操作。AES定义了一个S盒和一个逆S盒。

AES加密比较复杂,我们不深入研究,只掌握一些特征用于分析,具体解密方式可以用赛博厨师和Python脚本

  • 加密过程:密钥扩展–>轮密钥生成–>字节替换、行移位–>列替换和轮密钥加

  • 密钥长度和轮数的对应

    • 128bits–>10rounds
    • 192bits–>12rounds
    • 256bits–>14rounds

    S盒常量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
unsigned char S[256] = {
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
};

代码实现(来自AES算法描述及C语言实现_c语言实现aes算法-CSDN博客)

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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
#include <stdint.h>
#include <stdio.h>
#include <string.h>

typedef struct{
uint32_t eK[44], dK[44]; // encKey, decKey
int Nr; // 10 rounds
}AesKey;

#define BLOCKSIZE 16 //AES-128分组长度为16字节

// uint8_t y[4] -> uint32_t x
#define LOAD32H(x, y) \
do { (x) = ((uint32_t)((y)[0] & 0xff)<<24) | ((uint32_t)((y)[1] & 0xff)<<16) | \
((uint32_t)((y)[2] & 0xff)<<8) | ((uint32_t)((y)[3] & 0xff));} while(0)

// uint32_t x -> uint8_t y[4]
#define STORE32H(x, y) \
do { (y)[0] = (uint8_t)(((x)>>24) & 0xff); (y)[1] = (uint8_t)(((x)>>16) & 0xff); \
(y)[2] = (uint8_t)(((x)>>8) & 0xff); (y)[3] = (uint8_t)((x) & 0xff); } while(0)

// 从uint32_t x中提取从低位开始的第n个字节
#define BYTE(x, n) (((x) >> (8 * (n))) & 0xff)

/* used for keyExpansion */
// 字节替换然后循环左移1位
#define MIX(x) (((S[BYTE(x, 2)] << 24) & 0xff000000) ^ ((S[BYTE(x, 1)] << 16) & 0xff0000) ^ \
((S[BYTE(x, 0)] << 8) & 0xff00) ^ (S[BYTE(x, 3)] & 0xff))

// uint32_t x循环左移n位
#define ROF32(x, n) (((x) << (n)) | ((x) >> (32-(n))))
// uint32_t x循环右移n位
#define ROR32(x, n) (((x) >> (n)) | ((x) << (32-(n))))

/* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
// AES-128轮常量
static const uint32_t rcon[10] = {
0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL, 0x10000000UL,
0x20000000UL, 0x40000000UL, 0x80000000UL, 0x1B000000UL, 0x36000000UL
};
// S盒
unsigned char S[256] = {
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
};

//逆S盒
unsigned char inv_S[256] = {
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
};

/* copy in[16] to state[4][4] */
int loadStateArray(uint8_t (*state)[4], const uint8_t *in) {
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
state[j][i] = *in++;
}
}
return 0;
}

/* copy state[4][4] to out[16] */
int storeStateArray(uint8_t (*state)[4], uint8_t *out) {
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
*out++ = state[j][i];
}
}
return 0;
}
//秘钥扩展
int keyExpansion(const uint8_t *key, uint32_t keyLen, AesKey *aesKey) {

if (NULL == key || NULL == aesKey){
printf("keyExpansion param is NULL\n");
return -1;
}

if (keyLen != 16){
printf("keyExpansion keyLen = %d, Not support.\n", keyLen);
return -1;
}

uint32_t *w = aesKey->eK; //加密秘钥
uint32_t *v = aesKey->dK; //解密秘钥

/* keyLen is 16 Bytes, generate uint32_t W[44]. */

/* W[0-3] */
for (int i = 0; i < 4; ++i) {
LOAD32H(w[i], key + 4*i);
}

/* W[4-43] */
for (int i = 0; i < 10; ++i) {
w[4] = w[0] ^ MIX(w[3]) ^ rcon[i];
w[5] = w[1] ^ w[4];
w[6] = w[2] ^ w[5];
w[7] = w[3] ^ w[6];
w += 4;
}

w = aesKey->eK+44 - 4;
//解密秘钥矩阵为加密秘钥矩阵的倒序,方便使用,把ek的11个矩阵倒序排列分配给dk作为解密秘钥
//即dk[0-3]=ek[41-44], dk[4-7]=ek[37-40]... dk[41-44]=ek[0-3]
for (int j = 0; j < 11; ++j) {

for (int i = 0; i < 4; ++i) {
v[i] = w[i];
}
w -= 4;
v += 4;
}

return 0;
}

// 轮秘钥加
int addRoundKey(uint8_t (*state)[4], const uint32_t *key) {
uint8_t k[4][4];

/* i: row, j: col */
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
k[i][j] = (uint8_t) BYTE(key[j], 3 - i); /* 把 uint32 key[4] 先转换为矩阵 uint8 k[4][4] */
state[i][j] ^= k[i][j];
}
}

return 0;
}

//字节替换
int subBytes(uint8_t (*state)[4]) {
/* i: row, j: col */
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
state[i][j] = S[state[i][j]]; //直接使用原始字节作为S盒数据下标
}
}

return 0;
}

//逆字节替换
int invSubBytes(uint8_t (*state)[4]) {
/* i: row, j: col */
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
state[i][j] = inv_S[state[i][j]];
}
}
return 0;
}

//行移位
int shiftRows(uint8_t (*state)[4]) {
uint32_t block[4] = {0};

/* i: row */
for (int i = 0; i < 4; ++i) {
//便于行循环移位,先把一行4字节拼成uint_32结构,移位后再转成独立的4个字节uint8_t
LOAD32H(block[i], state[i]);
block[i] = ROF32(block[i], 8*i);
STORE32H(block[i], state[i]);
}

return 0;
}

//逆行移位
int invShiftRows(uint8_t (*state)[4]) {
uint32_t block[4] = {0};

/* i: row */
for (int i = 0; i < 4; ++i) {
LOAD32H(block[i], state[i]);
block[i] = ROR32(block[i], 8*i);
STORE32H(block[i], state[i]);
}

return 0;
}

/* Galois Field (256) Multiplication of two Bytes */
// 两字节的伽罗华域乘法运算
uint8_t GMul(uint8_t u, uint8_t v) {
uint8_t p = 0;

for (int i = 0; i < 8; ++i) {
if (u & 0x01) { //
p ^= v;
}

int flag = (v & 0x80);
v <<= 1;
if (flag) {
v ^= 0x1B; /* x^8 + x^4 + x^3 + x + 1 */
}

u >>= 1;
}

return p;
}

// 列混合
int mixColumns(uint8_t (*state)[4]) {
uint8_t tmp[4][4];
uint8_t M[4][4] = {{0x02, 0x03, 0x01, 0x01},
{0x01, 0x02, 0x03, 0x01},
{0x01, 0x01, 0x02, 0x03},
{0x03, 0x01, 0x01, 0x02}};

/* copy state[4][4] to tmp[4][4] */
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j){
tmp[i][j] = state[i][j];
}
}

for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) { //伽罗华域加法和乘法
state[i][j] = GMul(M[i][0], tmp[0][j]) ^ GMul(M[i][1], tmp[1][j])
^ GMul(M[i][2], tmp[2][j]) ^ GMul(M[i][3], tmp[3][j]);
}
}

return 0;
}

// 逆列混合
int invMixColumns(uint8_t (*state)[4]) {
uint8_t tmp[4][4];
uint8_t M[4][4] = {{0x0E, 0x0B, 0x0D, 0x09},
{0x09, 0x0E, 0x0B, 0x0D},
{0x0D, 0x09, 0x0E, 0x0B},
{0x0B, 0x0D, 0x09, 0x0E}}; //使用列混合矩阵的逆矩阵

/* copy state[4][4] to tmp[4][4] */
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j){
tmp[i][j] = state[i][j];
}
}

for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
state[i][j] = GMul(M[i][0], tmp[0][j]) ^ GMul(M[i][1], tmp[1][j])
^ GMul(M[i][2], tmp[2][j]) ^ GMul(M[i][3], tmp[3][j]);
}
}

return 0;
}

// AES-128加密接口,输入key应为16字节长度,输入长度应该是16字节整倍数,
// 这样输出长度与输入长度相同,函数调用外部为输出数据分配内存
int aesEncrypt(const uint8_t *key, uint32_t keyLen, const uint8_t *pt, uint8_t *ct, uint32_t len) {

AesKey aesKey;
uint8_t *pos = ct;
const uint32_t *rk = aesKey.eK; //解密秘钥指针
uint8_t out[BLOCKSIZE] = {0};
uint8_t actualKey[16] = {0};
uint8_t state[4][4] = {0};

if (NULL == key || NULL == pt || NULL == ct){
printf("param err.\n");
return -1;
}

if (keyLen > 16){
printf("keyLen must be 16.\n");
return -1;
}

if (len % BLOCKSIZE){
printf("inLen is invalid.\n");
return -1;
}

memcpy(actualKey, key, keyLen);
keyExpansion(actualKey, 16, &aesKey); // 秘钥扩展

// 使用ECB模式循环加密多个分组长度的数据
for (int i = 0; i < len; i += BLOCKSIZE) {
// 把16字节的明文转换为4x4状态矩阵来进行处理
loadStateArray(state, pt);
// 轮秘钥加
addRoundKey(state, rk);

for (int j = 1; j < 10; ++j) {
rk += 4;
subBytes(state); // 字节替换
shiftRows(state); // 行移位
mixColumns(state); // 列混合
addRoundKey(state, rk); // 轮秘钥加
}

subBytes(state); // 字节替换
shiftRows(state); // 行移位
// 此处不进行列混合
addRoundKey(state, rk+4); // 轮秘钥加

// 把4x4状态矩阵转换为uint8_t一维数组输出保存
storeStateArray(state, pos);

pos += BLOCKSIZE; // 加密数据内存指针移动到下一个分组
pt += BLOCKSIZE; // 明文数据指针移动到下一个分组
rk = aesKey.eK; // 恢复rk指针到秘钥初始位置
}
return 0;
}

// AES128解密, 参数要求同加密
int aesDecrypt(const uint8_t *key, uint32_t keyLen, const uint8_t *ct, uint8_t *pt, uint32_t len) {
AesKey aesKey;
uint8_t *pos = pt;
const uint32_t *rk = aesKey.dK; //解密秘钥指针
uint8_t out[BLOCKSIZE] = {0};
uint8_t actualKey[16] = {0};
uint8_t state[4][4] = {0};

if (NULL == key || NULL == ct || NULL == pt){
printf("param err.\n");
return -1;
}

if (keyLen > 16){
printf("keyLen must be 16.\n");
return -1;
}

if (len % BLOCKSIZE){
printf("inLen is invalid.\n");
return -1;
}

memcpy(actualKey, key, keyLen);
keyExpansion(actualKey, 16, &aesKey); //秘钥扩展,同加密

for (int i = 0; i < len; i += BLOCKSIZE) {
// 把16字节的密文转换为4x4状态矩阵来进行处理
loadStateArray(state, ct);
// 轮秘钥加,同加密
addRoundKey(state, rk);

for (int j = 1; j < 10; ++j) {
rk += 4;
invShiftRows(state); // 逆行移位
invSubBytes(state); // 逆字节替换,这两步顺序可以颠倒
addRoundKey(state, rk); // 轮秘钥加,同加密
invMixColumns(state); // 逆列混合
}

invSubBytes(state); // 逆字节替换
invShiftRows(state); // 逆行移位
// 此处没有逆列混合
addRoundKey(state, rk+4); // 轮秘钥加,同加密

storeStateArray(state, pos); // 保存明文数据
pos += BLOCKSIZE; // 输出数据内存指针移位分组长度
ct += BLOCKSIZE; // 输入数据内存指针移位分组长度
rk = aesKey.dK; // 恢复rk指针到秘钥初始位置
}
return 0;
}
// 方便输出16进制数据
void printHex(uint8_t *ptr, int len, char *tag) {
printf("%s\ndata[%d]: ", tag, len);
for (int i = 0; i < len; ++i) {
printf("%.2X ", *ptr++);
}
printf("\n");
}

int main() {

return 0;
}


加解密脚本

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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
#include<stdio.h>
#include<stdint.h>
#include<string.h>

static const int S[16][16] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };

/**
* 逆S盒
*/
static const int S2[16][16] = { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };

/**
* 获取整形数据的低8位的左4个位
*/
static int getLeft4Bit(int num) {
int left = num & 0x000000f0;
return left >> 4;
}

/**
* 获取整形数据的低8位的右4个位
*/
static int getRight4Bit(int num) {
return num & 0x0000000f;
}
/**
* 根据索引,从S盒中获得元素
*/
static int getNumFromSBox(int index) {
int row = getLeft4Bit(index);
int col = getRight4Bit(index);
return S[row][col];
}

/**
* 把一个字符转变成整型
*/
static int getIntFromChar(char c) {
int result = (int)c;
return result & 0x000000ff;
}

/**
* 把16个字符转变成4X4的数组,
* 该矩阵中字节的排列顺序为从上到下,
* 从左到右依次排列。
*/
static void convertToIntArray(char* str, int pa[4][4]) {
int k = 0;
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
pa[j][i] = getIntFromChar(str[k]);
k++;
}
}

/**
* 打印4X4的数组
*/
static void printArray(int a[4][4]) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++)
printf("a[%d][%d] = 0x%x ", i, j, a[i][j]);
printf("\n");
}
printf("\n");
}

/**
* 打印字符串的ASSCI,
* 以十六进制显示。
*/
static void printASSCI(char* str, int len) {
for (int i = 0; i < len; i++)
printf("0x%x ", getIntFromChar(str[i]));
printf("\n");
}

/**
* 把连续的4个字符合并成一个4字节的整型
*/
static int getWordFromStr(char* str) {
int one = getIntFromChar(str[0]);
one = one << 24;
int two = getIntFromChar(str[1]);
two = two << 16;
int three = getIntFromChar(str[2]);
three = three << 8;
int four = getIntFromChar(str[3]);
return one | two | three | four;
}

/**
* 把一个4字节的数的第一、二、三、四个字节取出,
* 入进一个4个元素的整型数组里面。
*/
static void splitIntToArray(int num, int array[4]) {
int one = num >> 24;
array[0] = one & 0x000000ff;
int two = num >> 16;
array[1] = two & 0x000000ff;
int three = num >> 8;
array[2] = three & 0x000000ff;
array[3] = num & 0x000000ff;
}

/**
* 将数组中的元素循环左移step位
*/
static void leftLoop4int(int array[4], int step) {
int temp[4];
for (int i = 0; i < 4; i++)
temp[i] = array[i];

int index = step % 4 == 0 ? 0 : step % 4;
for (int i = 0; i < 4; i++) {
array[i] = temp[index];
index++;
index = index % 4;
}
}

/**
* 把数组中的第一、二、三和四元素分别作为
* 4字节整型的第一、二、三和四字节,合并成一个4字节整型
*/
static int mergeArrayToInt(int array[4]) {
int one = array[0] << 24;
int two = array[1] << 16;
int three = array[2] << 8;
int four = array[3];
return one | two | three | four;
}

/**
* 常量轮值表
*/
static const int Rcon[10] = { 0x01000000, 0x02000000,
0x04000000, 0x08000000,
0x10000000, 0x20000000,
0x40000000, 0x80000000,
0x1b000000, 0x36000000 };
/**
* 密钥扩展中的T函数
*/
static int T(int num, int round) {
int numArray[4];
splitIntToArray(num, numArray);
leftLoop4int(numArray, 1);//字循环

//字节代换
for (int i = 0; i < 4; i++)
numArray[i] = getNumFromSBox(numArray[i]);

int result = mergeArrayToInt(numArray);
return result ^ Rcon[round];
}

//密钥对应的扩展数组
static int w[44];

/**
* 扩展密钥,结果是把w[44]中的每个元素初始化
*/
static void extendKey(char* key) {
for (int i = 0; i < 4; i++)
w[i] = getWordFromStr(key + i * 4);

for (int i = 4, j = 0; i < 44; i++) {
if (i % 4 == 0) {
w[i] = w[i - 4] ^ T(w[i - 1], j);
j++;//下一轮
}
else {
w[i] = w[i - 4] ^ w[i - 1];
}
}

}

/**
* 轮密钥加
*/
static void addRoundKey(int array[4][4], int round) {
int warray[4];
for (int i = 0; i < 4; i++) {

splitIntToArray(w[round * 4 + i], warray);

for (int j = 0; j < 4; j++) {
array[j][i] = array[j][i] ^ warray[j];
}
}
}

/**
* 字节代换
*/
static void subBytes(int array[4][4]) {
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
array[i][j] = getNumFromSBox(array[i][j]);
}

/**
* 行移位
*/
static void shiftRows(int array[4][4]) {
int rowTwo[4], rowThree[4], rowFour[4];
//复制状态矩阵的第2,3,4行
for (int i = 0; i < 4; i++) {
rowTwo[i] = array[1][i];
rowThree[i] = array[2][i];
rowFour[i] = array[3][i];
}
//循环左移相应的位数
leftLoop4int(rowTwo, 1);
leftLoop4int(rowThree, 2);
leftLoop4int(rowFour, 3);

//把左移后的行复制回状态矩阵中
for (int i = 0; i < 4; i++) {
array[1][i] = rowTwo[i];
array[2][i] = rowThree[i];
array[3][i] = rowFour[i];
}
}

/**
* 列混合要用到的矩阵
*/
static const int colM[4][4] = { 2, 3, 1, 1,
1, 2, 3, 1,
1, 1, 2, 3,
3, 1, 1, 2 };

static int GFMul2(int s) {
int result = s << 1;
int a7 = result & 0x00000100;

if (a7 != 0) {
result = result & 0x000000ff;
result = result ^ 0x1b;
}

return result;
}

static int GFMul3(int s) {
return GFMul2(s) ^ s;
}

static int GFMul4(int s) {
return GFMul2(GFMul2(s));
}

static int GFMul8(int s) {
return GFMul2(GFMul4(s));
}

static int GFMul9(int s) {
return GFMul8(s) ^ s;
}

static int GFMul11(int s) {
return GFMul9(s) ^ GFMul2(s);
}

static int GFMul12(int s) {
return GFMul8(s) ^ GFMul4(s);
}

static int GFMul13(int s) {
return GFMul12(s) ^ s;
}

static int GFMul14(int s) {
return GFMul12(s) ^ GFMul2(s);
}

/**
* GF上的二元运算
*/
static int GFMul(int n, int s) {
int result;

if (n == 1)
result = s;
else if (n == 2)
result = GFMul2(s);
else if (n == 3)
result = GFMul3(s);
else if (n == 0x9)
result = GFMul9(s);
else if (n == 0xb)//11
result = GFMul11(s);
else if (n == 0xd)//13
result = GFMul13(s);
else if (n == 0xe)//14
result = GFMul14(s);

return result;
}
/**
* 列混合
*/
static void mixColumns(int array[4][4]) {

int tempArray[4][4];

for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
tempArray[i][j] = array[i][j];

for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
array[i][j] = GFMul(colM[i][0], tempArray[0][j]) ^ GFMul(colM[i][1], tempArray[1][j])
^ GFMul(colM[i][2], tempArray[2][j]) ^ GFMul(colM[i][3], tempArray[3][j]);
}
}
/**
* 把4X4数组转回字符串
*/
static void convertArrayToStr(int array[4][4], char* str) {
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
*str++ = (char)array[j][i];
}
/**
* 检查密钥长度
*/
static int checkKeyLen(int len) {
if (len == 16)
return 1;
else
return 0;
}

/**
* 参数 p: 明文的字符串数组。
* 参数 plen: 明文的长度。
* 参数 key: 密钥的字符串数组。
*/
int aes(char* p, int plen, char* key) {

int keylen = strlen(key);
if (plen == 0 || plen % 16 != 0) {
return 0;
}

if (!checkKeyLen(keylen)) {
return 0;
}
extendKey(key);//扩展密钥
int pArray[4][4];

for (int k = 0; k < plen; k += 16) {
convertToIntArray(p + k, pArray);

addRoundKey(pArray, 0);//一开始的轮密钥加

for (int i = 1; i < 10; i++) {//前9轮

subBytes(pArray);//字节代换

shiftRows(pArray);//行移位

mixColumns(pArray);//列混合

addRoundKey(pArray, i);

}

//第10轮
subBytes(pArray);//字节代换

shiftRows(pArray);//行移位

addRoundKey(pArray, 10);

convertArrayToStr(pArray, p + k);
}

}
/**
* 根据索引从逆S盒中获取值
*/
static int getNumFromS1Box(int index) {
int row = getLeft4Bit(index);
int col = getRight4Bit(index);
return S2[row][col];
}
/**
* 逆字节变换
*/
static void deSubBytes(int array[4][4]) {
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
array[i][j] = getNumFromS1Box(array[i][j]);
}
/**
* 把4个元素的数组循环右移step位
*/
static void rightLoop4int(int array[4], int step) {
int temp[4];
for (int i = 0; i < 4; i++)
temp[i] = array[i];

int index = step % 4 == 0 ? 0 : step % 4;
index = 3 - index;
for (int i = 3; i >= 0; i--) {
array[i] = temp[index];
index--;
index = index == -1 ? 3 : index;
}
}

/**
* 逆行移位
*/
static void deShiftRows(int array[4][4]) {
int rowTwo[4], rowThree[4], rowFour[4];
for (int i = 0; i < 4; i++) {
rowTwo[i] = array[1][i];
rowThree[i] = array[2][i];
rowFour[i] = array[3][i];
}

rightLoop4int(rowTwo, 1);
rightLoop4int(rowThree, 2);
rightLoop4int(rowFour, 3);

for (int i = 0; i < 4; i++) {
array[1][i] = rowTwo[i];
array[2][i] = rowThree[i];
array[3][i] = rowFour[i];
}
}
/**
* 逆列混合用到的矩阵
*/
static const int deColM[4][4] = { 0xe, 0xb, 0xd, 0x9,
0x9, 0xe, 0xb, 0xd,
0xd, 0x9, 0xe, 0xb,
0xb, 0xd, 0x9, 0xe };

/**
* 逆列混合
*/
static void deMixColumns(int array[4][4]) {
int tempArray[4][4];

for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
tempArray[i][j] = array[i][j];

for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
array[i][j] = GFMul(deColM[i][0], tempArray[0][j]) ^ GFMul(deColM[i][1], tempArray[1][j])
^ GFMul(deColM[i][2], tempArray[2][j]) ^ GFMul(deColM[i][3], tempArray[3][j]);
}
}
/**
* 把两个4X4数组进行异或
*/
static void addRoundTowArray(int aArray[4][4], int bArray[4][4]) {
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
aArray[i][j] = aArray[i][j] ^ bArray[i][j];
}
/**
* 从4个32位的密钥字中获得4X4数组,
* 用于进行逆列混合
*/
static void getArrayFrom4W(int i, int array[4][4]) {
int index = i * 4;
int colOne[4], colTwo[4], colThree[4], colFour[4];
splitIntToArray(w[index], colOne);
splitIntToArray(w[index + 1], colTwo);
splitIntToArray(w[index + 2], colThree);
splitIntToArray(w[index + 3], colFour);

for (int i = 0; i < 4; i++) {
array[i][0] = colOne[i];
array[i][1] = colTwo[i];
array[i][2] = colThree[i];
array[i][3] = colFour[i];
}

}
/**
* 参数 c: 密文的字符串数组。
* 参数 clen: 密文的长度。
* 参数 key: 密钥的字符串数组。
*/
int deAes(char* c, int clen, char* key) {

int keylen = strlen(key);
if (clen == 0 || clen % 16 != 0) {
return 0;
}

if (!checkKeyLen(keylen)) {
return 0;
}
extendKey(key);//扩展密钥
int cArray[4][4];
for (int k = 0; k < clen; k += 16) {
convertToIntArray(c + k, cArray);


addRoundKey(cArray, 10);

int wArray[4][4];
for (int i = 9; i >= 1; i--) {
deSubBytes(cArray);

deShiftRows(cArray);

deMixColumns(cArray);
getArrayFrom4W(i, wArray);
deMixColumns(wArray);

addRoundTowArray(cArray, wArray);
}

deSubBytes(cArray);

deShiftRows(cArray);

addRoundKey(cArray, 0);

convertArrayToStr(cArray, c + k);


}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import base64

from Crypto.Cipher import AES
password = b'1234567812345678' #秘钥,b就是表示为bytes类型
iv = b'1234567812345678' # iv偏移量,bytes类型
text = b'abcdefghijklmnhi' #需要加密的内容,bytes类型


aes = AES.new(password,AES.MODE_CBC,iv) #创建一个aes对象
# AES.MODE_CBC 表示模式是CBC模式
en_text = aes.encrypt(text)
print("密文:",en_text) #加密明文,bytes类型

m = b'' #要解密的base64代码
debase64 = base64.decodebytes(m)

aes = AES.new(password,AES.MODE_CBC,iv) #CBC模式下解密需要重新创建一个aes对象
den_text = aes.decrypt(debase64)
print("明文:",den_text)

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
import base64
from base64 import encode

from Crypto.Cipher import AES

password = b'1234567812345678' #秘钥,b就是表示为bytes类型

text = b'abcdefghijklmnhi' #需要加密的内容,bytes类型
aes = AES.new(password,AES.MODE_ECB) #创建一个aes对象
# AES.MODE_ECB 表示模式是ECB模式


m = b'Pd04a4bt7Bcf97KEfgLGQw==' #要解密的base64值
en_text = base64.decodebytes(m)


# en_text = aes.encrypt(text) #加密明文
# print("密文:",en_text) #加密明文,bytes类型


den_text = aes.decrypt(en_text) # 解密密文
print("明文:",den_text)

# print(den_text.decode('gbk')) #中文输出

解密AES需要逆s盒,逆s盒脚本为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
new_s_box = [
0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16
]
import string
new_contrary_sbox = [0]*256
print(len(new_s_box))
for i in range(256):
line = (new_s_box[i]&0xf0)>>4
rol = new_s_box[i]&0xf
new_contrary_sbox[(line*16)+rol] = i
print(len(new_contrary_sbox))
for i in new_contrary_sbox:
print(f"{hex(i)},",end='')

SM4

SM4 的加密过程将数据块分成 128 位(16 字节)的分组进行加密,使用 32 轮加密操作,基于复杂的置换和替代(P-box 和 S-box)。由于其固定的 128 位分组长度,处理非 128 位整数倍的明文数据时,通常需要进行填充。主要包含异或、移位以及盒变换操作。它分为密钥拓展和加/解密两个模块,这两个模块的流程大同小异。其中,移位变换是指循环左移;盒变换是一个将8bit输入映射到8bit输出的变换,是一个固定的变换。

代码分析(来自Python实现SM4加解密算法_sm4 python-CSDN博客

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
# S盒,用于字节替换
S_BOX = [
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
]

# 轮常数,用于密钥扩展
FK = [0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc]

# 固定参数,用于轮密钥生成
CK = [
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
]

def byte_sub(byte):
"""S盒字节替换"""
return S_BOX[byte]

def l_transformation(b):
"""线性变换"""
return b ^ (b << 2) ^ (b << 10) ^ (b << 18) ^ (b << 24)

def t_function(x):
"""T函数,包括S盒替换和线性变换"""
b = byte_sub((x >> 24) & 0xFF) << 24 | \
byte_sub((x >> 16) & 0xFF) << 16 | \
byte_sub((x >> 8) & 0xFF) << 8 | \
byte_sub(x & 0xFF)
return l_transformation(b)

def key_expansion(key):
"""密钥扩展生成32轮密钥"""
K = [key[i] ^ FK[i] for i in range(4)]
rk = []
for i in range(32):
temp = K[i] ^ t_function(K[i + 1] ^ K[i + 2] ^ K[i + 3] ^ CK[i])
rk.append(temp)
K.append(temp)
return rk

def sm4_encrypt_block(plaintext, key):
"""SM4单块加密"""
rk = key_expansion(key)
X = plaintext.copy()
for i in range(32):
temp = X[i] ^ t_function(X[i + 1] ^ X[i + 2] ^ X[i + 3] ^ rk[i])
X.append(temp)
return X[35:31:-1] # 反序输出

def sm4_decrypt_block(ciphertext, key):
"""SM4单块解密"""
rk = key_expansion(key)[::-1] # 轮密钥反序
X = ciphertext.copy()
for i in range(32):
temp = X[i] ^ t_function(X[i + 1] ^ X[i + 2] ^ X[i + 3] ^ rk[i])
X.append(temp)
return X[35:31:-1] # 反序输出

# 示例使用
plaintext = [0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210]
key = [0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210]

ciphertext = sm4_encrypt_block(plaintext, key)
print(f"加密后的密文: {ciphertext}")

decrypted_text = sm4_decrypt_block(ciphertext, key)
print(f"解密后的明文: {decrypted_text}")

常用解密脚本

来自sm4 加解密 ( python版本) - 宁青楼 - 博客园

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
# -*- coding: utf-8 -*-
"""
author: 沈天巡
date:2023/4/27-10:33

说明:
"""

import binascii
from gmssl import sm4


class SM4:
"""
国产加密 sm4加解密
"""

def __init__(self):
self.crypt_sm4 = sm4.CryptSM4() # 实例化

def str_to_hexStr(self , hex_str):
"""
字符串转hex
:param hex_str: 字符串
:return: hex
"""
hex_data = hex_str.encode('utf-8')
str_bin = binascii.unhexlify(hex_data)
return str_bin.decode('utf-8')

def encryptSM4(self , encrypt_key , value):
"""
国密sm4加密
:param encrypt_key: sm4加密key
:param value: 待加密的字符串
:return: sm4加密后的十六进制值
"""
crypt_sm4 = self.crypt_sm4
crypt_sm4.set_key(encrypt_key.encode() , sm4.SM4_ENCRYPT) # 设置密钥
date_str = str(value)
encrypt_value = crypt_sm4.crypt_ecb(date_str.encode()) # 开始加密。bytes类型
return encrypt_value.hex() # 返回十六进制值

def decryptSM4(self , decrypt_key , encrypt_value):
"""
国密sm4解密
:param decrypt_key:sm4加密key
:param encrypt_value: 待解密的十六进制值
:return: 原字符串
"""
crypt_sm4 = self.crypt_sm4
crypt_sm4.set_key(decrypt_key.encode() , sm4.SM4_DECRYPT) # 设置密钥
decrypt_value = crypt_sm4.crypt_ecb(bytes.fromhex(encrypt_value)) # 开始解密。十六进制类型
return decrypt_value.decode()
# return self.str_to_hexStr(decrypt_value.hex())


if __name__ == '__main__':
key = "love_is_the_soul"
strData = "jntm"
SM4 = SM4()
print("原字符:" , strData)
encData = SM4.encryptSM4(key , strData) # 加密后的数据,返回bytes类型
print("sm4加密结果:" , encData)

# decData = SM4.decryptSM4(key , encData)
# print("sm4解密结果:" , decData) # 解密后的数据

blowfish

BlowFish是一个对称区块加密算法。每次加密数据为 64位 (2个int)类型数据大小。八个字节。密钥采用32-448位。进行多轮加密在加密或者初始化的过程中会使用两个盒来进行加密分别是PBOX 以及SBOX,这两个盒都是预计产生的,可以看成常数。

大概流程:对盒中PBOX的进行轮询与key进行加密。再用一遍加密函数加密0来改变PBOX和SBOX中的值。最后用明文去查找表数据进行运算替换。

常量特征

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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
p_box = [
0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344,
0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89,
0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C,
0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917,
0x9216D5D9, 0x8979FB1B]

s_box = [
[0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7,
0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99,
0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16,
0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E,
0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE,
0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013,
0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF,
0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E,
0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60,
0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440,
0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE,
0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A,
0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E,
0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677,
0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193,
0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032,
0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88,
0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239,
0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E,
0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0,
0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3,
0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98,
0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88,
0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE,
0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6,
0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D,
0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B,
0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7,
0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA,
0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463,
0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F,
0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09,
0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3,
0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB,
0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279,
0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8,
0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB,
0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82,
0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB,
0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573,
0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0,
0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B,
0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790,
0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8,
0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4,
0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0,
0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7,
0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C,
0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD,
0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1,
0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299,
0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9,
0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477,
0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF,
0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49,
0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF,
0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA,
0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5,
0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41,
0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915,
0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400,
0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915,
0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664,
0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A],
[0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623,
0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266,
0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1,
0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E,
0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6,
0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1,
0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E,
0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1,
0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737,
0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8,
0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF,
0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD,
0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701,
0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7,
0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41,
0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331,
0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF,
0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF,
0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E,
0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87,
0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C,
0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2,
0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16,
0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD,
0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B,
0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509,
0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E,
0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3,
0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F,
0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A,
0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4,
0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960,
0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66,
0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28,
0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802,
0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84,
0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510,
0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF,
0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14,
0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E,
0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50,
0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7,
0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8,
0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281,
0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99,
0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696,
0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128,
0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73,
0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0,
0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0,
0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105,
0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250,
0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3,
0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285,
0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00,
0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061,
0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB,
0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E,
0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735,
0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC,
0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9,
0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340,
0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20,
0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7],
[0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934,
0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068,
0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF,
0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840,
0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45,
0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504,
0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A,
0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB,
0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE,
0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6,
0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42,
0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B,
0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2,
0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB,
0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527,
0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B,
0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33,
0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C,
0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3,
0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC,
0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17,
0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564,
0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B,
0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115,
0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922,
0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728,
0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0,
0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E,
0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37,
0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D,
0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804,
0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B,
0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3,
0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB,
0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D,
0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C,
0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350,
0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9,
0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A,
0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE,
0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D,
0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC,
0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F,
0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61,
0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2,
0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9,
0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2,
0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C,
0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E,
0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633,
0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10,
0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169,
0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52,
0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027,
0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5,
0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62,
0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634,
0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76,
0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24,
0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC,
0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4,
0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C,
0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837,
0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0],
[0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B,
0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE,
0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B,
0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4,
0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8,
0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6,
0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304,
0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22,
0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4,
0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6,
0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9,
0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59,
0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593,
0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51,
0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28,
0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C,
0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B,
0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28,
0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C,
0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD,
0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A,
0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319,
0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB,
0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F,
0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991,
0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32,
0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680,
0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166,
0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE,
0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB,
0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5,
0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47,
0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370,
0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D,
0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84,
0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048,
0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8,
0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD,
0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9,
0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7,
0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38,
0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F,
0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C,
0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525,
0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1,
0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442,
0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964,
0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E,
0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8,
0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D,
0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F,
0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299,
0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02,
0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC,
0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614,
0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A,
0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6,
0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B,
0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0,
0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060,
0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E,
0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9,
0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F,
0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6]]

代码实现

来自BlowFish 加密算法 python实现 - yring

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
import Crypto.Util.number
import copy
from Blow_BOX import *

key_pbox = [0 for i in range(18)]
Encrypt = []


def init_key_pbox(_key): #密钥初始化盒
index = 0
for i in range(18):
for j in range(4):
key_pbox[i] = ord(_key[index]) | (key_pbox[i] << 8)
index += 1
if index >= len(_key):
index = 0

for i in range(18):
p_box[i] ^= key_pbox[i]


def Fn(Left):
a = (Left & 0xff000000) >> 24
b = (Left & 0x00ff0000) >> 16
c = (Left & 0x0000ff00) >> 8
d = Left & 0x000000ff

Sa = s_box[0][a]
Sb = s_box[1][b]
Sc = s_box[2][c]
Sd = s_box[3][d]

return (((Sa + Sb) ^ Sc) + Sd) & 0xffffffff


def Blow_Main_Encrypt(Left, Right): #主加密函数,查表异或替换
for i in range(16):
Left ^= p_box[i]
Right ^= Fn(Left)
Temp = Left
Left = Right
Right = Temp

Temp = Left
Left = Right ^ p_box[17]
Right = Temp ^ p_box[16]
return Left, Right


def Blow_Main_Decrypt(Left, Right):
for i in range(17, 1, -1):
Left ^= p_box[i]
Right ^= Fn(Left)

Temp = Left
Left = Right
Right = Temp

Temp = Left
Left = Right ^ p_box[0]
Right = Temp ^ p_box[1]
return Left , Right


def Change_Box(): #盒变化
Left = 0
Right = 0
for i in range(0, 18, 2):
Left, Right = Blow_Main_Encrypt(Left, Right)
p_box[i] = Left
p_box[i + 1] = Right

for i in range(4):
for j in range(0, 256, 2):
Left, Right = Blow_Main_Encrypt(Left, Right)
s_box[i][j] = Left
s_box[i][j + 1] = Right


def BlowFish_Encrypt(data):
while len(data) % 8:
data += '0'
cipher = ''
for i in range(0, len(data), 8):
Left = (ord(data[i]) << 24) | (ord(data[i + 1]) << 16) | (ord(data[i + 2]) << 8) | (ord(data[i + 3]))
Right = (ord(data[i + 4]) << 24) | (ord(data[i + 5]) << 16) | (ord(data[i + 6]) << 8) | (ord(data[i + 7]))
Left, Right = Blow_Main_Encrypt(Left, Right)
cipher += hex(Left)[2:]
cipher += hex(Right)[2:]
global Encrypt
Encrypt = []
print(cipher)


def BlowFish_Decrypt(cipher):
plain = ''
for i in range(0, len(cipher), 16):
Left = cipher[i:i + 8]
Right = cipher[i + 8:i + 16]
Left = int(Left, base=16)
Right = int(Right, base=16)

Left, Right = Blow_Main_Decrypt(Left, Right)
plain += hex(Left)[2:]
plain += hex(Right)[2:]

plain = int(plain, base=16)
print(Crypto.Util.number.long_to_bytes(plain))
global Encrypt
Encrypt = []


if __name__ == '__main__':
key = input("PLZ input the key First\n")
init_key_pbox(key)
Change_Box()
m = input("PLZ choose a model: 1.Encrypt 2.Decrypt 3.exit\n")
while 1:
if m == '1':
data = input("PLZ input the data:\n")
BlowFish_Encrypt(data)
m = input("PLZ choose a model: 1.Encrypt 2.Decrypt 3.exit\n")
if m == '2':
cipher = input("PLZ input the cipher:\n")
BlowFish_Decrypt(cipher)
m = input("PLZ choose a model: 1.Encrypt 2.Decrypt 3.exit\n")

if m == '3':
break


DES

演示动画

分组对称加密算法,用64位明文被分为一组进行加密,使用64位密钥。若有多于64位的明文需要进行多组加密。

  • 64bit密钥经过PC-1盒的变换去除校验位并打乱为56bit密钥,平分成两个28bit密文C0,D0,通过移位次数表进行16次循环左移,得到C10,D0到C15,D15,共16组,把Cn,Dn,每两个拼接成一个值,再通过PC-2进行变换,得到16个48bit的密钥。

  • 64bit的明文ip置换,把ip置换盒值指向的位,与ip盒值所在位置索引的位进行二进制交换

  • 64bit明文平分分成两部分L0和R0。R0先经过轮函数F()的变换。先把R0分为8个4bit的数据,并把每一个组的最前端加上前面一组的最后一位,最后端加上后一组的第一位。以此类推,把每组4bit数据转为6bit,最终得到48bit的数据。

  • 48bit数据与48bit的密钥异或。

  • 异或结果分为8组6bit数据,以每组数据的中间4bit为列坐标,两端的1bit组为2bit数据作为行坐标。在s盒中按坐标寻找值并替换,把数据压缩为32bit。

  • 再次进行一次p盒置换,与ip置换逻辑相同,并与L0异或得到R1。

  • 把R0赋值给L1,继续对R1进行加密,进行16轮。最后互换左右数据拼接成64bit的密文。

DES解密逻辑相同,但是子密钥的使用顺序相反,我们可以通过写内存的方式修改子密钥的顺序,并输入密文得到解密结果。

加解密实现代码

来自python实现DES算法-CSDN博客

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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
import re

# ========================================
# 一、子密钥生成
# (1) 初始置换 64->56
# 64位的种子密钥经过PC_1置换后,生成56位的密钥
# (2) 划分 56->(28,28)
# 经过初始置换后的56位密钥被均分成C0和D0两部分
# (3) 循环左移
# 第一轮,C0和D0根据移位次数表各自进行循环左移
# 得到C1和D1
# 每一轮的C和D值是由上一轮的C和D值循环左移得到的
# (4) 合并 (28,28)->56->48
# 左移后的两部分再次合并,通过一个选择压缩表(PC_2)
# 得到这一轮的子密钥
# (5)重复3、4操作,最终得到16个子密钥
# ========================================

# 置换选择表1(PC_1) 64->56
PC_1 = [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
]

# 选择压缩表2(PC_2) 56->48
PC_2 = [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
]

# 移位次数表
shift_num = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]


def pc_1_change(bin_key):
"""初始置换

64位的种子密钥经过PC_1置换后,生成56位的密钥
"""
return [bin_key[i - 1] for i in PC_1] # 列表形式


def shift_left(bin_key, num):
"""实现C和D的循环左移"""
return bin_key[num:] + bin_key[:num]


def pc_2_change(bin_key):
"""选择压缩

56位的密钥经过PC_2压缩,生成48位子密钥
"""
return ''.join([bin_key[i - 1] for i in PC_2]) # 列表转字符串


def get_subkey_list(bin_key):
"""生成16轮的加解子密钥"""
subkey_list = [] # 存储16轮子密钥
# 1. 初始置换 64->58
temp = pc_1_change(bin_key)
# 2. 循环左移
for i in shift_num:
temp[:28] = shift_left(temp[:28], i) # C部分循环左移
temp[28:] = shift_left(temp[28:], i) # D部分循环左移
subkey_list.append(pc_2_change(temp)) # 生成子密钥
return subkey_list


# ========================================
# 二、DES加解密实现
# ========================================

# 初始置换表IP 64->64
IP = [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
]

# 逆置换表_IP 64->64
_IP = [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 32->48
E = [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
]

# S盒 48->32
S1 = [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
]
S2 = [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
]
S3 = [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
]
S4 = [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
]
S5 = [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
]
S6 = [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
]
S7 = [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
]
S8 = [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
]
S = [S1, S2, S3, S4, S5, S6, S7, S8]

# P盒
P = [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
]


# encrypt
def ip_change(bin_text):
"""初始置换"""
return [bin_text[i - 1] for i in IP]


def s_box(bin_result):
"""S盒替换"""
int_result = []
result = ''
for i in range(8):
# 二进制行号
bin_row = bin_result[i][0] + bin_result[i][5]
# 二进制列号
bin_col = ''.join(bin_result[i][j] for j in range(1, 5))
# 获取对应的十进制数
int_result.append(S[i][16 * int(bin_row, base=2) + int(bin_col, base=2)])
# 十进制转成二进制
result += bin(int_result[-1])[2:].zfill(4)
return result


def p_box(result):
"""P盒置换"""
return ''.join(result[i - 1] for i in P)


def f(R, bin_key):
"""轮函数f()"""
# 1.将R由32位扩展成48位
R_ext = [R[i - 1] for i in E]
# 2.与子密钥进行逐位异或
bin_temp = [str(int(r) ^ int(k)) for r, k in zip(R_ext, bin_key)]
# 6个字符为一组,共8组
bin_result = [''.join(bin_temp[i:i + 6]) for i in range(0, len(bin_temp), 6)]
# 3.S盒替换 48->32
result = s_box(bin_result)
# 4.P盒置换 32->32
return p_box(result)


def _ip_change(bin_text):
"""进行IP-1逆置换"""
return ''.join(bin_text[i - 1] for i in _IP)


def des_cipher(bin_text, bin_key, reverse_keys=False):
"""通用DES加密解密函数"""
# 1. 初始置换IP
bin_text = ip_change(bin_text)
# 2. 分成左右两部分L、R
L, R = bin_text[:32], bin_text[32:]
# 3. 获得16轮子密钥
subkey_list = get_subkey_list(bin_key)
if reverse_keys:
subkey_list = subkey_list[::-1] # 解密时反转子密钥列表
# 4. 进行16轮迭代
for i in subkey_list:
R_temp = R
# 轮函数f()结果和L进行异或
R = ''.join(str(int(r) ^ int(l)) for r, l in zip(f(R, i), L))
L = R_temp
# 5. 进行IP-1逆置换 64->64
return _ip_change(R + L) # 输出二进制字符串


# 使用示例
def str2bin(text):
"""字符串转二进制字符串"""
return ''.join(bin(byte)[2:].zfill(8) for byte in text.encode())


def bin2str(bin_text):
"""二进制字符串转字符串"""
# 1.将二进制字符串按8位分割,并转换为字节数组
byte_array = bytearray(int(i, 2) for i in re.findall(r'.{8}', bin_text) if int(i, 2) != 0)
# 2.将字节序列解码为字符串
return byte_array.decode()


def is_valid_key(key):
"""检查密钥是否有效 64bit"""
return len(key.encode()) == 8


def des_encrypt(plaintext, key):
"""DES加密"""
# 1.明文转成二进制字符串, 0填充至64的倍数
bin_plaintext = str2bin(plaintext)
padding_len = (64 - (len(bin_plaintext) % 64)) % 64
bin_padding_plaintext = bin_plaintext + '0' * padding_len
# 2.进行64位分组加密
bin_group_64 = re.findall(r'.{64}', bin_padding_plaintext)
bin_ciphertext = ''
for g in bin_group_64:
bin_ciphertext += des_cipher(g, str2bin(key))
# 3.密文转为16进制输出
bin_group_4 = re.findall(r'.{4}', bin_ciphertext)
hex_ciphertext = ''
for g in bin_group_4:
hex_ciphertext += format(int(g, 2), 'x')
return hex_ciphertext


def des_decrypt(hex_ciphertext, key):
"""DES解密"""
# 1.16进制密文转为2进制字符串
bin_ciphertext = ''.join(bin(int(h, 16))[2:].zfill(4) for h in hex_ciphertext)
# 2.进行64位分组解密
bin_group_64 = re.findall(r'.{64}', bin_ciphertext)
bin_deciphertext = ''
for g in bin_group_64:
bin_deciphertext += des_cipher(g, str2bin(key), reverse_keys=True)
# 3.将解密密文转为字符串输出
return bin2str(bin_deciphertext)


def des_run():
"""DES启动界面"""
flag = True
while flag:
print('=' * 3, "DES加密解密", '=' * 3)
print('[1]加密')
print('[2]解密')
print('[0]退出')
choice = input('请输入你的选择:')
match choice:
case '0':
flag = False
case '1':
plaintext = input('请输入明文:')
key = input('请输入密钥(64bit):')
if not is_valid_key(key):
print('密钥长度错误')
continue
ciphertext = des_encrypt(plaintext, key)
print(f'密文:{ciphertext}')
case '2':
ciphertext = input('请输入密文:')
key = input('请输入密钥(64bit):')
if not is_valid_key(key):
print('密钥长度错误')
continue
print(f'解密:{des_decrypt(ciphertext, key)}')
case _:
print('输入错误')
print('=' * 15)


if __name__ == '__main__':
des_run()


CRC64

CRC校验原理及实现 - 知乎

循环冗余校验(Cyclic Redundancy Check, CRC)是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术,主要用来检测或校验数据传输或者保存后可能出现的错误。

本质就是一种多项式除法,把原二进制与一个另一个二进制以多项式的形式相除,最后把余数添加到数据末尾用于检验。

我们可以用赛博厨师计算crc的值。

解密脚本(特征)

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
import struct


def shld(a1, a2):
return ((a1 << 1) | (a2 >> 31)) & 0xffffffff


def shl(a1):
return (a1 << 1) & 0xffffffff


def shr(a1):
return (a1 >> 1) & 0xffffffff


def de(buf):
for i in range(0, 10, 2):
ta = buf[i]
tb = buf[i + 1]
for k in range(64):

if (ta & 1):
ta = (0x54AA4A9 ^ ta) & 0xffffffff
ta = shr(ta) | ((tb & 1) << 31)

tb = shr(tb) | (1 << 31)
else:
ta = shr(ta) | ((tb & 1) << 31)

tb = shr(tb)
buf[i] = ta
buf[i + 1] = tb


def main():
flag = [0x149b24c1, 0xbc17996, 0x192ce051, 0x1666bae6, 0xf0f13109, 0x713168a1, 0xcc4fa796, 0x9d5344d9, 0x623329f6, 0x5e22b5da]
de(flag)
for i in range(len(flag)):
print(hex(flag[i]), end=', ')
print()
flag = b''.join(struct.pack("<I", i) for i in flag)
print(flag)


if __name__ == '__main__':
main()

crc32

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
#include <stdint.h>  
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define CRC32_POLYNOMIAL 0xEDB88320

uint32_t crc32_table[256];

void generate_crc32_table() {
uint32_t crc;
for (int i = 0; i < 256; i++) {
crc = i;
for (int j = 0; j < 8; j++) {
if (crc & 1) {
crc = (crc >> 1) ^ CRC32_POLYNOMIAL;
}
else {
crc >>= 1;
}
}
crc32_table[i] = crc;
}
}

uint32_t crc32(const uint8_t* data, size_t length) {
uint32_t crc = 0xFFFFFFFF;
for (size_t i = 0; i < length; i++) {
crc = (crc >> 8) ^ crc32_table[(crc ^ data[i]) & 0xFF];
}
return crc ^ 0xFFFFFFFF;
}
int main() {
uint8_t data[100] = {};
uint32_t result[10];
result[0] = crc32(data, 100);
for (int i = 0; i < 1; i++) {
printf("%2x", data[i]);
}
}

Hash

  • 数据摘要算法,可以理解为有损压缩
  • 因此,hash不可逆,所以如果解题遇到hash基本以算法识别+撞库为主
  • md5、sha1、sha256、sha384、sha512等等
  • 加密过程有大量移位操作且不可逆

MD5

演示动画

特征常量

1
2
3
4
67452301h
0EFCDAB89h
98BADCFEh
10325476h
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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
#include<string.h>
#include<stdio.h>
typedef unsigned char* POINTER; //指针类型定义
typedef struct {
unsigned int state[4]; /* A,B,C,D四个常数 */
unsigned int count[2]; /* 数据的bit数计数器(对2^64取余) */
unsigned char buffer[64]; /* 输入数据缓冲区 */
} MD5_CTX; //存放MD5算法相关信息的结构体定义

void MD5Init(MD5_CTX*);
void MD5Update(MD5_CTX*, unsigned char*, unsigned int);
void MD5Final(unsigned char[16], MD5_CTX*);
void MD5Transform(unsigned int[4], unsigned char[64]);
void Encode(unsigned char*, unsigned int*, unsigned int);
void Decode(unsigned int*, unsigned char*, unsigned int);

//循环左移的位数
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21

//数据填充的内容
unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

//F,G,H,I四个非线性变换函数
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))

//x循环左移n位的操作
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))

//FF,GG,HH,II是四轮循环变换分别用到的变换函数
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (unsigned int)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (unsigned int)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (unsigned int)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (unsigned int)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}

//MD5算法初始化操作
void MD5Init(MD5_CTX* context)
{
//bit计数器清零
context->count[0] = context->count[1] = 0;
//A,B,C,D被初始化为四个特定的常数(Magic Number)
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}

//使用MD5算法对input的数据进行处理
void MD5Update(MD5_CTX* context, unsigned char* input, unsigned int inputLen)
{
unsigned int i, index, partLen;
//计算[已处理数据长度(byte) mod 64]
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
//bit计数器累加
if ((context->count[0] += ((unsigned int)inputLen << 3))
< ((unsigned int)inputLen << 3)) //处理加法进位溢出的情况
context->count[1]++;
context->count[1] += ((unsigned int)inputLen >> 29);
//计算缓冲区还有多少字节空间
partLen = 64 - index;
//以512位数据为一组进行处理
if (inputLen >= partLen) {
memcpy(&context->buffer[index], input, partLen);
MD5Transform(context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform(context->state, &input[i]);
index = 0;
}
else i = 0;
//缓存未处理的输入
memcpy(&context->buffer[index], &input[i], inputLen - i);
}

//获取MD5码(由digest返回),顺便清除context数据
void MD5Final(unsigned char digest[16], MD5_CTX* context)
{
unsigned char bits[8];
unsigned int index, padLen;
//记录数据长度
Encode(bits, context->count, 8);
//填充数据
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5Update(context, PADDING, padLen);
//追加数据长度信息
MD5Update(context, bits, 8);
//获取MD5码。其实就是将ABCD四个32位整数以16进制方式级联
Encode(digest, context->state, 16);
//清除数据
memset(context, 0, sizeof(*context));
}

//MD5变换函数
void MD5Transform(unsigned int state[4], unsigned char block[64])
{
unsigned int a = state[0], b = state[1], c = state[2], d = state[3], x[16];
//将64字节的一组数据进一步划分为16个子分组
Decode(x, block, 64);
//第1轮循环变换
FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
//第2轮循环变换
GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
//第3轮循环变换
HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
//第4轮循环变换
II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */

state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}

//将无符号整数转为字节类型数组
void Encode(unsigned char* output, unsigned int* input, unsigned int len)
{
unsigned int i, j;

for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j + 1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j + 2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j + 3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}

//将字节类型数组转为无符号整数
void Decode(unsigned int* output, unsigned char* input, unsigned int len)
{
unsigned int i, j;

for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((unsigned int)input[j]) | (((unsigned int)input[j + 1]) << 8) |
(((unsigned int)input[j + 2]) << 16) | (((unsigned int)input[j + 3]) << 24);
}

int main()
{
MD5_CTX md5_calc;
//char c[] = { 0,0,0,4,0,0,0,2,0,0,0,125};
unsigned int c[] = { 0x00000007, 0x00000002, 0x0000007D };
unsigned char md5[16];
//演示计算字符串abc的MD5码
MD5Init(&md5_calc);
MD5Update(&md5_calc, (unsigned char*)c, 12);
MD5Final(md5, &md5_calc);
//输出MD5码
for (int i = 0; i < 16; i++) {
md5[i] ^= 0x14;
md5[i] ^= 0x11;
}
printf("字符串abc的MD5码为:");
for (int i = 0; i < 16; i++) printf("%02x", md5[i]);
printf("\n");
return 0;
}

skip32

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
#!/usr/bin/env python3

import struct

FTABLE = (0xa3, 0xd7, 0x09, 0x83, 0xf8, 0x48, 0xf6, 0xf4,
0xb3, 0x21, 0x15, 0x78, 0x99, 0xb1, 0xaf, 0xf9,
0xe7, 0x2d, 0x4d, 0x8a, 0xce, 0x4c, 0xca, 0x2e,
0x52, 0x95, 0xd9, 0x1e, 0x4e, 0x38, 0x44, 0x28,
0x0a, 0xdf, 0x02, 0xa0, 0x17, 0xf1, 0x60, 0x68,
0x12, 0xb7, 0x7a, 0xc3, 0xe9, 0xfa, 0x3d, 0x53,
0x96, 0x84, 0x6b, 0xba, 0xf2, 0x63, 0x9a, 0x19,
0x7c, 0xae, 0xe5, 0xf5, 0xf7, 0x16, 0x6a, 0xa2,
0x39, 0xb6, 0x7b, 0x0f, 0xc1, 0x93, 0x81, 0x1b,
0xee, 0xb4, 0x1a, 0xea, 0xd0, 0x91, 0x2f, 0xb8,
0x55, 0xb9, 0xda, 0x85, 0x3f, 0x41, 0xbf, 0xe0,
0x5a, 0x58, 0x80, 0x5f, 0x66, 0x0b, 0xd8, 0x90,
0x35, 0xd5, 0xc0, 0xa7, 0x33, 0x06, 0x65, 0x69,
0x45, 0x00, 0x94, 0x56, 0x6d, 0x98, 0x9b, 0x76,
0x97, 0xfc, 0xb2, 0xc2, 0xb0, 0xfe, 0xdb, 0x20,
0xe1, 0xeb, 0xd6, 0xe4, 0xdd, 0x47, 0x4a, 0x1d,
0x42, 0xed, 0x9e, 0x6e, 0x49, 0x3c, 0xcd, 0x43,
0x27, 0xd2, 0x07, 0xd4, 0xde, 0xc7, 0x67, 0x18,
0x89, 0xcb, 0x30, 0x1f, 0x8d, 0xc6, 0x8f, 0xaa,
0xc8, 0x74, 0xdc, 0xc9, 0x5d, 0x5c, 0x31, 0xa4,
0x70, 0x88, 0x61, 0x2c, 0x9f, 0x0d, 0x2b, 0x87,
0x50, 0x82, 0x54, 0x64, 0x26, 0x7d, 0x03, 0x40,
0x34, 0x4b, 0x1c, 0x73, 0xd1, 0xc4, 0xfd, 0x3b,
0xcc, 0xfb, 0x7f, 0xab, 0xe6, 0x3e, 0x5b, 0xa5,
0xad, 0x04, 0x23, 0x9c, 0x14, 0x51, 0x22, 0xf0,
0x29, 0x79, 0x71, 0x7e, 0xff, 0x8c, 0x0e, 0xe2,
0x0c, 0xef, 0xbc, 0x72, 0x75, 0x6f, 0x37, 0xa1,
0xec, 0xd3, 0x8e, 0x62, 0x8b, 0x86, 0x10, 0xe8,
0x08, 0x77, 0x11, 0xbe, 0x92, 0x4f, 0x24, 0xc5,
0x32, 0x36, 0x9d, 0xcf, 0xf3, 0xa6, 0xbb, 0xac,
0x5e, 0x6c, 0xa9, 0x13, 0x57, 0x25, 0xb5, 0xe3,
0xbd, 0xa8, 0x3a, 0x01, 0x05, 0x59, 0x2a, 0x46)


def g(key, k, w):
g1 = 0xFF & (w >> 8)
g2 = 0xFF & w

g3 = FTABLE[g2 ^ key[(4 * k + 0) % 10]] ^ g1
g4 = FTABLE[g3 ^ key[(4 * k + 1) % 10]] ^ g2
g5 = FTABLE[g4 ^ key[(4 * k + 2) % 10]] ^ g3
g6 = FTABLE[g5 ^ key[(4 * k + 3) % 10]] ^ g4

return ((g5 << 8) + g6)


def skip32(key, buf, encrypt):
# sort out direction
if encrypt:
k, step = 0, 1
else:
k, step = 23, -1

# pack into words
wl = (buf[0] << 8) + buf[1]
wr = (buf[2] << 8) + buf[3]

# 24 feistel rounds, doubled up
for _ in range(12):
wr ^= g(key, k, wl) ^ k
k += step
wl ^= g(key, k, wr) ^ k
k += step

# implicitly swap halves while unpacking
return bytes((wr >> 8, wr & 0xFF,
wl >> 8, wl & 0xFF))


class Skippy:
def __init__(self, key):
if len(key) < 10:
raise ValueError("key must be at least 10 bytes in length")
self._key = key

def encrypt(self, value):
buf = struct.pack("=I", value)
enc = skip32(self._key, buf, True)
return struct.unpack("=I", enc)[0]

def decrypt(self, value):
buf = struct.pack("=I", value)
dec = skip32(self._key, buf, False)
return struct.unpack("=I", dec)[0]

RSA

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
from Crypto.Util.number import inverse, getPrime
import random

p = 61
q = 53
n = p * q
phi = (p - 1) * (q - 1)

e = 65537
d = inverse(e, phi)

print(f"n = {n}")
print(f"e = {e}")
print(f"d = {d}")

m = 42

# 加密
c = pow(m, e, n)
print(f"Encrypted c = {c}")

# 解密
m2 = pow(c, d, n)
print(f"Decrypted m = {m2}")

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
#include <gmpxx.h>
#include <iostream>

mpz_class hex_to_mpz(const std::string& hex) {
mpz_class res;
mpz_set_str(res.get_mpz_t(), hex.c_str(), 16); // base 16
return res;
}

mpz_class generate_prime(unsigned int bits, gmp_randclass& rng, int trials = 25) {
mpz_class candidate;
while (true) {
candidate = rng.get_z_bits(bits); // 生成随机 bits 位数的大整数
mpz_setbit(candidate.get_mpz_t(), bits - 1); // 确保是 bits 位
mpz_setbit(candidate.get_mpz_t(), 0); // 确保是奇数

if (mpz_probab_prime_p(candidate.get_mpz_t(), trials) > 0) {
return candidate;
}
}
}


int main() {
gmp_randclass rng(gmp_randinit_mt);
rng.seed(1);

mpz_class p = generate_prime(512, rng);
mpz_class q = generate_prime(512, rng);
mpz_class n = p * q; // n = p * q
mpz_class phi = (p - 1) * (q - 1); // phi = (p-1)*(q-1)
mpz_class e = 65537; // 常用 e
mpz_class d;

// 求模逆 d ≡ e^(-1) mod phi
if (!mpz_invert(d.get_mpz_t(), e.get_mpz_t(), phi.get_mpz_t())) {
std::cerr << "Modular inverse does not exist!\n";
return 1;
}

std::cout << "n = " << n << std::endl;
std::cout << "e = " << e << std::endl;
std::cout << "d = " << d << std::endl;

// 明文 m
mpz_class m = hex_to_mpz("1234567890abcdef");

// 加密 c = m^e mod n
mpz_class c;

mpz_powm(c.get_mpz_t(), m.get_mpz_t(), e.get_mpz_t(), n.get_mpz_t());
std::cout << "Encrypted c = " << c << std::endl;

// 解密 m2 = c^d mod n
mpz_class m2;
mpz_powm(m2.get_mpz_t(), c.get_mpz_t(), d.get_mpz_t(), n.get_mpz_t());
std::cout << "Decrypted m = " << m2 << std::endl;

char r[100];
__gmpz_get_str(r, 16, m2.get_mpz_t());
std::cout << "Decrypted hex: " << r << std::endl;

return 0;
}

opensslEVP签名校验

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
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/err.h>
#include <iostream>
#include <vector>
#include <memory>
#include <cstring>

void handle_openssl_error() {
ERR_print_errors_fp(stderr);
abort();
}

// 使用智能指针管理 OpenSSL 结构
using EVP_PKEY_ptr = std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>;
using EVP_MD_CTX_ptr = std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)>;

EVP_PKEY_ptr generate_rsa_key(int bits = 2048) {
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
if (!ctx) handle_openssl_error();

if (EVP_PKEY_keygen_init(ctx) <= 0) handle_openssl_error();
if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) <= 0) handle_openssl_error();

EVP_PKEY *raw_pkey = nullptr;
if (EVP_PKEY_keygen(ctx, &raw_pkey) <= 0) handle_openssl_error();

EVP_PKEY_CTX_free(ctx);
return EVP_PKEY_ptr(raw_pkey, EVP_PKEY_free);
}

std::vector<unsigned char> sign_message(EVP_PKEY *pkey, const unsigned char *msg, size_t msg_len) {
EVP_MD_CTX_ptr ctx(EVP_MD_CTX_new(), EVP_MD_CTX_free);
if (!ctx) handle_openssl_error();

if (EVP_DigestSignInit(ctx.get(), NULL, EVP_sha256(), NULL, pkey) <= 0)
handle_openssl_error();

if (EVP_DigestSignUpdate(ctx.get(), msg, msg_len) <= 0)
handle_openssl_error();

size_t sig_len = 0;
if (EVP_DigestSignFinal(ctx.get(), NULL, &sig_len) <= 0)
handle_openssl_error();

std::vector<unsigned char> signature(sig_len);
if (EVP_DigestSignFinal(ctx.get(), signature.data(), &sig_len) <= 0)
handle_openssl_error();

signature.resize(sig_len);
return signature;
}

bool verify_signature(EVP_PKEY *pkey, const unsigned char *msg, size_t msg_len,
const unsigned char *sig, size_t sig_len) {
EVP_MD_CTX_ptr ctx(EVP_MD_CTX_new(), EVP_MD_CTX_free);
if (!ctx) handle_openssl_error();

if (EVP_DigestVerifyInit(ctx.get(), NULL, EVP_sha256(), NULL, pkey) <= 0)
handle_openssl_error();

if (EVP_DigestVerifyUpdate(ctx.get(), msg, msg_len) <= 0)
handle_openssl_error();

int ret = EVP_DigestVerifyFinal(ctx.get(), sig, sig_len);
return ret == 1;
}

void save_keys(EVP_PKEY *pkey) {
FILE *fpri = fopen("private.pem", "w");
FILE *fpub = fopen("public.pem", "w");
if (!fpri || !fpub) {
std::cerr << "无法打开文件保存密钥\n";
exit(1);
}
PEM_write_PrivateKey(fpri, pkey, NULL, NULL, 0, NULL, NULL);
PEM_write_PUBKEY(fpub, pkey);
fclose(fpri);
fclose(fpub);
}

int main() {
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();

std::string message = "This is a test.";

// 生成 RSA 密钥对
EVP_PKEY_ptr key = generate_rsa_key();
std::cout << "[+] 密钥对生成完成\n";

// 签名消息
std::vector<unsigned char> sig = sign_message(key.get(),
(unsigned char *)message.c_str(), message.size());
std::cout << "[+] 签名完成,长度 = " << sig.size() << "\n";

// 验证签名
bool ok = verify_signature(key.get(),
(unsigned char *)message.c_str(), message.size(),
sig.data(), sig.size());

if (ok) {
std::cout << "[+] 签名验证成功 ✅\n";
} else {
std::cout << "[!] 签名验证失败 ❌\n";
}

// 保存密钥
save_keys(key.get());
std::cout << "[+] 密钥对保存为 PEM 文件\n";

EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
ERR_free_strings();
return 0;
}