CTF逆向常见加密算法总结

流密码系列

只要识别出流密码,我们就可以选择动态调试获取密钥流或者直接把目标密文 patch 进去拿输出就可以了

RC4

比较常见,原理不赘述,可以看我的RC4&RSA | Matriy’s blog

RC4常见时会有一个初始化256个的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
key = list('RC4_1s_4w3s0m3')
content = [0xA7, 0x1A, 0x68, 0xEC, 0xD8, 0x27, 0x11, 0xCC, 0x8C, 0x9B, 0x16, 0x15, 0x5C, 0xD2, 0x67, 0x3E, 0x82, 0xAD,
0xCE, 0x75, 0xD4, 0xBC, 0x57, 0x56, 0xC2, 0x8A, 0x52, 0xB8, 0x6B, 0xD6, 0xCC, 0xF8, 0xA4, 0xBA, 0x72, 0x2F,
0xE0, 0x57, 0x15, 0xB9, 0x24, 0x11]
rc4number = 256
s = [0] * rc4number
flag = ''

def rc4_init(s, key, rc4number):
for i in range(rc4number):
s[i] = i
j = 0
for i in range(rc4number):
j = (j + s[i] + ord(key[i % len(key)])) % rc4number
s[i],s[j] = s[j],s[i]

def rc4_endecode(s, content, rc4number):
i = 0
j = 0
for k in range(len(content)):
i = (i + 1) % rc4number
j = (j + s[i]) % rc4number
s[i],s[j] = s[j],s[i]
t = (s[i] + s[j]) % rc4number
content[k] = chr(content[k] ^ s[t])
content = ''.join(content)
print(content)

rc4_init(s, key, rc4number)
rc4_endecode(s, content, rc4number)

Salsa20

Salsa20是一种流式对称加密算法,类似于Chacha20,算法性能相比AES能够快3倍以上。

Salsa20算法通过将32 Byte的key和8 Byte的随机数nonce扩展为2^70 Byte的随机字节流,通过随机字节流和异或操作实现加解密,因此Salsa20算法中随机字节流的生成为关键所在。

Salsa20算法通过将 32 字节(或者 16 字节)的密钥 和 **8 字节的iv **扩展为伪随机密钥字节流,通过伪随机密钥字节流和异或操作实现加解密。

伪随机密钥字节流的生成其实是使用 密钥、iv、以及一些常量构成 64 字节数据,输入到核心函数中得到 64 字节的输出。

Salsa20 密钥拓展规则如下:

1
2
3
4
5
6
# key 为 32 字节时
c[0] + key[0:16] + c[1] + iv + 计数器(8 bytes) + key[16:32] + c[4]
c = [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574] # expand 32-byte k
# key 为 16 字节时
c[0] + key[0:16] + c[1] + iv + 计数器(8 bytes) + key[0:16] + c[4]
c = [0x61707865, 0x3120646e, 0x79622d36, 0x6b206574] # expand 16-byte k

核心

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
#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
void salsa20_word_specification(uint32 out[16],uint32 in[16])
{
int i;
uint32 x[16];
for (i = 0; i < 16; ++i) x[i] = in[i];
for (i = 20; i > 0; i -= 2) { // 迭代次数,注意每次 i -= 2 !
// 每列
x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9);
x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18);

x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9);
x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18);

x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9);
x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18);

x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9);
x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18);

// 每行
x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9);
x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18);

x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9);
x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18);

x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9);
x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18);

x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9);
x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18);
}
for (i = 0;i < 16;++i) out[i] = x[i] + in[i];
}

后面接着就是 xor 了,看了前面的实现代码,我相信这种加密的识别也并不困难

首先,构造核心函数输入时的参数,是最容易识别的。(当然也是最容易魔改的)

其次,核心函数中的标志性循环左移,以及每一位对应的位移数,不要看着复杂,其实就是 7、9、13、18,可以看到上面的代码中我把每4个分成了一组,因为在实现的时候有时候会把每四个作为一组来处理。

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
#define quarter(a,b,c,d) do {\
b ^= R(d+a, 7);\
c ^= R(a+b, 9);\
d ^= R(b+c, 13);\
a ^= R(c+d, 18);\
} while (0)

void salsa20_words(uint32_t *out, uint32_t in[16]) {
uint32_t x[4][4];
int i;
for (i=0; i<16; ++i) x[i/4][i%4] = in[i];
for (i=0; i<10; ++i) { // 10 double rounds = 20 rounds
// column round: quarter round on each column; start at ith element and wrap
quarter(x[0][0], x[1][0], x[2][0], x[3][0]);
quarter(x[1][1], x[2][1], x[3][1], x[0][1]);
quarter(x[2][2], x[3][2], x[0][2], x[1][2]);
quarter(x[3][3], x[0][3], x[1][3], x[2][3]);
// row round: quarter round on each row; start at ith element and wrap around
quarter(x[0][0], x[0][1], x[0][2], x[0][3]);
quarter(x[1][1], x[1][2], x[1][3], x[1][0]);
quarter(x[2][2], x[2][3], x[2][0], x[2][1]);
quarter(x[3][3], x[3][0], x[3][1], x[3][2]);
}
for (i=0; i<16; ++i) out[i] = x[i/4][i%4] + in[i];
}

最后提醒下,Salsa20 核心函数中的 20 轮也是可以魔改的。

在线解密网站:SSL在线工具-Salsa20在线加解密-Salsa20 encryption-SSLeye官网

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

#define U32C(x) ((uint32_t)(x))
#define ROTL32(v, n) (U32C((v) << (n)) | U32C((v) >> (32 - (n))))

/* -------------------- 工具:小端装载/存储 -------------------- */
static uint32_t load32_le(const uint8_t* p) {
return U32C(p[0]) | (U32C(p[1]) << 8) | (U32C(p[2]) << 16) | (U32C(p[3]) << 24);
}
static void store32_le(uint8_t* p, uint32_t x) {
p[0] = (uint8_t)(x);
p[1] = (uint8_t)(x >> 8);
p[2] = (uint8_t)(x >> 16);
p[3] = (uint8_t)(x >> 24);
}

/* -------------------- Salsa20 核心(20轮) -------------------- */
/* quarterround 原位宏(按论文次序:+、ROTL、XOR) */
#define QR(a,b,c,d) \
do { \
b ^= ROTL32(a + d, 7); \
c ^= ROTL32(b + a, 9); \
d ^= ROTL32(c + b,13); \
a ^= ROTL32(d + c,18); \
} while(0)

/* 对 16×32bit 状态做 Salsa20/20 轮,out = in + 轮后状态 */
static void salsa20_block(uint32_t out[16], const uint32_t in[16]) {
uint32_t x[16];
memcpy(x, in, sizeof(x));

// 若轮数不同,则在此处修改
for (int i = 0; i < 10; i++)
{ /* 20轮 = 10次(列轮+行轮) */
/* column round */
QR(x[0], x[4], x[8], x[12]);
QR(x[5], x[9], x[13], x[1]);
QR(x[10], x[14], x[2], x[6]);
QR(x[15], x[3], x[7], x[11]);
/* row round */
QR(x[0], x[1], x[2], x[3]);
QR(x[5], x[6], x[7], x[4]);
QR(x[10], x[11], x[8], x[9]);
QR(x[15], x[12], x[13], x[14]);
}
for (int i = 0; i < 16; i++) out[i] = x[i] + in[i];
}

/* -------------------- Salsa20 加/解密(32字节密钥) -------------------- */
/* key: 32字节; nonce: 8字节; counter: 64位块计数 */
void salsa20_xor(uint8_t* out, const uint8_t* in, size_t len,
const uint8_t key[32], const uint8_t nonce[8], uint64_t counter)
{
/* 常量 "expand 32-byte k" → 4个32位小端 */
static const uint32_t c0 = 0x61707865; /* "expa" */
static const uint32_t c1 = 0x3320646e; /* "nd 3" */
static const uint32_t c2 = 0x79622d32; /* "2-by" */
static const uint32_t c3 = 0x6b206574; /* "te k" */

uint32_t state[16];
uint8_t ks[64];
size_t off = 0;

/* 初始状态(严格按规范) */
state[0] = c0;
state[1] = load32_le(key + 0);
state[2] = load32_le(key + 4);
state[3] = load32_le(key + 8);
state[4] = load32_le(key + 12);
state[5] = c1;
state[6] = load32_le(nonce + 0); /* nonce 低32位 */
state[7] = load32_le(nonce + 4); /* nonce 高32位 */
state[8] = (uint32_t)(counter & 0xFFFFFFFFu); /* 计数器低32 */
state[9] = (uint32_t)(counter >> 32); /* 计数器高32 */
state[10] = c2;
state[11] = load32_le(key + 16);
state[12] = load32_le(key + 20);
state[13] = load32_le(key + 24);
state[14] = load32_le(key + 28);
state[15] = c3;

while (len) {
uint32_t block[16];
salsa20_block(block, state);

/* 导出 64 字节密钥流(小端) */
for (int i = 0; i < 16; i++) store32_le(ks + 4 * i, block[i]);

size_t n = len < 64 ? len : 64;
for (size_t i = 0; i < n; i++) out[off + i] = in[off + i] ^ ks[i];

off += n;
len -= n;

/* 计数器自增(64位,小端放在 state[8], state[9]) */
state[8]++;
if (state[8] == 0) state[9]++;
}
}

/* -------------------- Demo 测试 -------------------- */
static void hexprint(const uint8_t* p, size_t n) {
for (size_t i = 0; i < n; i++) {
printf("%02X%s", p[i], (i + 1 == n) ? "" : ((i % 16 == 15) ? "\n" : " "));
}
if (n && n % 16) puts("");
}

int main(void) {
// key秘钥(32字节)
uint8_t key[32] = "1234567890123456789012345678901";
// 初始化向量(IV),也称一次性数字(nonce)
uint8_t nonce[8] = { 0 };
// 明文或密文
const char* msg = "Hello, Salsa20! This is a test message.";
size_t len = strlen(msg);

uint8_t* pt = (uint8_t*)msg;
uint8_t* ct = (uint8_t*)malloc(len);
uint8_t* dec = (uint8_t*)malloc(len);

if (!ct || !dec) return 1;

/* 加密 */
salsa20_xor(ct, pt, len, key, nonce, 0);

/* 解密(同一函数) */
salsa20_xor(dec, ct, len, key, nonce, 0);

printf("Plaintext: %.*s\n", (int)len, pt);
printf("Ciphertext (hex):\n");
hexprint(ct, len);
printf("Decrypted: %.*s\n", (int)len, dec);

free(ct);
free(dec);
return 0;
}

在逆向分析实战中判断Salsa20算法的可从一下几点入手:

  1. 初始化矩阵中出现 "expand 32-byte k""expand 16-byte k".
  2. 使用 ROTL32 循环左移 7、9、13、18 位
  3. 20 轮循环,且分为 “列变换” 与 “行变换” 两个阶段。
  4. 数据块为 64 字节,逐块生成密钥流。

ChaCha20

Chacha20流密码经常和Poly1305消息认证码结合使用,被称为ChaCha20-Poly1305,由Google公司率先在Andriod移动平台中的Chrome中代替RC4使用,由于其算法精简、安全性强、兼容性强等特点,目前Google致力于全面将其在移动端推广。

ChaCha20算法使用256位的密钥(32字节) 和一个12字节的随机数(称为nonce) 作为输入,生成一个可变长度的伪随机比特流,然后与明文进行异或运算得到密文。ChaCha20算法的特点是快速、安全、易于实现和内存友好,适用于高速网络通信和移动设备。

ChaCha20 的 密钥为 32 字节iv 为 12 字节计数器为 4 字节

ChaCha20 密钥拓展规则如下:

1
2
c[0:4] + key[0:32] + 计数器(4 bytes) + iv
c = [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574] # expand 32-byte k
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
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) {
int i;
uint32_t x[16];

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

for (i = num_rounds; i > 0; i -= 2) {
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);
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);
}

RCTF2022 中的checkserver 中的加密,看密钥 64 字节,没有iv,也没有常量,看起来好像不是 ChaCha20,但是看后面,标志性的循环左移16 12 8 7,我们就可以很容易的识别出来,这是一个去除了密钥拓展的 ChaCha20.

image-20251003173601690

在逆向分析中判断 ChaCha20 的常见特征:

  1. 常量字符串 "expand 32-byte k" 出现在初始化矩阵中(可能是 ASCII 值形式)。
  2. 内部循环 20 轮(10 次双轮),每轮包含多次 Quarter Round。
  3. 使用 循环左移 16、12、8、7 位的 ROTL 操作。
  4. 处理的数据块大小为 64 字节

解密代码:

python用库版:

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

from Crypto.Cipher import ChaCha20
key = b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'
plaintext = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_"
nonce = b'\\x00\\x00'

cipher = ChaCha20.new(key=key,nonce=nonce)
ciphertext = cipher.encrypt(plaintext)

# 获取 nonce(用于解密)
nonce = cipher.nonce

# 解密
cipher = ChaCha20.new(key=key, nonce=nonce)
decrypted_text = cipher.decrypt(ciphertext)
print(decrypted_text)
a = [hex(i) for i in ciphertext]
print(a)

cpp版原理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>

#define U32C(x) ((uint32_t)(x))
#define ROTL32(v,n) (U32C((v) << (n)) | U32C((v) >> (32 - (n))))

/* -------------------- 工具:小端装载/存储 -------------------- */
static uint32_t load32_le(const uint8_t* p) {
return U32C(p[0]) | (U32C(p[1]) << 8) | (U32C(p[2]) << 16) | (U32C(p[3]) << 24);
}
static void store32_le(uint8_t* p, uint32_t x) {
p[0] = (uint8_t)(x);
p[1] = (uint8_t)(x >> 8);
p[2] = (uint8_t)(x >> 16);
p[3] = (uint8_t)(x >> 24);
}

/* -------------------- ChaCha20 核心 -------------------- */
#define QR(a,b,c,d) \
do { \
a += b; d ^= a; d = ROTL32(d,16); \
c += d; b ^= c; b = ROTL32(b,12); \
a += b; d ^= a; d = ROTL32(d, 8); \
c += d; b ^= c; b = ROTL32(b, 7); \
} while(0)

/* 对 16×32bit 状态做 20 轮 ChaCha20,out = in + 轮后状态 */
static void chacha20_block(uint32_t out[16], const uint32_t in[16]) {
uint32_t x[16];
memcpy(x, in, sizeof(x));

for (int i = 0; i < 10; i++) { // 20轮 = 10次 column+diagonal
// column round
QR(x[0], x[4], x[8], x[12]);
QR(x[1], x[5], x[9], x[13]);
QR(x[2], x[6], x[10], x[14]);
QR(x[3], x[7], x[11], x[15]);
// diagonal round
QR(x[0], x[5], x[10], x[15]);
QR(x[1], x[6], x[11], x[12]);
QR(x[2], x[7], x[8], x[13]);
QR(x[3], x[4], x[9], x[14]);
}

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

/* -------------------- ChaCha20 加/解密 -------------------- */
/* key: 32字节; nonce: 8字节; counter: 64位块计数 */
void chacha20_xor(uint8_t* out, const uint8_t* in, size_t len,
const uint8_t key[32], const uint8_t nonce[8], uint64_t counter)
{
static const uint32_t c0 = 0x61707865; // "expa"
static const uint32_t c1 = 0x3320646e; // "nd 3"
static const uint32_t c2 = 0x79622d32; // "2-by"
static const uint32_t c3 = 0x6b206574; // "te k"

uint32_t state[16];
uint8_t ks[64];
size_t off = 0;

state[0] = c0;
state[1] = c1;
state[2] = c2;
state[3] = c3;

state[4] = load32_le(key + 0);
state[5] = load32_le(key + 4);
state[6] = load32_le(key + 8);
state[7] = load32_le(key + 12);
state[8] = load32_le(key + 16);
state[9] = load32_le(key + 20);
state[10] = load32_le(key + 24);
state[11] = load32_le(key + 28);

state[12] = (uint32_t)(counter & 0xFFFFFFFFu);
state[13] = (uint32_t)(counter >> 32);

state[14] = load32_le(nonce + 0);
state[15] = load32_le(nonce + 4);

while (len) {
uint32_t block[16];
chacha20_block(block, state);

for (int i = 0; i < 16; i++) store32_le(ks + 4 * i, block[i]);

size_t n = len < 64 ? len : 64;
for (size_t i = 0; i < n; i++) out[off + i] = in[off + i] ^ ks[i];

off += n;
len -= n;

state[12]++;
if (state[12] == 0) state[13]++;
}
}

/* -------------------- Demo 测试 -------------------- */
static void hexprint(const uint8_t* p, size_t n) {
for (size_t i = 0; i < n; i++) {
printf("%02X%s", p[i], (i + 1 == n) ? "" : ((i % 16 == 15) ? "\n" : " "));
}
if (n && n % 16) puts("");
}

int main(void) {
uint8_t key[32] = "1234567890123456789012345678902";
uint8_t nonce[8] = { 0,0,0,0,0,0,0,0 };
const char* msg = "Hello, ChaCha20! This is a test message.";
size_t len = strlen(msg);

uint8_t* pt = (uint8_t*)msg;
uint8_t* ct = (uint8_t*)malloc(len);
uint8_t* dec = (uint8_t*)malloc(len);

if (!ct || !dec) return 1;

chacha20_xor(ct, pt, len, key, nonce, 0);
chacha20_xor(dec, ct, len, key, nonce, 0);

printf("Plaintext: %.*s\n", (int)len, pt);
printf("Ciphertext (hex):\n");
hexprint(ct, len);
printf("Decrypted: %.*s\n", (int)len, dec);

free(ct);
free(dec);
return 0;
}

在线解密网站在线ChaCha20加密解密工具

ZUC

祖冲之加密算法(ZUC)是我国自主设计的流密码算法,主要用于与4G网络中的加密,目前主要应用在通信领域当中。

特征有两个S盒

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
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
from math import ceil

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

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

D = [
0x44D7, 0x26BC, 0x626B, 0x135E, 0x5789, 0x35E2, 0x7135, 0x09AF,
0x4D78, 0x2F13, 0x6BC4, 0x1AF1, 0x5E26, 0x3C4D, 0x789A, 0x47AC
]


def addition_uint31(a, b):
c = a + b
return (c & 0x7FFFFFFF) + (c >> 31)


def rotl_uint31(a, shift):
return ((a << shift) | (a >> (31 - shift))) & 0x7FFFFFFF


def rotl_uint32(a, shift):
return ((a << shift) | (a >> (32 - shift))) & 0xFFFFFFFF


def l1(x):
return (x ^ rotl_uint32(x, 2) ^ rotl_uint32(x, 10) ^ rotl_uint32(x, 18) ^ rotl_uint32(x, 24))


def l2(x):
return (x ^ rotl_uint32(x, 8) ^ rotl_uint32(x, 14) ^ rotl_uint32(x, 22) ^ rotl_uint32(x, 30))


def make_uint32(a, b, c, d):
return ((a << 24) & 0xffffffff) | ((b << 16) & 0xffffffff) | ((c << 8) & 0xffffffff) | d


def make_uint31(a, b, c):
return ((a << 23) & 0x7fffffff) | ((b << 8) & 0x7fffffff) | c


class ZUC(object):
def __init__(self, key, iv):
self.r = [0, 0]
self.lfsr = [0 for _ in range(16)]
self.x = [0, 0, 0, 0]
self.zuc_init(key, iv)

def bit_reorganization(self):
self.x[0] = ((self.lfsr[15] & 0x7FFF8000) << 1) | (self.lfsr[14] & 0xFFFF)
self.x[1] = ((self.lfsr[11] & 0xFFFF) << 16) | (self.lfsr[9] >> 15)
self.x[2] = ((self.lfsr[7] & 0xFFFF) << 16) | (self.lfsr[5] >> 15)
self.x[3] = ((self.lfsr[2] & 0xFFFF) << 16) | (self.lfsr[0] >> 15)

def lfsr_next(self):
f = self.lfsr[0]
v = rotl_uint31(self.lfsr[0], 8)
f = addition_uint31(f, v)
v = rotl_uint31(self.lfsr[4], 20)
f = addition_uint31(f, v)
v = rotl_uint31(self.lfsr[10], 21)
f = addition_uint31(f, v)
v = rotl_uint31(self.lfsr[13], 17)
f = addition_uint31(f, v)
v = rotl_uint31(self.lfsr[15], 15)
f = addition_uint31(f, v)
return f

def lfsr_append(self, f):
self.lfsr.append(f)
if len(self.lfsr) > 16:
self.lfsr.pop(0)

def lfsr_init(self, u):
self.lfsr_append(addition_uint31(self.lfsr_next(), u))

def lfsr_shift(self):
self.lfsr_append(self.lfsr_next())

def f(self):
W = ((self.x[0] ^ self.r[0]) + self.r[1]) & 0xffffffff
W1 = (self.r[0] + self.x[1]) & 0xffffffff
W2 = self.r[1] ^ self.x[2]
u = l1(((W1 & 0x0000ffff) << 16) | (W2 >> 16))
v = l2(((W2 & 0x0000ffff) << 16) | (W1 >> 16))
self.r = [make_uint32(S0[u >> 24], S1[(u >> 16) & 0xFF],
S0[(u >> 8) & 0xFF], S1[u & 0xFF]),
make_uint32(S0[v >> 24], S1[(v >> 16) & 0xFF],
S0[(v >> 8) & 0xFF], S1[v & 0xFF])]
return W

def zuc_init(self, key, iv):
# Expand key.
self.lfsr = [make_uint31(key[i], D[i], iv[i]) for i in range(16)]
self.r = [0, 0]
for i in range(32):
self.bit_reorganization()
w = self.f()
self.lfsr_init(w >> 1)

def zuc_generate_keystream(self, length):
keystream_buffer = []
self.bit_reorganization()
self.f() # Discard the output of F.

def itor():
self.lfsr_shift()
self.bit_reorganization()
return self.f() ^ self.x[-1]

keystream_buffer = [itor() for _ in range(length)]
self.lfsr_shift()
return keystream_buffer

def zuc_encrypt(self, input):
length = len(input)
key_stream = self.zuc_generate_keystream(length)
return [inp ^ key_stream[i] for i, inp in enumerate(input)]


if '__main__' == __name__:
key = [0x00] * 16
iv = [0x00] * 16
zuc = ZUC(key, iv)
# 加密过程
out = zuc.zuc_encrypt(b"i love u")
print("加密得到的字流", ["%08x" % e for e in out])
# 解密过程
zuc2 = ZUC(key, iv)
out2 = zuc2.zuc_encrypt(out)
print("解密得到的字流", ["%08x" % e for e in out2])
print(bytes(out2))

TEA系列

不介绍原理了,直接看解密代码吧,不是很难

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

using namespace std;

void decrypt(uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1];
uint32_t delta = 0x9e3779b9;
uint32_t sum = (32) * delta;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
for (uint32_t 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() {
unsigned char enc[] = { 0x2f, 0x33, 0x20, 0x70, 0xac, 0x7e, 0x89, 0x4, 0xca, 0xd2, 0xfb, 0x3, 0x51, 0x8c, 0x80, 0x23, 0x69, 0xe0, 0xc0, 0xe5, 0x41, 0x62, 0xf2, 0x26, 0xb8, 0x87, 0xa4, 0x33, 0xfb, 0x7a, 0x29, 0xe4, 0x45, 0x20, 0x3c, 0x2a, 0xfe, 0x2c, 0xec, 0x18, 0xf3, 0x2, 0x1, 0xe, 0x99, 0x3b, 0x7, 0x21};
unsigned int* key = (uint32_t*)"sO*h4hdsOm3!!sg!";
for (int i = 0; i < 48; i += 4) swap(enc[i], enc[i + 3]), swap(enc[i + 1], enc[i + 2]);
for (int i = 0; i < 48; i++) enc[i] ^= 0x27;
for (int i = 10; i >= 0; i--) {
decrypt((uint32_t*)&enc[4 * i], key);
}
cout << enc;

}

输入出也可以这样

1
2
3
uint32_t enc[8] = { 0x877A62A6, 0x6A55F1F3, 0xAE194847, 0xB1E643E7, 0xA94FE881, 0x9BC8A28A, 0xC4CFAA9F, 0xF1A00CA1, };
printf("L3HCTF{%.32s}\n", enc);
printf("L3HCTF{");

XTEA

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

void decrypt(uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1];
uint32_t delta = 0x9e3779b9;
uint32_t sum = 32 * delta;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
for (int 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;
}

void decrypt2(uint32_t* v, uint32_t* key) {
uint32_t delta = 0x9e3779b9;
// unsigned int delta = 0x9e3779b9;
uint32_t sum = 32 * delta;
uint32_t v1 = v[0];
uint32_t v0 = v[1];
for (int i = 0; i < 32; i++) {
v0 -= (sum + key[(sum >> 11) & 3]) ^ (v1 + ((16 * v1) ^ (v1 >> 5)));
sum -= delta;
v1 -= (sum + key[sum & 3]) ^ (v0 + ((16 * v0) ^ (v0 >> 5)));
}
v[0] = v1;
v[1] = v0;
}

int main() {
// 原始密文数据
unsigned char enc[] = {
0x18, 0x09, 0x1C, 0x14, 0x37, 0x1D, 0x16, 0x2D, 0x3C, 0x05,
0x16, 0x3E, 0x02, 0x03, 0x10, 0x2C, 0x0E, 0x31, 0x39, 0x15,
0x04, 0x3A, 0x39, 0x03, 0x0D, 0x13, 0x2B, 0x3E, 0x06, 0x08,
0x37, 0x00, 0x17, 0x0B, 0x00, 0x1D, 0x1C, 0x00, 0x16, 0x06,
0x07, 0x17, 0x30, 0x03, 0x30, 0x06, 0x0A, 0x71
};
unsigned char xore[] = { 0xDA, 0x30, 0x23, 0xE3, 0xDC, 0x39, 0x82, 0x60, 0xA5, 0x44,
0x68, 0xC2, 0x43, 0x7A, 0xBB, 0xE4, 0x50, 0xE1, 0x02, 0xC2,
0x81, 0x59, 0xEA, 0x1E, 0xC6, 0x8B, 0x71, 0x38, 0x27, 0x83,
0x94, 0xD8, 0xF4, 0x8D, 0x1A, 0x2A, 0x56, 0x8A, 0x4A, 0xD4,
0x54, 0xDC, 0x24, 0x3F, 0xB9, 0xED, 0x7B, 0x9A };
unsigned char keya[] = "Laughter_is_poison_to_fear";
for (int i = 0; i < 48; i++) enc[i] ^= xore[i];
unsigned int* k = (unsigned int*)enc;
unsigned int* key = (uint32_t*)"{you_find_it_!?}";
for (int j = 0; j < 12; j += 2) {
decrypt2(&k[j], key);
}
for (int i = 0; i < 48; i++) enc[i] ^= keya[i % 26];
for (int i = 0; i < 48; i++) printf("%c", enc[i]);
return 0;
}

XXTEA

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
def dwords_to_bytes_little_endian(dword_array):
byte_list = []
for dword in dword_array:
byte_list.extend(dword.to_bytes(4, byteorder='little'))
return byte_list

def XXTEA(m, k):
n = 8
delta = 0x61C88646
r = 6 + 52 // n
mul = (r * delta) & 0xFFFFFFFF
rounds = 6 + mul // delta
ttl = 0
for j in range(rounds-1, -1, -1):
ttl = (ttl + delta) & 0xFFFFFFFF
e = ttl >> 2 & 3
for i in range(n):
after = m[(i + 1) % n]
before = m[(i - 1) % n]
m[i] = (m[i] + (((before >> 5) ^ (after << 2)) + ((after >> 3) ^ (before << 4)) ^ ((ttl ^ after) + (k[(i ^ e) & 3] ^ before)))) & 0xFFFFFFFF
return m

def de_XXTEA(m, k):
n = 8
delta = 0x61C88646
r = 6 + 52 // n
mul = (r * delta) & 0xFFFFFFFF
rounds = 6 + mul // delta
ttl = ((rounds + 1) * delta) & 0xFFFFFFFF
for j in range(0, rounds, 1):
ttl = (ttl - delta) & 0xFFFFFFFF
e = ttl >> 2 & 3
for i in range(n-1, -1, -1):
after = m[(i + 1) % n]
before = m[(i - 1) % n]
m[i] = (m[i] - (((before >> 5) ^ (after << 2)) + ((after >> 3) ^ (before << 4)) ^ ((ttl ^ after) + (k[(i ^ e) & 3] ^ before)))) & 0xFFFFFFFF
return m

dwordenc = [0xA9934E2F, 0x030B90FA, 0x0DCBF1D3, 0x328B5BDE,
0x044FAB4E, 0x1DCF0051, 0x85EBBE55, 0x93AA773A]
dwordkey = [0x2daf, 0x669d, 0x3954, 0x3e5a]

# 解密flag
dwordflag = de_XXTEA(dwordenc, dwordkey)
flag = bytearray(dwords_to_bytes_little_endian(dwordflag))
print(flag.decode())
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
# Implement the recovered cipher and solve for the plaintext that encrypts to the given 'ans'.
from ctypes import c_uint32

DELTA = 0x87654321
K = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476]

def MX(z, y, total, key, p, e):
temp1 = (z.value >> 6 ^ y.value << 4) + (y.value >> 2 ^ z.value << 5)
temp2 = (total.value ^ y.value) + (key[(p & 3) ^ e.value] ^ z.value)
return c_uint32(temp1 ^ temp2)

def enc(v):
n = len(v)
key = K
delta = DELTA
rounds = 6 + 52//n
total = c_uint32(0)
z = c_uint32(v[n-1])
e = c_uint32(0)
v = [c_uint32(x).value for x in v]
while rounds > 0:
total.value = (total.value + delta) & 0xFFFFFFFF
e.value = (total.value >> 2) & 3
for p in range(n-1):
y = c_uint32(v[p+1])
v[p] = c_uint32(v[p] + MX(z, y, total, key, p, e).value).value
z.value = v[p]
y = c_uint32(v[0])
v[n-1] = c_uint32(v[n-1] + MX(z, y, total, key, n-1, e).value).value
z.value = v[n-1]
rounds -= 1
return v

def dec(v):
n = len(v)
key = K
delta = DELTA
rounds = 6 + 52//n
total = c_uint32((rounds * delta) & 0xFFFFFFFF)
e = c_uint32(0)
v = [c_uint32(x).value for x in v]
while total.value != 0:
e.value = (total.value >> 2) & 3
# p from n-1 down to 1
for p in range(n-1, 0, -1):
z = c_uint32(v[p-1])
y = c_uint32(v[(p+1) % n])
v[p] = c_uint32(v[p] - MX(z, y, total, key, p, e).value).value
# p = 0
z = c_uint32(v[n-1])
y = c_uint32(v[(0+1) % n])
v[0] = c_uint32(v[0] - MX(z, y, total, key, 0, e).value).value
total.value = (total.value - delta) & 0xFFFFFFFF
return v

def ints2bytes(v):
out = bytearray()
for i in range(0, len(v), 2):
out += int(v[i]).to_bytes(4, 'little')
out += int(v[i+1]).to_bytes(4, 'little')
return bytes(out)

def bytes2ints(cs: bytes):
# exact reimplementation of the challenge's bytes2ints padding
new_length = len(cs) + (8 - len(cs) % 8) % 8
barray = cs.ljust(new_length, b'\x00')
i = 0
v = []
while i < new_length:
v0 = int.from_bytes(barray[i:i+4], 'little')
v1 = int.from_bytes(barray[i+4:i+8], 'little')
v.append(v0); v.append(v1)
i += 8
return v

ans = [1374278842, 2136006540, 4191056815, 3248881376]

# Decrypt 2-block (4 words) ciphertext to get 16-byte plaintext
pt_words = dec(ans[:])

pt_bytes = ints2bytes(pt_words)

pt_words, pt_bytes, len(pt_bytes)

print(pt_words)
print('*CTF{' +pt_bytes.decode()+'}')
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
import binascii
from ctypes import *
import struct


def MX(z, y, total, key, p, e):
temp1 = (z.value >> 5 ^ y.value << 2) + (y.value >> 3 ^ z.value << 4)
temp2 = (total.value ^ y.value) + (key[(p & 3) ^ e.value] ^ z.value)

return c_uint32(temp1 ^ temp2)


def decrypt(n, v, key):
delta = 0x61C88647
rounds = 6 + 52 // n

total = c_uint32(-rounds * delta)
y = c_uint32(v[0])
e = c_uint32(0)

while rounds > 0:
e.value = (total.value >> 2) & 3
for p in range(n - 1, 0, -1):
z = c_uint32(v[p - 1])
v[p] = c_uint32((v[p] - MX(z, y, total, key, p, e).value)).value
y.value = v[p]
z = c_uint32(v[n - 1])
v[0] = c_uint32(v[0] - MX(z, y, total, key, 0, e).value).value
y.value = v[0]
total.value += delta
rounds -= 1

return v


if __name__ == "__main__":
ct = "7218181A02F79F4B5773E8FFE83FE732DF96259FF2B86AAB945468A132A83D83CF9D750E316C8675"
ct = binascii.a2b_hex(ct)
flag = ""
key = "Wowww111auUu3"
v = struct.unpack('<10I', ct)
k = struct.unpack('<4I', key.encode() + b'\x00' * 3)
v = list(v)
k = list(k)
n = 10
res = decrypt(n, v, k)
for r in res:
print(r.to_bytes(4, 'little').decode(), end='')

cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <stdio.h>
#include <stdint.h>

#define MX (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z)))

void xxtea_decrypt(uint32_t* v, int n, uint32_t const key[4]) {
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1) {
rounds = 6 + 52 / n;
sum = rounds * 0x9E3779B9;
y = v[0];
do {
e = (sum >> 2) & 3;
for (p = n - 1; p > 0; p--) {
z = v[p - 1];
y = v[p] -= MX;
}
z = v[n - 1];
y = v[0] -= MX;
sum -= 0x9E3779B9;
} while (--rounds);
}
}

int main() {
uint32_t encrypted[2] = { 0x8F748963, 0xCB1D96A8 };
uint32_t key[4] = { 0x12345678, 0x9ABCDEF0, 0xFEDCBA98, 0x87654321 };

xxtea_decrypt(encrypted, 2, key);

// 按小端序输出每个DWORD的字节
unsigned char* flag = (unsigned char*)encrypted;
for (int i = 0; i < 8; i++) {
printf("%c", flag[i]);
}
printf("\n");

return 0;
}

哈希

这系列可以直接cyberchef,但是逆向时仍然需要识别它

MD5

MD5算法是消息摘要算法,也是单项散列算法,其作用是将一个任意长度的消息压缩成固定长度,该算法默认会产生一个128位的消息摘要,常用于验证消息完整性以及数字签名等。

逆向识别方式:

消息摘要初始化时,会用4个变量来辅助计算消息摘要,这些寄存器会被初始化为:

A=>01234567h B=>89abcdefh C=>fedcba98h d=>76543210h

其主要加密代码是这样的,先是初始化这四个变量,然后再更新。

1
2
3
4
MD5Init(&context);
MD5Update(&context,szName,dtLength);
MD5Update(&context,szTeam,lstrlen(szTeam));
MD5Final(szHash, &context);

image-20251003202201117

md5数据库:md5在线解密破解,md5解密加密

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

#include "md5.h"


unsigned int ROTATE_LEFT(unsigned int x, unsigned int n) {
return ((x << n) | (x >> (32 - n)));
}

unsigned int F(unsigned int X, unsigned int Y, unsigned int Z) {
return (X & Y) | ((~X) & Z);
}

unsigned int G(unsigned int X, unsigned int Y, unsigned int Z) {
return (X & Z) | (Y & (~Z));
}

unsigned int H(unsigned int X, unsigned int Y, unsigned int Z) {
return (X ^ Y ^ Z);
}

unsigned int I(unsigned int X, unsigned int Y, unsigned int Z) {
return (Y ^ (X | (~Z)));
}

void FF(unsigned int *a,unsigned int b,unsigned int c,unsigned int d,unsigned int m,unsigned int const t,unsigned int s){
*a += F(b,c,d) + m + t;
*a = ROTATE_LEFT(*a,s);
*a += b;

return;
}

void GG(unsigned int *a,unsigned int b,unsigned int c,unsigned int d,unsigned int m,unsigned int const t,unsigned int s){
*a += G(b,c,d) + m + t;
*a = ROTATE_LEFT(*a,s);
*a += b;

return;
}

void HH(unsigned int *a,unsigned int b,unsigned int c,unsigned int d,unsigned int m,unsigned int const t,unsigned int s){
*a += H(b,c,d) + m + t;
*a = ROTATE_LEFT(*a,s);
*a += b;

return;
}

void II(unsigned int *a,unsigned int b,unsigned int c,unsigned int d,unsigned int m,unsigned int const t,unsigned int s){
*a += I(b,c,d) + m + t;
*a = ROTATE_LEFT(*a,s);
*a += b;

return;
}

unsigned int shift(unsigned int a){
unsigned int t1,t2,t3,t4;
t1 = (a & 0xFF) << 24;
t2 = (a & 0xFF00) << 8;
t3 = (a >> 8) & 0xFF00;
t4 = (a >> 24) & 0xFF;
//printf("%x\\n",t1 + t2 + t3 + t4);
return (t1 + t2 + t3 + t4);
}



/* MD5 initialization */
void md5_init(unsigned int *A,unsigned int *B,unsigned int *C,unsigned int *D){
unsigned char data[] = {
0x01, 0x23, 0x45, 0x67,
0x89, 0xAB, 0xCD, 0xEF,
0xFE, 0xDC, 0xBA, 0x98,
0x76, 0x54, 0x32, 0x10
};

memcpy(A, data, 4);
memcpy(B, data + 4, 4);
memcpy(C, data + 8, 4);
memcpy(D, data + 12, 4);
return;
}

size_t md5_update(char **out, char const *input, size_t inLen){
int i;
int j;

size_t bitLen = inLen * 8; // the bit length of input
//size_t fillLen = 64 - (inLen - 56) % 64; // the length of padding
//printf("len:%d\\n",fillLen);
size_t fillLen = 56 - (inLen % 64);
//printf("temp:%d\\n",temp);
size_t filledLen = inLen + fillLen + 8; // the length after padding

char *outBuf = (char*)calloc(filledLen, sizeof(char));
memcpy(outBuf, input, inLen);
outBuf[inLen] = 0x80;// padding 1


j = sizeof(inLen); // the length of input_lengh
for (i = 0; i < j; i++) {
memcpy(outBuf + filledLen - 8 + i, (char*)(&bitLen) + i, 1); // LittleEndian
//memcpy(outBuf + filledLen - 4 + i, (char*)(&bitLen) + j - 1 - i, 1);

}

*out = outBuf; // the data after padding
return filledLen;
}


void md5_transform(unsigned int *out, char *input){
memcpy(out,input,GROUP_SIZE);
return;

}




void data_round(unsigned int *A, unsigned int *B, unsigned int *C, unsigned int *D, unsigned int const *m){
//int k;
unsigned int a = *A;
unsigned int b = *B;
unsigned int c = *C;
unsigned int d = *D;

/* round 1 */
FF(&a,b,c,d,m[0],T[0],S[0]);
FF(&d,a,b,c,m[1],T[1],S[1]);
FF(&c,d,a,b,m[2],T[2],S[2]);
FF(&b,c,d,a,m[3],T[3],S[3]);
FF(&a,b,c,d,m[4],T[4],S[0]);
FF(&d,a,b,c,m[5],T[5],S[1]);
FF(&c,d,a,b,m[6],T[6],S[2]);
FF(&b,c,d,a,m[7],T[7],S[3]);
FF(&a,b,c,d,m[8],T[8],S[0]);
FF(&d,a,b,c,m[9],T[9],S[1]);
FF(&c,d,a,b,m[10],T[10],S[2]);
FF(&b,c,d,a,m[11],T[11],S[3]);
FF(&a,b,c,d,m[12],T[12],S[0]);
FF(&d,a,b,c,m[13],T[13],S[1]);
FF(&c,d,a,b,m[14],T[14],S[2]);
FF(&b,c,d,a,m[15],T[15],S[3]);

/* round 2 */
GG(&a,b,c,d,m[1],T[16],S[4]);
GG(&d,a,b,c,m[6],T[17],S[5]);
GG(&c,d,a,b,m[11],T[18],S[6]);
GG(&b,c,d,a,m[0],T[19],S[7]);
GG(&a,b,c,d,m[5],T[20],S[4]);
GG(&d,a,b,c,m[10],T[21],S[5]);
GG(&c,d,a,b,m[15],T[22],S[6]);
GG(&b,c,d,a,m[4],T[23],S[7]);
GG(&a,b,c,d,m[9],T[24],S[4]);
GG(&d,a,b,c,m[14],T[25],S[5]);
GG(&c,d,a,b,m[3],T[26],S[6]);
GG(&b,c,d,a,m[8],T[27],S[7]);
GG(&a,b,c,d,m[13],T[28],S[4]);
GG(&d,a,b,c,m[2],T[29],S[5]);
GG(&c,d,a,b,m[7],T[30],S[6]);
GG(&b,c,d,a,m[12],T[31],S[7]);

/* round 3 */
HH(&a,b,c,d,m[5],T[32],S[8]);
HH(&d,a,b,c,m[8],T[33],S[9]);
HH(&c,d,a,b,m[11],T[34],S[10]);
HH(&b,c,d,a,m[14],T[35],S[11]);
HH(&a,b,c,d,m[1],T[36],S[8]);
HH(&d,a,b,c,m[4],T[37],S[9]);
HH(&c,d,a,b,m[7],T[38],S[10]);
HH(&b,c,d,a,m[10],T[39],S[11]);
HH(&a,b,c,d,m[13],T[40],S[8]);
HH(&d,a,b,c,m[0],T[41],S[9]);
HH(&c,d,a,b,m[3],T[42],S[10]);
HH(&b,c,d,a,m[6],T[43],S[11]);
HH(&a,b,c,d,m[9],T[44],S[8]);
HH(&d,a,b,c,m[12],T[45],S[9]);
HH(&c,d,a,b,m[15],T[46],S[10]);
HH(&b,c,d,a,m[2],T[47],S[11]);

/* round 4 */
II(&a,b,c,d,m[0],T[48],S[12]);
II(&d,a,b,c,m[7],T[49],S[13]);
II(&c,d,a,b,m[14],T[50],S[14]);
II(&b,c,d,a,m[5],T[51],S[15]);
II(&a,b,c,d,m[12],T[52],S[12]);
II(&d,a,b,c,m[3],T[53],S[13]);
II(&c,d,a,b,m[10],T[54],S[14]);
II(&b,c,d,a,m[1],T[55],S[15]);
II(&a,b,c,d,m[8],T[56],S[12]);
II(&d,a,b,c,m[15],T[57],S[13]);
II(&c,d,a,b,m[6],T[58],S[14]);
II(&b,c,d,a,m[13],T[59],S[15]);
II(&a,b,c,d,m[4],T[60],S[12]);
II(&d,a,b,c,m[11],T[61],S[13]);
II(&c,d,a,b,m[2],T[62],S[14]);
II(&b,c,d,a,m[9],T[63],S[15]);

*A += a;
*B += b;
*C += c;
*D += d;
}


void md5_calc(char *out, char const *input, size_t inLen){
int i;
size_t filledLen;
char *filledData;
unsigned int A,B,C,D;
unsigned int *M = (unsigned int*)malloc(GROUP_SIZE);

filledLen = md5_update(&filledData,input,inLen);

//printf("input:%s\\n",input);

md5_init(&A,&B,&C,&D);
//printf("%x\\n%x\\n%x\\n%x\\n",A,B,C,D);

for(i = 0;i < filledLen / GROUP_SIZE;i++){
md5_transform(M, filledData + i * 64); //char to int
data_round(&A,&B,&C,&D,M);
}

//printf("%x\\n%x\\n%x\\n%x\\n",A,B,C,D);

sprintf(out,"%08x%08x%08x%08x",shift(A),shift(B),shift(C),shift(D));

free(M);
M = NULL;
free(filledData);
filledData = NULL;

return;

}

SHA1

Sha系列算法,又叫做安全散列算法,其包括 sha-1,sha-256,sha-384,sha-512总共这四种,分别产生160/256/384/512位的散列值,该算法与MD4算法设计原理相同,但安全性更高一些。

以sha-1为例,其会产生160位消息摘要,在对消息处理之前,初始散列值H用5个32位双子进行初始化,可以通过识别这些双字压缩常数来确定是否是该算法。

h0=> 67452301h h1=>efcdab89h h2=>98badcfeh h3=>10325476h h4=>c3d2e1f0h

image-20251003203944222

image-20251003202239639

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

#define GROUP_SIZE 64
#define MAX_SIZE 1024

unsigned int const K[64] ={
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};


unsigned int ROR(unsigned int x, unsigned int n);
unsigned int SHR(unsigned int x,unsigned int n);
unsigned int Ch(unsigned int E,unsigned int F,unsigned int G);
unsigned int Maj(unsigned int A,unsigned int B,unsigned int C);
unsigned int Lsigma_0(unsigned int A);
unsigned int Lsigma_1(unsigned int E);
unsigned int Ssigma_0(unsigned int x);
unsigned int Ssigma_1(unsigned int x);

void sha_init(unsigned int *A,unsigned int *B,unsigned int *C,unsigned int *D,unsigned int *E,unsigned int *F,unsigned int *G,unsigned int *H);
size_t sha_update(unsigned char **out, char const *input, size_t inLen);
void sha_transform(unsigned int *out, char *input);
void data_round(unsigned int *A,unsigned int *B,unsigned int *C,unsigned int *D,unsigned int *E,unsigned int *F,unsigned int *G,unsigned int *H,unsigned int const *M);
void sha_calc(char *out, char const *input, size_t inLen);

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

DWORD CRC32(BYTE* ptr, DWORD Size)
{
DWORD crcTable[256], crcTmp1;

// 动态生成CRC-32表
for (int i = 0; i<256; i++)
{
crcTmp1 = i;
for (int j = 8; j>0; j--)
{
if (crcTmp1 & 1) crcTmp1 = (crcTmp1 >> 1) ^ 0xEDB88320L;
else crcTmp1 >>= 1;
}
crcTable[i] = crcTmp1;
}
// 计算CRC32值
DWORD crcTmp2 = 0xFFFFFFFF;
while (Size--)
{
crcTmp2 = ((crcTmp2 >> 8) & 0x00FFFFFF) ^ crcTable[(crcTmp2 ^ (*ptr)) & 0xFF];
ptr++;
}
return (crcTmp2 ^ 0xFFFFFFFF);
}

int main(int argc,char *argv[])
{
char* ptr = "hello lyshark";
DWORD size = sizeof("hello lyshark");

DWORD ret = CRC32((BYTE *)ptr, size);
printf("CRC32 = %x \n", ret);

system("pause");
return 0;
}

分组加密算法

DES

DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的分组算法。

image-20251003204103499

图一中的IPFP分别代表初始置换(Initial Permutation)和末尾置换(Final Permutation),图二中的S1S8是8个置换盒(Substitution-Box),这些都可以作为识别DES算法的特征。
随便在GitHub上扒一份源码,就能找到这些常量:

在2020祥云杯的某道APK逆向里,Findcrypt插件失效(可能是Findcrypt分析不了ARM框架下的文件),所以我们只能靠手动分析找到DES的特征(以下是S1到S8):

image-20251003204124256

image-20251003204140230

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

void encryption(unsigned char * plaintext,unsigned char * ciphertext);
void decryption(unsigned char * ciphertext,unsigned char * plaintext);

void ip_replace(unsigned char * in,unsigned char *out);
void fp_replace(unsigned char * in,unsigned char *out);
void byte2Bit(unsigned char *in,unsigned char *out,int len);
void bit2Byte(unsigned char *in,unsigned char *out,int len);

void f_func(unsigned char *in,unsigned char * out,unsigned char *ki);
void get_subkey(unsigned char *key);

void byteXOR(unsigned char *a,unsigned char *b,int len);
void e_expand(unsigned char * in,unsigned char * out);
void s_replace(unsigned char * in,unsigned char * out);
void p_replace(unsigned char * in,unsigned char * out);

void pc1_replace(unsigned char * in,unsigned char * out);
void pc2_replace(unsigned char *in,unsigned char *out);

const char IP_Table[64]= {
58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7
};

const char IPR_Table[64] = {
40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31,
38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,
36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27,
34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25
};

const char E_Table[48] = {
32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9,
8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,
24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1
};

const char P_Table[32] = {
16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
};

const char PC1_Table[56] = {
57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4
};
const char PC2_Table[48] = {
14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
};

const char LOOP_Table[16] = {
1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1
};
const char S_Box[8][4][16] = {
// 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
};

unsigned char subkey[16][48];

unsigned char result[]={0xef,0x34,0xd4,0xa3,0xc6,0x84,0xe4,0x23};

int main()
{
unsigned char key[9] = "DE3_En1C";

unsigned char plaintext[20];
//HarDd3s?
unsigned char ciphertext[8];
int i=0;

puts("give me a string to encrypt:");

scanf("%s",plaintext);

if(strlen((const char *)plaintext)!=8){
system("pause");
return -1;
}


//to generate 16 round subkey
get_subkey(key);

//to encrypt plaintext
encryption(plaintext,ciphertext);

for(i=0;i<8;++i){
if(ciphertext[i]!=result[i]){
puts("Wrong!!");
system("pause");
return -1;
}
}
puts("G00d Job!!");
system("pause");
return 0;
}

void encryption(unsigned char * plaintext,unsigned char * ciphertext){
int i;
unsigned char array_plaintext[64];
unsigned char f_result[32];
unsigned char left_array[32];
unsigned char right_array[32];

byte2Bit(plaintext,array_plaintext,8);
ip_replace(array_plaintext,array_plaintext);

memcpy(left_array,array_plaintext,32);
memcpy(right_array,array_plaintext+32,32);

for(i=0;i<15;++i){
f_func(right_array,f_result,&subkey[i][0]);
byteXOR(f_result,left_array,32);
memcpy(left_array,right_array,32);
memcpy(right_array,f_result,32);
}

f_func(right_array,f_result,&subkey[i][0]);
byteXOR(left_array,f_result,32);

memcpy(array_plaintext,left_array,32);
memcpy(array_plaintext+32,right_array,32);

fp_replace(array_plaintext,array_plaintext);
bit2Byte(array_plaintext,ciphertext,8);

}


void byte2Bit(unsigned char *in,unsigned char *out,int len){
int i,j;
for(i=0;i<len;++i)
for(j=0;j<8;++j){
out[i*8+j] = (in[i]>>(7-j))&0x1;
}
}

void bit2Byte(unsigned char *in,unsigned char *out,int len){
int i,j;
unsigned char temp;
for(i=0;i<len;++i){
temp = in[i*8]&0x1;
for(j=1;j<8;++j){
temp = temp<<1;
temp = temp+(in[i*8+j]&0x1);
}
out[i]=temp;
}
}

//change the input 64 bit data to 64 bytes array, use ip table to replace 64 bytes array
void ip_replace(unsigned char * in,unsigned char *out){
int i;
unsigned char temp[64];
memcpy(temp,in,64);
//use ip table to replace 64 bytes(bit) array
for(i=0;i<64;++i){
out[i] = temp[IP_Table[i]-1];
//printf("%x ",out[i]);
}
}

void fp_replace(unsigned char *in,unsigned char* out){
int i;
unsigned char temp[64];

memcpy(temp,in,64);
for(i=0;i<64;++i)
out[i] = temp[IPR_Table[i]-1];
}

void e_expand(unsigned char * in, unsigned char *out){
unsigned char temp[48];
int i;

memcpy(temp,in,48);
for(i=0;i<48;++i)
out[i] = temp[E_Table[i]-1];
}

void s_replace(unsigned char * in,unsigned char *out){
int i,j;
int raw,col;
char temp;
for(i=0,j=0;i<8;++i){
raw = ((in[i*6]<<1)|(in[i*6+5]))&0x3;
col = ((in[i*6+1]<<3)|(in[i*6+2]<<2)|(in[i*6+3]<<1)|(in[i*6+4]))&0xF;
temp = S_Box[i][raw][col]&0xF;
out[j] = (temp>>3)&0x1;
out[j+1] = (temp>>2)&0x1;
out[j+2] = (temp>>1)&0x1;
out[j+3] = (temp)&0x1;
j+=4;
}
}

void p_replace(unsigned char * in,unsigned char * out){
unsigned char temp[32];
int i;

memcpy(temp,in,32);
for(i=0;i<32;++i){
out[i] = temp[P_Table[i]-1];
}
}

void byteXOR(unsigned char *a,unsigned char *b,int len){
int i;
for(i=0;i<len;++i){
a[i] = (a[i]+b[i])&0x1;
}
}

void f_func(unsigned char * in,unsigned char * out,unsigned char * ki){
unsigned char expand_result[48];
unsigned char replace_result[32];

e_expand(in,expand_result);
byteXOR(expand_result,ki,48);
s_replace(expand_result,replace_result);
p_replace(replace_result,replace_result);
memcpy(out,replace_result,32);
}

void pc1_replace(unsigned char * in,unsigned char * out){
int i;
for(i=0;i<56;++i)
out[i]=in[PC1_Table[i]-1];
}

void pc2_replace(unsigned char *in,unsigned char *out){
int i;
for(i=0;i<48;++i)
out[i] = in[PC2_Table[i]-1];
}

void shift_left(unsigned char *in,unsigned char *out,int len){
unsigned char temp[28];
int i,j;

memcpy(temp,in,28);
for(i=len,j=0;i<28;++i)
out[j++]=temp[i];
for(i=0;i<len;++i)
out[j++]=temp[i];
}
//use user's input key to generate 16 subkey
void get_subkey(unsigned char *key){
unsigned char key_temp[64];
unsigned char pc1_result[56];
unsigned char pc2_result[48];
int i;

byte2Bit(key,key_temp,8);
pc1_replace(key_temp,pc1_result);

for(i=0;i<16;++i){
shift_left(pc1_result,pc1_result,LOOP_Table[i]);
shift_left(pc1_result+28,pc1_result+28,LOOP_Table[i]);
pc2_replace(pc1_result,pc2_result);
memcpy(&subkey[i][0],pc2_result,48);
}
}

此外的变种有3-DES…

不过这些都是比较偏密码了,逆向一般不会到魔改3-DES这种

AES

AES 高级加密标准算法,其发展是从1997年开始的,AES其主要是用于替换DES而产生的,该算法具有128位的分组长度,支持192/256位的密钥长度,其算法仅支持128/192/256的密钥长度,分别称作AES-128,AES-192,AES-256。

原理直接看我的AES加密分析 | Matriy’s blog

1
2
3
4
5
6
7
from Crypto.Cipher import AES
from Crypto.Util.number import *
key = long_to_bytes(0xcb8d493521b47a4cc1ae7e62229266ce) #密钥
mi = long_to_bytes(0xbc0aadc0147c5ecce0b140bc9c51d52b46b2b9434de5324bad7fb4b39cdb4b5b) #密文
lun = AES.new(key, mode=AES.MODE_ECB)
flag = lun.decrypt(mi)
print(flag)
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
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "aes.h"

/**
* S盒
*/
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;
int i,j;
for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++) {
pa[j][i] = getIntFromChar(str[k]);
k++;
}
}

/**
* 打印4X4的数组
*/
static void printArray(int a[4][4]) {
int i,j;
for(i = 0; i < 4; i++){
for(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) {
int i;
for(i = 0; i < len; i++)
printf("0x%x ", getIntFromChar(str[i]));
printf("\n");
}

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

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

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

index = step % 4 == 0 ? 0 : step % 4;
for(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];
int i;
int result;
splitIntToArray(num, numArray);
leftLoop4int(numArray, 1);//字循环

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

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

//密钥对应的扩展数组
static int w[44];
/**
* 打印W数组
*/
static void printW() {
int i, j;
for(i = 0, j = 1; i < 44; i++,j++){
printf("w[%d] = 0x%x ", i, w[i]);
if(j % 4 == 0)
printf("\n");
}
printf("\n");
}


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

for(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];
int i,j;
for(i = 0; i < 4; i++) {

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

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

/**
* 字节代换
*/
static void subBytes(int array[4][4]){
int i,j;
for(i = 0; i < 4; i++)
for(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];
int i;
for(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(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];
int i,j;
for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++)
tempArray[i][j] = array[i][j];

for(i = 0; i < 4; i++)
for(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) {
int i,j;
for(i = 0; i < 4; i++)
for(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: 密钥的字符串数组。
*/
void aes(char *p, int plen, char *key){

int keylen = strlen(key);
int pArray[4][4];
int k,i;

if(plen == 0 || plen % 16 != 0) {
printf("明文字符长度必须为16的倍数!\n");
exit(0);
}

if(!checkKeyLen(keylen)) {
printf("密钥字符长度错误!长度必须为16。当前长度为%d\n",keylen);
exit(0);
}

extendKey(key);//扩展密钥

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

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

for(i = 1; i < 10; i++){

subBytes(pArray);//字节代换

shiftRows(pArray);//行移位

mixColumns(pArray);//列混合

addRoundKey(pArray, i);

}

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]) {
int i,j;
for(i = 0; i < 4; i++)
for(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];
int i;
int index;
for(i = 0; i < 4; i++)
temp[i] = array[i];

index = step % 4 == 0 ? 0 : step % 4;
index = 3 - index;
for(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];
int i;
for(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(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];
int i,j;
for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++)
tempArray[i][j] = array[i][j];

for(i = 0; i < 4; i++)
for(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]) {
int i,j;
for(i = 0; i < 4; i++)
for(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,j;
int colOne[4], colTwo[4], colThree[4], colFour[4];
index = i * 4;
splitIntToArray(w[index], colOne);
splitIntToArray(w[index + 1], colTwo);
splitIntToArray(w[index + 2], colThree);
splitIntToArray(w[index + 3], colFour);

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

}

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

int cArray[4][4];
int keylen,k;
keylen = strlen(key);
if(clen == 0 || clen % 16 != 0) {
printf("密文字符长度必须为16的倍数!现在的长度为%d\n",clen);
exit(0);
}

if(!checkKeyLen(keylen)) {
printf("密钥字符长度错误!长度必须为16、24和32。当前长度为%d\n",keylen);
exit(0);
}

extendKey(key);//扩展密钥

for(k = 0; k < clen; k += 16) {
int i;
int wArray[4][4];

convertToIntArray(c + k, cArray);





addRoundKey(cArray, 10);

for(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
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
568
569
570
571
572
573
574
575
576
577
578
#include <stdio.h>
#include <stdint.h>
#include <memory.h>
/****************************************************************************************************************/
typedef enum {
AES_CYPHER_128,
AES_CYPHER_192,
AES_CYPHER_256,
} AES_CYPHER_T;
/****************************************************************************************************************/
/*
* Encryption Rounds
*/
int g_aes_key_bits[] = {
/* AES_CYPHER_128 */ 128,
/* AES_CYPHER_192 */ 192,
/* AES_CYPHER_256 */ 256,
};
int g_aes_rounds[] = {
/* AES_CYPHER_128 */ 10,
/* AES_CYPHER_192 */ 12,
/* AES_CYPHER_256 */ 14,
};
int g_aes_nk[] = {
/* AES_CYPHER_128 */ 4,
/* AES_CYPHER_192 */ 6,
/* AES_CYPHER_256 */ 8,
};
int g_aes_nb[] = {
/* AES_CYPHER_128 */ 4,
/* AES_CYPHER_192 */ 4,
/* AES_CYPHER_256 */ 4,
};
/****************************************************************************************************************/
/*
* aes Rcon:
*
* WARNING: Rcon is designed starting from 1 to 15, not 0 to 14.
* FIPS-197 Page 9: "note that i starts at 1, not 0"
*
* i | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
* -----+------------------------------------------------------------------------------------------
* | [01] [02] [04] [08] [10] [20] [40] [80] [1b] [36] [6c] [d8] [ab] [4d] [9a]
* RCON | [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00]
* | [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00]
* | [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00]
*/
static const uint32_t g_aes_rcon[] = {
0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000,
0x1b000000, 0x36000000, 0x6c000000, 0xd8000000, 0xab000000, 0xed000000, 0x9a000000
};
/****************************************************************************************************************/
/*
* aes sbox and invert-sbox
*/
static const uint8_t g_aes_sbox[256] = {
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
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
};
static const uint8_t g_inv_sbox[256] = {
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
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
};
/****************************************************************************************************************/
uint8_t aes_sub_sbox(uint8_t val)
{
return g_aes_sbox[val];
}
/****************************************************************************************************************/
uint32_t aes_sub_dword(uint32_t val)
{
uint32_t tmp = 0;

tmp |= ((uint32_t)aes_sub_sbox((uint8_t)((val >> 0) & 0xFF))) << 0;
tmp |= ((uint32_t)aes_sub_sbox((uint8_t)((val >> 8) & 0xFF))) << 8;
tmp |= ((uint32_t)aes_sub_sbox((uint8_t)((val >> 16) & 0xFF))) << 16;
tmp |= ((uint32_t)aes_sub_sbox((uint8_t)((val >> 24) & 0xFF))) << 24;

return tmp;
}
/****************************************************************************************************************/
uint32_t aes_rot_dword(uint32_t val)
{
uint32_t tmp = val;

return (val >> 8) | ((tmp & 0xFF) << 24);
}
/****************************************************************************************************************/
uint32_t aes_swap_dword(uint32_t val)
{
return (((val & 0x000000FF) << 24) |
((val & 0x0000FF00) << 8) |
((val & 0x00FF0000) >> 8) |
((val & 0xFF000000) >> 24));
}
/****************************************************************************************************************/
/*
* nr: number of rounds
* nb: number of columns comprising the state, nb = 4 dwords (16 bytes)
* nk: number of 32-bit words comprising cipher key, nk = 4, 6, 8 (KeyLength/(4*8))
*/
void aes_key_expansion(AES_CYPHER_T mode, uint8_t *key, uint8_t *round)
{
uint32_t *w = (uint32_t *)round;
uint32_t t;
int i = 0;

do {
w[i] = *((uint32_t *)&key[i * 4 + 0]);
} while (++i < g_aes_nk[mode]);

do {
if ((i % g_aes_nk[mode]) == 0) {
t = aes_rot_dword(w[i - 1]);
t = aes_sub_dword(t);
t = t ^ aes_swap_dword(g_aes_rcon[i / g_aes_nk[mode] - 1]);
}
else if (g_aes_nk[mode] > 6 && (i % g_aes_nk[mode]) == 4) {
t = aes_sub_dword(w[i - 1]);
}
else {
t = w[i - 1];
}
w[i] = w[i - g_aes_nk[mode]] ^ t;
} while (++i < g_aes_nb[mode] * (g_aes_rounds[mode] + 1));
}
/****************************************************************************************************************/
void aes_add_round_key(AES_CYPHER_T mode, uint8_t *state,
uint8_t *round, int nr)
{
uint32_t *w = (uint32_t *)round;
uint32_t *s = (uint32_t *)state;
int i;

for (i = 0; i < g_aes_nb[mode]; i++) {
s[i] ^= w[nr * g_aes_nb[mode] + i];
}
}
/****************************************************************************************************************/
void aes_sub_bytes(AES_CYPHER_T mode, uint8_t *state)
{
int i, j;

for (i = 0; i < g_aes_nb[mode]; i++) {
for (j = 0; j < 4; j++) {
state[i * 4 + j] = aes_sub_sbox(state[i * 4 + j]);
}
}
}
/****************************************************************************************************************/
void aes_shift_rows(AES_CYPHER_T mode, uint8_t *state)
{
uint8_t *s = (uint8_t *)state;
int i, j, r;

for (i = 1; i < g_aes_nb[mode]; i++) {
for (j = 0; j < i; j++) {
uint8_t tmp = s[i];
for (r = 0; r < g_aes_nb[mode]; r++) {
s[i + r * 4] = s[i + (r + 1) * 4];
}
s[i + (g_aes_nb[mode] - 1) * 4] = tmp;
}
}
}
/****************************************************************************************************************/
uint8_t aes_xtime(uint8_t x)
{
return ((x << 1) ^ (((x >> 7) & 1) * 0x1b));
}
/****************************************************************************************************************/
uint8_t aes_xtimes(uint8_t x, int ts)
{
while (ts-- > 0) {
x = aes_xtime(x);
}

return x;
}
/****************************************************************************************************************/
uint8_t aes_mul(uint8_t x, uint8_t y)
{
/*
* encrypt: y has only 2 bits: can be 1, 2 or 3
* decrypt: y could be any value of 9, b, d, or e
*/

return ((((y >> 0) & 1) * aes_xtimes(x, 0)) ^
(((y >> 1) & 1) * aes_xtimes(x, 1)) ^
(((y >> 2) & 1) * aes_xtimes(x, 2)) ^
(((y >> 3) & 1) * aes_xtimes(x, 3)) ^
(((y >> 4) & 1) * aes_xtimes(x, 4)) ^
(((y >> 5) & 1) * aes_xtimes(x, 5)) ^
(((y >> 6) & 1) * aes_xtimes(x, 6)) ^
(((y >> 7) & 1) * aes_xtimes(x, 7)));
}
/****************************************************************************************************************/
void aes_mix_columns(AES_CYPHER_T mode, uint8_t *state)
{
uint8_t y[16] = { 2, 3, 1, 1, 1, 2, 3, 1, 1, 1, 2, 3, 3, 1, 1, 2 };
uint8_t s[4];
int i, j, r;

for (i = 0; i < g_aes_nb[mode]; i++) {
for (r = 0; r < 4; r++) {
s[r] = 0;
for (j = 0; j < 4; j++) {
s[r] = s[r] ^ aes_mul(state[i * 4 + j], y[r * 4 + j]);
}
}
for (r = 0; r < 4; r++) {
state[i * 4 + r] = s[r];
}
}
}
/****************************************************************************************************************/
int aes_encrypt(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key)
{
uint8_t w[4 * 4 * 15] = { 0 }; /* round key */
uint8_t s[4 * 4] = { 0 }; /* state */

int nr, i, j;

/* key expansion */
aes_key_expansion(mode, key, w);

/* start data cypher loop over input buffer */
for (i = 0; i < len; i += 4 * g_aes_nb[mode]) {

/* init state from user buffer (plaintext) */
for (j = 0; j < 4 * g_aes_nb[mode]; j++)
s[j] = data[i + j];

/* start AES cypher loop over all AES rounds */
for (nr = 0; nr <= g_aes_rounds[mode]; nr++) {

if (nr > 0) {

/* do SubBytes */
aes_sub_bytes(mode, s);

/* do ShiftRows */
aes_shift_rows(mode, s);

if (nr < g_aes_rounds[mode]) {
/* do MixColumns */
aes_mix_columns(mode, s);
}
}

/* do AddRoundKey */
aes_add_round_key(mode, s, w, nr);
}

/* save state (cypher) to user buffer */
for (j = 0; j < 4 * g_aes_nb[mode]; j++)
data[i + j] = s[j];
}

return 0;
}
/****************************************************************************************************************/
int aes_encrypt_ecb(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key)
{
return aes_encrypt(mode, data, len, key);
}
/****************************************************************************************************************/
int aes_encrypt_cbc(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key, uint8_t *iv)
{
uint8_t w[4 * 4 * 15] = { 0 }; /* round key */
uint8_t s[4 * 4] = { 0 }; /* state */
uint8_t v[4 * 4] = { 0 }; /* iv */

int nr, i, j;


/* key expansion */
aes_key_expansion(mode, key, w);

memcpy(v, iv, sizeof(v));

/* start data cypher loop over input buffer */
for (i = 0; i < len; i += 4 * g_aes_nb[mode]) {

/* init state from user buffer (plaintext) */
for (j = 0; j < 4 * g_aes_nb[mode]; j++)
s[j] = data[i + j] ^ v[j];

/* start AES cypher loop over all AES rounds */
for (nr = 0; nr <= g_aes_rounds[mode]; nr++) {

if (nr > 0) {

/* do SubBytes */
aes_sub_bytes(mode, s);

/* do ShiftRows */
aes_shift_rows(mode, s);

if (nr < g_aes_rounds[mode]) {
/* do MixColumns */
aes_mix_columns(mode, s);
}
}

/* do AddRoundKey */
aes_add_round_key(mode, s, w, nr);
}

/* save state (cypher) to user buffer */
for (j = 0; j < 4 * g_aes_nb[mode]; j++)
data[i + j] = v[j] = s[j];
}

return 0;
}
/****************************************************************************************************************/
void inv_shift_rows(AES_CYPHER_T mode, uint8_t *state)
{
uint8_t *s = (uint8_t *)state;
int i, j, r;

for (i = 1; i < g_aes_nb[mode]; i++) {
for (j = 0; j < g_aes_nb[mode] - i; j++) {
uint8_t tmp = s[i];
for (r = 0; r < g_aes_nb[mode]; r++) {
s[i + r * 4] = s[i + (r + 1) * 4];
}
s[i + (g_aes_nb[mode] - 1) * 4] = tmp;
}
}
}
/****************************************************************************************************************/
uint8_t inv_sub_sbox(uint8_t val)
{
return g_inv_sbox[val];
}
/****************************************************************************************************************/
void inv_sub_bytes(AES_CYPHER_T mode, uint8_t *state)
{
int i, j;

for (i = 0; i < g_aes_nb[mode]; i++) {
for (j = 0; j < 4; j++) {
state[i * 4 + j] = inv_sub_sbox(state[i * 4 + j]);
}
}
}
/****************************************************************************************************************/
void inv_mix_columns(AES_CYPHER_T mode, uint8_t *state)
{
uint8_t y[16] = { 0x0e, 0x0b, 0x0d, 0x09, 0x09, 0x0e, 0x0b, 0x0d,
0x0d, 0x09, 0x0e, 0x0b, 0x0b, 0x0d, 0x09, 0x0e };
uint8_t s[4];
int i, j, r;

for (i = 0; i < g_aes_nb[mode]; i++) {
for (r = 0; r < 4; r++) {
s[r] = 0;
for (j = 0; j < 4; j++) {
s[r] = s[r] ^ aes_mul(state[i * 4 + j], y[r * 4 + j]);
}
}
for (r = 0; r < 4; r++) {
state[i * 4 + r] = s[r];
}
}
}
/****************************************************************************************************************/
int aes_decrypt(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key)
{
uint8_t w[4 * 4 * 15] = { 0 }; /* round key */
uint8_t s[4 * 4] = { 0 }; /* state */

int nr, i, j;

/* key expansion */
aes_key_expansion(mode, key, w);

/* start data cypher loop over input buffer */
for (i = 0; i < len; i += 4 * g_aes_nb[mode]) {

/* init state from user buffer (cyphertext) */
for (j = 0; j < 4 * g_aes_nb[mode]; j++)
s[j] = data[i + j];

/* start AES cypher loop over all AES rounds */
for (nr = g_aes_rounds[mode]; nr >= 0; nr--) {

/* do AddRoundKey */
aes_add_round_key(mode, s, w, nr);

if (nr > 0) {

if (nr < g_aes_rounds[mode]) {
/* do MixColumns */
inv_mix_columns(mode, s);
}

/* do ShiftRows */
inv_shift_rows(mode, s);

/* do SubBytes */
inv_sub_bytes(mode, s);
}
}

/* save state (cypher) to user buffer */
for (j = 0; j < 4 * g_aes_nb[mode]; j++)
data[i + j] = s[j];
}

return 0;
}
/****************************************************************************************************************/
int aes_decrypt_ecb(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key)
{
return aes_decrypt(mode, data, len, key);
}
/****************************************************************************************************************/
int aes_decrypt_cbc(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key, uint8_t *iv)
{
uint8_t w[4 * 4 * 15] = { 0 }; /* round key */
uint8_t s[4 * 4] = { 0 }; /* state */
uint8_t v[4 * 4] = { 0 }; /* iv */


int nr, i, j;

/* key expansion */
aes_key_expansion(mode, key, w);

memcpy(v, iv, sizeof(v));

/* start data cypher loop over input buffer */
for (i = 0; i < len; i += 4 * g_aes_nb[mode]) {


/* init state from user buffer (cyphertext) */
for (j = 0; j < 4 * g_aes_nb[mode]; j++)
s[j] = data[i + j];

/* start AES cypher loop over all AES rounds */
for (nr = g_aes_rounds[mode]; nr >= 0; nr--) {

/* do AddRoundKey */
aes_add_round_key(mode, s, w, nr);

if (nr > 0) {

if (nr < g_aes_rounds[mode]) {
/* do MixColumns */
inv_mix_columns(mode, s);
}

/* do ShiftRows */
inv_shift_rows(mode, s);

/* do SubBytes */
inv_sub_bytes(mode, s);
}
}

/* save state (cypher) to user buffer */
for (j = 0; j < 4 * g_aes_nb[mode]; j++) {
uint8_t p = s[j] ^ v[j];
v[j] = data[i + j];
data[i + j] = p;
}
}

return 0;
}
/****************************************************************************************************************/
void aes_cypher_128_test()
{
#if 1
uint8_t buf[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
uint8_t key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
#else
uint8_t buf[] = { 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d,
0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34 };
uint8_t key[] = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
#endif

aes_encrypt(AES_CYPHER_128, buf, sizeof(buf), key);

aes_decrypt(AES_CYPHER_128, buf, sizeof(buf), key);
}
/****************************************************************************************************************/
void aes_cypher_192_test()
{
uint8_t buf[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
uint8_t key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };

aes_encrypt(AES_CYPHER_192, buf, sizeof(buf), key);

aes_decrypt(AES_CYPHER_192, buf, sizeof(buf), key);
}
/****************************************************************************************************************/
void aes_cypher_256_test()
{
uint8_t buf[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
uint8_t key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f };

aes_encrypt(AES_CYPHER_256, buf, sizeof(buf), key);

aes_decrypt(AES_CYPHER_256, buf, sizeof(buf), key);
}
/****************************************************************************************************************/
int main()
{
//数据
uint8_t buf[] = { 78, 204, 144, 217, 57, 62, 169, 79, 165, 219, 206, 216, 180, 137, 206, 138 };
//密钥
uint8_t key[] = { 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112 };
//向量
//uint8_t iv[] = {};
switch (sizeof(key))
{
//ECB
case 16:aes_decrypt(AES_CYPHER_128, buf, sizeof(buf), key); break;
case 24:aes_decrypt(AES_CYPHER_192, buf, sizeof(buf), key); break;
case 32:aes_decrypt(AES_CYPHER_256, buf, sizeof(buf), key); break;
//CBC
/*
case 16:aes_decrypt_cbc(AES_CYPHER_128, buf, sizeof(buf), key, iv); break;
case 24:aes_decrypt_cbc(AES_CYPHER_192, buf, sizeof(buf), key, iv); break;
case 32:aes_decrypt_cbc(AES_CYPHER_256, buf, sizeof(buf), key, iv); break;
*/
}
for (int i = 0; i < sizeof(buf); i++)
{
printf("%c", buf[i] & 0xFF);
}
printf("\\n");
return 0;
}

最主要时识别AES盒和AES的S盒逆

SM4

直接看我的SM4加密分析 | Matriy’s blog

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
# 魔改S盒
S_BOX = [
0xD1, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x5, 0x2B, 0x67, 0x9A,
0x76, 0x2A, 0xBE, 0x4, 0xC3, 0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x6, 0x99, 0x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF,
0x98, 0x7A, 0x33, 0x54, 0xB, 0x43, 0xED, 0xCF, 0xAC, 0x62, 0xE4, 0xB3, 0x17, 0xA9, 0x1C, 0x8, 0xE8, 0x95, 0x80,
0xDF, 0x94, 0xFA, 0x75, 0x8F, 0x3F, 0xA6, 0x47, 0x7, 0xA7, 0x4F, 0xF3, 0x73, 0x71, 0xBA, 0x83, 0x59, 0x3C, 0x19,
0xE6, 0x85, 0xD6, 0xA8, 0x68, 0x6B, 0x81, 0xB2, 0xFC, 0x64, 0xDA, 0x8B, 0xF8, 0xEB, 0xF, 0x4B, 0x70, 0x56, 0x9D,
0x35, 0x1E, 0x24, 0xE, 0x78, 0x63, 0x58, 0x9F, 0xA2, 0x25, 0x22, 0x7C, 0x3B, 0x1, 0x21, 0xC9, 0x87, 0xD4, 0x0, 0x46,
0x57, 0x5E, 0xD3, 0x27, 0x52, 0x4C, 0x36, 0x2, 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,
0xD, 0x53, 0x4E, 0x6F, 0xD5, 0xDB, 0x37, 0x45, 0xDE, 0xFD, 0x8E, 0x2F, 0x3, 0xFF, 0x6A, 0x72, 0x6D, 0x6C, 0x5B,
0x51, 0x8D, 0x1B, 0xAF, 0x92, 0xBB, 0xDD, 0xBC, 0x7F, 0x11, 0xD9, 0x5C, 0x41, 0x1F, 0x10, 0x5A, 0xD8, 0xA, 0xC1,
0x31, 0x88, 0xA5, 0xCD, 0x7B, 0xBD, 0x2D, 0x74, 0xD0, 0x12, 0xB8, 0xE5, 0xB4, 0xB0, 0x89, 0x69, 0x97, 0x4A, 0xC,
0x96, 0x77, 0x7E, 0x65, 0xB9, 0xF1, 0x9, 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 wd_to_byte(wd, bys):
bys.extend([(wd >> i) & 0xff for i in range(24, -1, -8)])


def bys_to_wd(bys):
ret = 0
for i in range(4):
bits = 24 - i * 8
ret |= (bys[i] << bits)
return ret

def s_box(wd):
ret = []
for i in range(0, 4):
byte = (wd >> (24 - i * 8)) & 0xff
row = byte >> 4
col = byte & 0x0f
index = (row * 16 + col)
ret.append(S_BOX[index])
return bys_to_wd(ret)


def rotate_left(wd, bit):
return (wd << bit & 0xffffffff) | (wd >> (32 - bit))


def Linear_transformation(wd):
return wd ^ rotate_left(wd, 2) ^ rotate_left(wd, 10) ^ rotate_left(wd, 18) ^ rotate_left(wd, 24)


def Tx(k1, k2, k3, ck):
xor = k1 ^ k2 ^ k3 ^ ck
t = s_box(xor)
return t ^ rotate_left(t, 13) ^ rotate_left(t, 23)


def T(x1, x2, x3, rk):
t = x1 ^ x2 ^ x3 ^ rk
t = s_box(t)
return t ^ rotate_left(t, 2) ^ rotate_left(t, 10) ^ rotate_left(t, 18) ^ rotate_left(t, 24)

def key_extend(main_key):
MK = [(main_key >> (128 - (i + 1) * 32)) & 0xffffffff for i in range(4)]
keys = [FK[i] ^ MK[i] for i in range(4)]
RK = []
for i in range(32):
t = Tx(keys[i + 1], keys[i + 2], keys[i + 3], CK[i])
k = keys[i] ^ t
keys.append(k)
RK.append(k)
return RK


def R(x0, x1, x2, x3):
x0 &= 0xffffffff
x1 &= 0xffffffff
x2 &= 0xffffffff
x3 &= 0xffffffff
s = f"{x3:08x}{x2:08x}{x1:08x}{x0:08x}"
return s


def encode(plaintext, rk):
X = [plaintext >> (128 - (i + 1) * 32) & 0xffffffff for i in range(4)]
for i in range(32):
t = T(X[1], X[2], X[3], rk[i])
c = (t ^ X[0])
X = X[1:] + [c]
ciphertext = R(X[0], X[1], X[2], X[3])
return ciphertext


def decode(ciphertext, rk):
ciphertext = int(ciphertext, 16)
X = [ciphertext >> (128 - (i + 1) * 32) & 0xffffffff for i in range(4)]
for i in range(32):
t = T(X[1], X[2], X[3], rk[31 - i])
c = (t ^ X[0])
X = X[1:] + [c]
m = R(X[0], X[1], X[2], X[3])
return m


if __name__ == '__main__':
key_str = 'NCTF24nctfNCTF24'
main_key = int.from_bytes(key_str.encode('utf-8'), byteorder='big')
rk = key_extend(main_key)

enc = bytes([
0xFB, 0x97, 0x3C, 0x3B, 0xF1, 0x99, 0x12, 0xDF, 0x13, 0x30,
0xF7, 0xD8, 0x7F, 0xEB, 0xA0, 0x6C, 0x14, 0x5B, 0xA6, 0x2A,
0xA8, 0x05, 0xA5, 0xF3, 0x76, 0xBE, 0xC9, 0x01, 0xF9, 0x36,
0x7B, 0x46
])

# Split ciphertext into two 16-byte blocks
block1 = enc[:16].hex()
block2 = enc[16:].hex()

# Decrypt each block
part1 = decode(block1, rk)
part2 = decode(block2, rk)

# Combine and decode to get flag
combined = bytes.fromhex(part1 + part2).decode('utf-8', errors='replace')
print(f"NCTF{{{combined}}}")

1
2
3
4
5
from gmssl.sm4 import CryptSM4, SM4_DECRYPT

sm4_dec = CryptSM4()
sm4_dec.set_key(b'Pyu0Z8#bC5vqUFgt', SM4_DECRYPT)
print(sm4_dec.crypt_ecb(bytes.fromhex('6A61EF281A7473D6B1B431D0351F7E2242CFB9D6EC4E01EF656D6CF520F142821C7061EB843D5ABE378B394C4DC1298B')))

识别S盒(可魔改),和FK CK

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

#ifndef GET_ULONG_BE
#define GET_ULONG_BE(n,b,i) \\
{ \\
(n) = ( (unsigned long) (b)[(i) ] << 24 ) \\
| ( (unsigned long) (b)[(i) + 1] << 16 ) \\
| ( (unsigned long) (b)[(i) + 2] << 8 ) \\
| ( (unsigned long) (b)[(i) + 3] ); \\
}
#endif

#ifndef PUT_ULONG_BE
#define PUT_ULONG_BE(n,b,i) \\
{ \\
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \\
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \\
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \\
(b)[(i) + 3] = (unsigned char) ( (n) ); \\
}
#endif

#define SHL(x,n) (((x) & 0xFFFFFFFF) << n)
#define ROTL(x,n) (SHL((x),n) | ((x) >> (32 - n)))

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

static const unsigned char SboxTable[16][16] = {
{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}
};

static const unsigned long FK[4] = {0xa3b1bac6,0x56aa3350,0x677d9197,0xb27022dc};

static const unsigned long CK[32] = {
0x00070e15,0x1c232a31,0x383f464d,0x545b6269,
0x70777e85,0x8c939aa1,0xa8afb6bd,0xc4cbd2d9,
0xe0e7eef5,0xfc030a11,0x181f262d,0x343b4249,
0x50575e65,0x6c737a81,0x888f969d,0xa4abb2b9,
0xc0c7ced5,0xdce3eaf1,0xf8ff060d,0x141b2229,
0x30373e45,0x4c535a61,0x686f767d,0x848b9299,
0xa0a7aeb5,0xbcc3cad1,0xd8dfe6ed,0xf4fb0209,
0x10171e25,0x2c333a41,0x484f565d,0x646b7279
};

static unsigned char sm4Sbox(unsigned char inch) {
unsigned char *pTable = (unsigned char *)SboxTable;
unsigned char retVal = (unsigned char)(pTable[inch]);
return retVal;
}

static unsigned long sm4Lt(unsigned long ka) {
unsigned long bb = 0;
unsigned long c = 0;
unsigned char a[4];
unsigned char b[4];
PUT_ULONG_BE(ka,a,0)
b[0] = sm4Sbox(a[0]);
b[1] = sm4Sbox(a[1]);
b[2] = sm4Sbox(a[2]);
b[3] = sm4Sbox(a[3]);
GET_ULONG_BE(bb,b,0)
c =bb^(ROTL(bb, 2))^(ROTL(bb, 10))^(ROTL(bb, 18))^(ROTL(bb, 24));
return c;
}

static unsigned long sm4F(unsigned long x0, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long rk) {
return (x0^sm4Lt(x1^x2^x3^rk));
}



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

memset(ulbuf, 0, sizeof(ulbuf));
GET_ULONG_BE( ulbuf[0], input, 0 )
GET_ULONG_BE( ulbuf[1], input, 4 )
GET_ULONG_BE( ulbuf[2], input, 8 )
GET_ULONG_BE( ulbuf[3], input, 12 )
while(i<32) {
ulbuf[i+4] = sm4F(ulbuf[i], ulbuf[i+1], ulbuf[i+2], ulbuf[i+3], sk[i]);
i++;
}
PUT_ULONG_BE(ulbuf[35],output,0);
PUT_ULONG_BE(ulbuf[34],output,4);
PUT_ULONG_BE(ulbuf[33],output,8);
PUT_ULONG_BE(ulbuf[32],output,12);
}

static unsigned long sm4CalciRK(unsigned long ka) {
unsigned long bb = 0;
unsigned long rk = 0;
unsigned char a[4];
unsigned char b[4];
PUT_ULONG_BE(ka,a,0)
b[0] = sm4Sbox(a[0]);
b[1] = sm4Sbox(a[1]);
b[2] = sm4Sbox(a[2]);
b[3] = sm4Sbox(a[3]);
GET_ULONG_BE(bb,b,0)
rk = bb^(ROTL(bb, 13))^(ROTL(bb, 23));
return rk;
}

static void sm4_setkey( unsigned long sk[32], unsigned char key[16] ) {
unsigned long MK[4];
unsigned long k[36];
unsigned long i = 0;

GET_ULONG_BE( MK[0], key, 0 );
GET_ULONG_BE( MK[1], key, 4 );
GET_ULONG_BE( MK[2], key, 8 );
GET_ULONG_BE( MK[3], key, 12 );
k[0] = MK[0]^FK[0];
k[1] = MK[1]^FK[1];
k[2] = MK[2]^FK[2];
k[3] = MK[3]^FK[3];
for(; i<32; i++) {
k[i+4] = k[i] ^ (sm4CalciRK(k[i+1]^k[i+2]^k[i+3]^CK[i]));
sk[i] = k[i+4];
}
}

int main() {
unsigned char key[16] = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
unsigned char input[16] = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
unsigned char output[16];
unsigned long sk[32];
unsigned long i;

sm4_setkey(sk,key);

sm4_one_round(sk, input,output);

for(i=0; i<16; i++)
printf("%02x ", output[i]);
printf("\\n");

return 0;
}

其它

Base64

换表base64

1
2
3
4
5
6
7
8
9
import base64

def base64decode(s):
old_table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
new_table = 'AbcdefghijklmnopqrstuvwxyzaBCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/'
s = s.translate(str.maketrans(new_table, old_table))
return base64.b64decode(s)

print(base64decode('Exv3nhr5BNW0axn3aNz/DNv9C3q0wxj/Exe='))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
table = [0x4f,0x4c,0x4d,0x4a,0x4b,0x48,0x49,0x46,0x47,0x44,0x45,0x42,0x43,0x40,0x41,0x5e,0x5f,0x5c,0x5d,0x5a,0x5b,0x58,0x59,0x56,0x57,0x54,0x6f,0x6c,0x6d,0x6a,0x6b,0x68,0x69,0x66,0x67,0x64,0x65,0x62,0x63,0x60,0x61,0x7e,0x7f,0x7c,0x7d,0x7a,0x7b,0x78,0x79,0x76,0x77,0x74,0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39,0x36,0x37,0x25,0x21]

enc = "lY7bW=\\ck?eyjX7]TZ\\}CVbh\\tOyTH6>jH7XmFifG]H7"

rev = {chr(ch):i for i,ch in enumerate(table)}
enc_bytes = bytearray()

mid = []
for i in enc:
mid.append(rev[i])
if len(mid) == 4:
b1,b2,b3,b4 = mid
enc_bytes.append(((b1 << 2) | (b2 >> 4)))
enc_bytes.append(((b2 & 0xf) << 4 | (b3 >> 2)))
enc_bytes.append(((b3 & 0x3) << 6 | b4))
mid = []

print(enc_bytes.decode('latin1'))

RSA

RC4&RSA | Matriy’s blog

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import libnum
from Crypto.Util.number import long_to_bytes

q = 282164587459512124844245113950593348271
p = 366669102002966856876605669837014229419
e = 65537
c = 0xad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35
n = 103461035900816914121390101299049044413950405173712170434161686539878160984549

# invmod(a, n) - 求a对于n的模逆,逆向加密过程中计算ψ(n)=(p-1)(q-1),对ψ(n)保密,也就是对应根据e*d=1 mod ψ(n),求出d
d = libnum.invmod(e, (p - 1) * (q - 1))
m = pow(c, d, n)
string = long_to_bytes(m) # 获取m明文,要转成字符串
# print(ex(m)[2:].decode('hex'))
print(string)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import gmpy2
import rsa

e = 65537
n = 86934482296048119190666062003494800588905656017203025617216654058378322103517
p = 285960468890451637935629440372639283459
q = 304008741604601924494328155975272418463

phin = (q - 1) * (p - 1)

d = gmpy2.invert(e, phin)

key = rsa.PrivateKey(n, e, int(d), p, q)

# 读取密文
with open("./flag.txt", "rb") as f:
ciphertext = f.read()

# 解密密文
decrypted_message = rsa.decrypt(ciphertext, key)
print(decrypted_message.decode())

PRESENT

遇到的一题:

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
Sbox = [12, 5, 6, 11, 9, 0, 10, 13, 3, 14, 15, 8, 4, 7, 1, 2]
Sbox_inv = [Sbox.index(x) for x in range(16)]

PBox = [
0, 16, 32, 48, 1, 17, 33, 49, 2, 18, 34, 50, 3, 19, 35, 51,
4, 20, 36, 52, 5, 21, 37, 53, 6, 22, 38, 54, 7, 23, 39, 55,
8, 24, 40, 56, 9, 25, 41, 57, 10, 26, 42, 58, 11, 27, 43, 59,
12, 28, 44, 60, 13, 29, 45, 61, 14, 30, 46, 62, 15, 31, 47, 63
]
PBox_inv = [PBox.index(x) for x in range(64)]

def addRoundKey(state, roundkey):
return state ^ roundkey

def generateRoundkeys80(key, rounds):
roundkeys = []
for i in range(1, rounds + 1):
roundkeys.append(key >> 16)
key = ((key & 524287) << 61) + (key >> 19)
key = (Sbox[key >> 76] << 76) + (key & ((2 ** 76) - 1))
key ^= (i << 15) ^ (key >> 19)
return roundkeys


def inv_sBoxLayer(state):
output = 0
for i in range(16):
output += Sbox_inv[(state >> (i * 4)) & 15] << (i * 4)
return output


def inv_pLayer(state):
output = 0
for i in range(64):
output += ((state >> i) & 1) << PBox_inv[i]
return output


def number2string(n):
chars = []
for i in range(8):
chars.append(chr((n >> (i * 8)) & 0xFF))
return ''.join(chars)


def decrypt(ciphers):
rounds = 32
roundkeys = generateRoundkeys80(85354531916197809168417, rounds)
out = []

for cipher in ciphers:
state = cipher

for i in range(rounds - 1, 0, -1):
state = addRoundKey(state, roundkeys[i])
state = inv_pLayer(state)
state = inv_sBoxLayer(state)

block = addRoundKey(state, roundkeys[0])
out.append(number2string(block))

return ''.join(out)


cmps = [120617461261311902, 16357837616839286114, 312508749794633008, 1843701600916795272]

decrypted_flag = decrypt(cmps)
print(decrypted_flag)
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
SBOX = [12,5,6,11,9,0,10,13,3,14,15,8,4,7,1,2]

PBOX = [
0,16,32,48, 1,17,33,49, 2,18,34,50, 3,19,35,51,
4,20,36,52, 5,21,37,53, 6,22,38,54, 7,23,39,55,
8,24,40,56, 9,25,41,57,10,26,42,58,11,27,43,59,
12,28,44,60,13,29,45,61,14,30,46,62,15,31,47,63
]

# 逆表
SBOX_INV = [0]*16
for i, v in enumerate(SBOX):
SBOX_INV[v] = i

PBOX_INV = [0]*64
for i, p in enumerate(PBOX):
PBOX_INV[p] = i

def sbox_layer(x: int) -> int:
out = 0
for i in range(16): # 16 个 4bit
out |= (SBOX[(x >> (4*i)) & 0xF] << (4*i))
return out

def sbox_inv_layer(x: int) -> int:
out = 0
for i in range(16):
out |= (SBOX_INV[(x >> (4*i)) & 0xF] << (4*i))
return out

def p_layer(x: int) -> int:
out = 0
for i in range(64):
out |= ((x >> i) & 1) << PBOX[i]
return out

def p_inv_layer(x: int) -> int:
out = 0
for i in range(64):
out |= ((x >> i) & 1) << PBOX_INV[i]
return out

def add_round_key(state: int, rk: int) -> int:
return state ^ rk

def generateRoundkeys80(key: int, rounds: int):
# 每轮先取 top64 作为 roundkey,再做旋转/代换/异或注入
roundkeys = []
for i in range(1, rounds + 1):
roundkeys.append(key >> 16) # top 64 bits
key = ((key & 524287) << 61) + (key >> 19) # 524287 = 2^19-1
top_nib = SBOX[(key >> 76) & 0xF]
key = (top_nib << 76) + (key & ((1 << 76) - 1))
key ^= ((i << 15) ^ (key >> 19))
return roundkeys

def decrypt_block_le(cipher: int, roundkeys):
# 最后一轮仅 ARK,所以先去掉最后一轮 ARK
state = add_round_key(cipher, roundkeys[-1])
# 反向:P^-1 -> S^-1 -> ARK
for i in range(len(roundkeys) - 2, -1, -1):
state = p_inv_layer(state)
state = sbox_inv_layer(state)
state = add_round_key(state, roundkeys[i])
# 题目里 string2number 是小端拼 64bit,这里按小端还原回字节
return state.to_bytes(8, 'little')

def main():
ROUNDS = 32
FIXED_KEY = 85354531916197809168417 # 反汇编里 encrypt 使用的固定 80-bit 密钥

cmps = [
120617461261311902,
16357837616839286114,
312508749794633008,
1843701600916795272,
]

roundkeys = generateRoundkeys80(FIXED_KEY, ROUNDS)

# 逐块解密并拼接
blocks = [decrypt_block_le(c, roundkeys) for c in cmps]
flag_bytes = b''.join(blocks)

try:
flag = flag_bytes.decode('utf-8')
except UnicodeDecodeError:
flag = flag_bytes.hex()

print(flag)

if __name__ == "__main__":
main()

还有一些如维吉尼亚的….偏misc一般逆向里不会出现,这里不再赘述