tea加解密学习

开始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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <stdio.h>
#include <stdint.h>

// 加密函数
void encrypt(uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1], sum = 0, i;
uint32_t delta = 0x9e3779b9;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
for (i = 0; i < 32; i++) {
sum += delta;
v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
}
v[0] = v0;
v[1] = v1;
}

int main() {
// 明文分组(小端序十六进制)
uint32_t plaintext[8] = {
0x67616C66, 0x3332317B, 0x37363534, 0x30303938,
0x34333231, 0x38373635, 0x32313039, 0x7D353433
};

// 密钥(小端序十六进制)
uint32_t key[4] = {
0x34333231, 0x38373635, 0x32313039, 0x36353433
};

// 打印原始明文
printf("原始明文(小端序十六进制):\n");
for (int i = 0; i < 8; i++) {
printf("0x%08X ", plaintext[i]);
if (i % 2 == 1) printf("\n");
}

// 对每个64位分组进行加密
for (int i = 0; i < 8; i += 2) {
uint32_t v[2] = { plaintext[i], plaintext[i + 1] };
encrypt(v, key);
plaintext[i] = v[0];
plaintext[i + 1] = v[1];
}

// 打印加密后的密文
printf("\n加密后的密文(小端序十六进制):\n");
for (int i = 0; i < 8; i++) {
printf("0x%08X ", plaintext[i]);
if (i % 2 == 1) printf("\n");
}

return 0;
}

python和c与语言在tea加密的时候会发现有时候会不一样,其中有可能是小端序储存的问题。

解密

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

void decrypt(uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1], sum = 0xC6EF3720, i;
uint32_t delta = 0x9e3779b9;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
for (i = 0; i < 32; i++) {
v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
sum -= delta;
}
v[0] = v0;
v[1] = v1;
}

int main() {
uint32_t k[4] = {0x34333231, 0x38373635, 0x32313039, 0x36353433}; // 密钥
uint32_t blocks[4][2] = {
{0x4438A9E2, 0x39D00322}, // 密文块1
{0x55564858, 0x0414AC05}, // 密文块2
{0x4D66EF71, 0x5ABD1754}, // 密文块3
{0x94554B4A, 0x8F3245C0} // 密文块4
};

for (int i = 0; i < 4; i++) {
uint32_t v[2] = {blocks[i][0], blocks[i][1]};
decrypt(v, k);
// 将解密后的uint32_t转换为小端序字节序列并输出
uint8_t *bytes = (uint8_t *)v;
for (int j = 0; j < 8; j++) {
printf("%c", bytes[j]);
}
}
printf("\n");
return 0;
}

介绍

TEA(Tiny Encryption Algorithm)是一种分组密码算法,由David Wheeler和Roger Needham于1994年提出。它采用64位数据块和128位

密钥,具有简单、高效的特点。算法使用32轮循环的Feistel结构,每轮操作包括移位、异或和加法

最常魔改点

delta = 0x9e3779b9(标准) 这里经常会被换成别的数据

在反汇编中x-=0x61c88647和x+=0x9e3779b9,这两个值是等价的。

进行32轮循环,每轮执行以下操作:

1
2
3
sum += delta;
v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);

解密的换就反过来进行32次就可以了

1
2
3
v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
sum -= delta;

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

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

int main() {
// 原始明文(小端序十六进制)
uint32_t plaintext[8] = {
0x67616C66, 0x3332317B, 0x37363534, 0x30303938,
0x34333231, 0x38373635, 0x32313039, 0x7D353433
};

// 原始密钥(小端序十六进制)
uint32_t const key[4] = {
0x34333231, 0x38373635, 0x32313039, 0x36353433
};

unsigned int num_rounds = 32;

printf("原始明文:\n");
for (int i = 0; i < 8; i++) {
printf("%08X ", plaintext[i]);
if (i % 2 == 1) printf("\n");
}

// 对每个64位块进行加密
for (int i = 0; i < 8; i += 2) {
uint32_t block[2] = { plaintext[i], plaintext[i + 1] };
encipher(num_rounds, block, key);
plaintext[i] = block[0];
plaintext[i + 1] = block[1];
}

printf("\n加密后的密文:\n");
for (int i = 0; i < 8; i++) {
printf("%08X ", plaintext[i]);
if (i % 2 == 1) printf("\n");
}

return 0;
}

解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <stdio.h>
#include <stdint.h>

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

int main() {
uint32_t const key[4] = { 0x34333231, 0x38373635, 0x32313039, 0x36353433 }; // 密钥
unsigned int r = 32; // 轮数

// 密文分组
uint32_t ciphertext[4][2] = {
{0x37DB3CE9, 0x6C07F159},
{0xE1893135, 0x57978EA8},
{0xB159F7E6, 0x439F8389},
{0x988499C3, 0x9765BBF9}
};

printf("解密后的数据:\n");
for (int i = 0; i < 4; i++) {
uint32_t v[2] = { ciphertext[i][0], ciphertext[i][1] };
decipher(r, v, key);
printf("组 %d: 0x%08X 0x%08X\n", i + 1, v[0], v[1]);

// 将解密后的32位整数转换为字节序列(小端序)以显示为字符串
unsigned char* bytes = (unsigned char*)v;
printf(" 作为字节序列: ");
for (int j = 0; j < 8; j++) {
printf("%02X ", bytes[j]);
}
printf("\n 可能作为字符串: ");
for (int j = 0; j < 8; j++) {
if (bytes[j] >= 32 && bytes[j] <= 126) {
printf("%c", bytes[j]);
}
else {
printf(".");
}
}
printf("\n\n");
}

return 0;
}

介绍

XTEA(eXtended TEA)是 TEA 算法的改进版,由 David Wheeler 和 Roger Needham 于 1997 年提出,主要修复了 TEA 的相关密钥攻击漏洞,以 64 位为数据块、128 位为密钥,通过 32 轮包含加 / 减、循环移位和异或的操作实现加密解密,因轻量易实现、对资源需求低,常用于嵌入式设备等场景。

最常魔改点

delta是魔数0x9E3779B9 这个数据经常被换。

加密核心

1
2
3
4
5
6
7
8
9
10
11
void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0 = v[0], v1 = v[1], sum = 0, delta = 0x9E3779B9; // 初始化
for (i = 0; i < num_rounds; i++) {
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]); // 对左半块操作
sum += delta; // 更新“轮常量”
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]); // 对右半块操作
}
v[0] = v0; // 加密后的左半块
v[1] = v1; // 加密后的右半块
}

解密的换就反过来进行

1
2
3
4
5
6
7
8
9
10
11
void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0 = v[0], v1 = v[1], delta = 0x9E3779B9, sum = delta * num_rounds; // 初始化sum为最终值
for (i = 0; i < num_rounds; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]); // 逆向操作右半块
sum -= delta; // 逆向更新sum
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]); // 逆向操作左半块
}
v[0] = v0;
v[1] = v1;
}

xxtea

加密

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

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

void btea(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 = 0;
z = v[n - 1];
do {
sum += DELTA;
e = (sum >> 2) & 3;
for (p = 0; p < n - 1; p++) {
y = v[p + 1];
z = v[p] += MX;
}
y = v[0];
z = v[n - 1] += MX;
} while (--rounds);
}
}

int main() {
uint32_t v[8] = {
0x67616C66, 0x3332317B, 0x37363534, 0x30303938,
0x34333231, 0x38373635, 0x32313039, 0x7D353433
};
uint32_t const k[4] = { 0x34333231, 0x38373635, 0x32313039, 0x36353433 };
int n = 8;

printf("原始明文(小端序十六进制):\n");
for (int i = 0; i < n; i++) {
printf("0x%08X ", v[i]);
}
printf("\n");

btea(v, n, k);

printf("加密后的数据(十六进制):\n");
for (int i = 0; i < n; i++) {
printf("0x%08X ", v[i]);
}
printf("\n");

return 0;
}

解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <stdio.h>
#include <stdint.h>

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

void btea(uint32_t* v, int n, uint32_t const key[4]) {
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1) { /* Coding Part */
rounds = 6 + 52 / n;
sum = 0;
z = v[n - 1];
do {
sum += DELTA;
e = (sum >> 2) & 3;
for (p = 0; p < n - 1; p++) {
y = v[p + 1];
z = v[p] += MX;
}
y = v[0];
z = v[n - 1] += MX;
} while (--rounds);
}
else if (n < -1) { /* Decoding Part */
n = -n;
rounds = 6 + 52 / n;
sum = rounds * DELTA;
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 -= DELTA;
} while (--rounds);
}
}

int main() {
// 密文数据 (小端序十六进制)
uint32_t v[8] = {
0x3E95DFCB, 0x608F99DA, 0x40ABC551, 0x941490C5,
0x7985C1B9, 0x20FC9B0A, 0x23C095EB, 0x62EFB4EE
};

// 密钥 (小端序十六进制)
uint32_t const k[4] = {
0x34333231, 0x38373635, 0x32313039, 0x36353433
};

int n = 8; // 密文长度为8个32位无符号整数

printf("密文数据:\n");
for (int i = 0; i < n; i++) {
printf("0x%08X ", v[i]);
if ((i + 1) % 4 == 0) printf("\n");
}

// 解密
btea(v, -n, k);

printf("\n解密后的数据:\n");
for (int i = 0; i < n; i++) {
printf("0x%08X ", v[i]);
if ((i + 1) % 4 == 0) printf("\n");
}

// 将解密后的数据解释为字符
printf("\n解密后的字符串:\n");
unsigned char* bytes = (unsigned char*)v;
for (int i = 0; i < n * 4; i++) {
if (bytes[i] >= 32 && bytes[i] <= 126) {
printf("%c", bytes[i]);
}
else {
printf("\\x%02X", bytes[i]);
}
}
printf("\n");

return 0;
}

介绍

XXTEA(Corrected Block TEA)是 XTEA 算法的优化升级版,专为解决 XTEA 对数据块长度的限制而生,能以 32 位无符号整数为基本单位,对任意长度的数据进行加密解密;它延续了轻量级特性,仅依赖基础算术与位运算,代码量少、资源占用低,同时优化了轮函数设计,增强抗攻击能力,广泛用于嵌入式设备、物联网终端、小型通信协议等对算力和存储要求严苛的场景。

最常魔改点

define DELTA 0x9e3779b9 这个数据经常被换。

加密原理

  • 输入:明文数组 v(8个32位整数)、数组长度 n=8、密钥 k(4个32位整数)。
  • 关键步骤
    • 计算轮数 rounds = 6 + 52 / n(确保充分混淆)。
    • 初始化 sum = 0z = v[n-1]
    • 多轮循环(每轮 sum += DELTA(0x9e3779b9)):
      • 计算 e = (sum >> 2) & 3(动态选择密钥索引)。
      • 遍历数组(除最后一个元素),使用 MX 函数更新每个 v[p]v[p] += MXMX 混合 y(下一个元素)、z(前一个元素)、密钥和 sum)。
      • 更新最后一个元素 v[n-1] += MX(使用 y = v[0])。
  • 输出:密文数组 v(原始明文被加密)。

解密原理

  • 输入:密文数组 v、负长度 -n(触发解密模式)、相同密钥 k
  • 关键步骤
    • n 的绝对值,计算相同轮数 rounds
    • 初始化 sum = rounds * DELTA(加密最终值),y = v[0]
    • 多轮循环(每轮 sum -= DELTA):
      • 计算 e(同加密)。
      • 反向遍历数组(从最后一个元素到第二个),使用 v[p] -= MX(逆操作,恢复加密前值)。
      • 更新第一个元素 v[0] -= MX
  • 输出:明文数组 v(密文被解密)。