Tea

Tea

HuAmI Lv3

Tea

Tiny Encryption Algorithm)|分组加密算法

Basic Elements:

参数 说明
明文 64 比特(分为两个 32 位部分)
密钥 128 比特(分为 4 个 32 位部分)
轮数 64 次(32 轮循环,每轮包含两个半轮操作)
常量 delta = 0x9E3779B9 (即黄金分割常数的整数近似)

首先,我们逐一对各个element进行分析解释:

明文:

明文长度不一定是64bit
明文不是 64 位(不是 8 字节)怎么办?——必须填充(padding)到 8 字节的倍数
填充完之后再做处理。

分组:

明文填充(padding)到 8 字节的倍数需要分组。
example:
“helloctfgaoshou”,此字符串按照utf-8编码,标准的ASCII字符串的长度是15,很显然需要填充一个字符来达到8字节整数倍达到16字节。

此处按PKCS7Padding模式,按块所缺个数填充值。
例如:填充至符合块大小的整数倍,填充值为填充数量数,需要填充7个字节,就全部填07。

原始:FF FF FF FF FF FF FF FF FF
填充:FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07

填充完之后进行分组,按每8字节为一个块(block)

Block 0: 前 8 字节
Block 1: 后 8 字节

接着每个块(即每8个字节):

每 8 字节被分成:
v0 = 前 4 字节(32bit) // 1字节==8位(bit)
v1 = 后 4 字节(32bit)

这样分组工作就做好了!

再之我们就需要进行加密工作了,但在这之前我们需要选取一个合适的key。

选取key:

key的选取不是随机的,当然也是随机的。

为什么这么说呢,前者是说key的选取要有一定的要求:

1、必须是 16 字节(128 位) //!注意:key一般不推荐进行填充!
2、任意字节值都可以(00–FF)
3、可以是字符串、随机数、固定常量都行
(但字符串本身也必须恰好 16 字节)

后者对key就要有随机性,不能有特殊含义和规律。

加密:

加密按每4字节进行(前面已经分好组了)。
同时key也要进行分组,在分组那边就不多赘述了,直接在这里讲。

将 key 拆成 4 个 32-bit 整数。
明文8字节一组,每组独立加密。
每组执行 32 轮运算:(以下是示例代码)

1
2
3
4
5
6
sum = 0

for i = 1 to 32:
sum += DELTA
v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1) //kn为分组后key
v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3) //vn为分组后明文

当然如果太明白这段代码,可以看一下文字赘述,或者AI辅助理解:

v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1)

逐项拆解:
(v1 << 4) + k0
v1 左移 4 位 → 放大高位信息
加上子密钥 k0 → 加入密钥扰动
左移 4 位相当于乘 16,加大 v1 对 v0 的影响
(v1 + sum)
用 v1 + 累加的 sum 做混合
sum 每轮不同,保证每轮输入不同
(v1 >> 5) + k1
v1 右移 5 位 → 保留低位信息
加上子密钥 k1 → 密钥扰动
左移和右移结合,增强高低位混合
三者用异或 ^ 连接
XOR 可以把各部分位信息混合
保证混合后 v0 每轮高度变化
最后 v0 += …
将混合结果加到 v0
所有操作都是 32-bit 无符号整数,溢出会自动循环

v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3)

和 v0 的更新几乎一样,只是用新的 v0 和 k2/k3
保证左右交互(Feistel结构):
v0 影响 v1
v1 影响下一轮 v0

最后学习了这些,给给大家一个完整的加解密流程,来深入感受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
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
#include <stdint.h>
#include <string.h>
#include <stdlib.h>

#define DELTA 0x9E3779B9
#define ROUNDS 32

// —————————
// TEA 单组加密(v0,v1)
// key: 16 字节
// —————————
void tea_encrypt_block(uint32_t *v, uint32_t *k) {
uint32_t v0 = v[0], v1 = v[1];
uint32_t sum = 0;

for (int i = 0; i < ROUNDS; i++) {
sum += DELTA;
v0 += ((v1 << 4) + k[0]) ^ (v1 + sum) ^ ((v1 >> 5) + k[1]);
v1 += ((v0 << 4) + k[2]) ^ (v0 + sum) ^ ((v0 >> 5) + k[3]);
}

v[0] = v0;
v[1] = v1;
}

// —————————
// 对任意长度明文进行 TEA 加密
// —————————
void tea_encrypt(uint8_t *plaintext, int len, uint8_t *key, uint8_t **ciphertext, int *cipher_len) {
// 填充到 8 字节倍数
int pad_len = 8 - (len % 8);
if (pad_len == 0) pad_len = 8;

int total_len = len + pad_len;
uint8_t *buf = (uint8_t *)malloc(total_len);
memcpy(buf, plaintext, len);

// PKCS7 填充
for (int i = len; i < total_len; i++) {
buf[i] = pad_len;
}

*cipher_len = total_len;
*ciphertext = (uint8_t *)malloc(total_len);

// 将 key 拆成 4 个 32-bit
uint32_t k[4];
for (int i = 0; i < 4; i++) {
k[i] = ((uint32_t)key[i*4] << 24) | ((uint32_t)key[i*4 + 1] << 16)
| ((uint32_t)key[i*4 + 2] << 8) | ((uint32_t)key[i*4 + 3]);
}

// 每 8 字节分组加密
for (int i = 0; i < total_len; i += 8) {
uint32_t v[2];
v[0] = ((uint32_t)buf[i] << 24) | ((uint32_t)buf[i+1] << 16)
| ((uint32_t)buf[i+2] << 8) | ((uint32_t)buf[i+3]);
v[1] = ((uint32_t)buf[i+4] << 24) | ((uint32_t)buf[i+5] << 16)
| ((uint32_t)buf[i+6] << 8) | ((uint32_t)buf[i+7]);

tea_encrypt_block(v, k);

// 存回密文
(*ciphertext)[i] = (v[0] >> 24) & 0xFF;
(*ciphertext)[i+1] = (v[0] >> 16) & 0xFF;
(*ciphertext)[i+2] = (v[0] >> 8) & 0xFF;
(*ciphertext)[i+3] = v[0] & 0xFF;

(*ciphertext)[i+4] = (v[1] >> 24) & 0xFF;
(*ciphertext)[i+5] = (v[1] >> 16) & 0xFF;
(*ciphertext)[i+6] = (v[1] >> 8) & 0xFF;
(*ciphertext)[i+7] = v[1] & 0xFF;
}

free(buf);
}

// —————————
// 测试 TEA 加密
// —————————
int main() {
uint8_t key[16] = ”1234567890abcdef“; // 16 字节 key
uint8_t plaintext[] = ”woshinibaba“; // 明文
uint8_t *ciphertext;
int cipher_len;

tea_encrypt(plaintext, strlen((char *)plaintext), key, &ciphertext, &cipher_len);

printf(”密文 (HEX): “);
for (int i = 0; i < cipher_len; i++) {
printf(”%02X “, ciphertext[i]);
}
printf(”\n“);

free(ciphertext);
return 0;
}
解密:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <stdint.h>
#include <string.h>
#include <stdlib.h>

#define DELTA 0x9E3779B9
#define ROUNDS 32

// —————————
// TEA 单组解密(v0,v1)
// key: 16 字节
// —————————
void tea_decrypt_block(uint32_t *v, uint32_t *k) {
uint32_t v0 = v[0], v1 = v[1];
uint32_t sum = DELTA * ROUNDS; // 解密从最大 sum 开始

for (int i = 0; i < ROUNDS; i++) {
v1 -= ((v0 << 4) + k[2]) ^ (v0 + sum) ^ ((v0 >> 5) + k[3]);
v0 -= ((v1 << 4) + k[0]) ^ (v1 + sum) ^ ((v1 >> 5) + k[1]);
sum -= DELTA;
}

v[0] = v0;
v[1] = v1;
}

// —————————
// 对任意长度密文进行 TEA 解密
// —————————
void tea_decrypt(uint8_t *ciphertext, int cipher_len, uint8_t *key, uint8_t **plaintext, int *plain_len) {
if (cipher_len % 8 != 0) {
printf(”密文长度必须是 8 的倍数\n“);
*plaintext = NULL;
*plain_len = 0;
return;
}

uint8_t *buf = (uint8_t *)malloc(cipher_len);

// 将 key 拆成 4 个 32-bit
uint32_t k[4];
for (int i = 0; i < 4; i++) {
k[i] = ((uint32_t)key[i*4] << 24) | ((uint32_t)key[i*4 + 1] << 16)
| ((uint32_t)key[i*4 + 2] << 8) | ((uint32_t)key[i*4 + 3]);
}

// 每 8 字节分组解密
for (int i = 0; i < cipher_len; i += 8) {
uint32_t v[2];
v[0] = ((uint32_t)ciphertext[i] << 24) | ((uint32_t)ciphertext[i+1] << 16)
| ((uint32_t)ciphertext[i+2] << 8) | ((uint32_t)ciphertext[i+3]);
v[1] = ((uint32_t)ciphertext[i+4] << 24) | ((uint32_t)ciphertext[i+5] << 16)
| ((uint32_t)ciphertext[i+6] << 8) | ((uint32_t)ciphertext[i+7]);

tea_decrypt_block(v, k);

// 存回明文
buf[i] = (v[0] >> 24) & 0xFF;
buf[i+1] = (v[0] >> 16) & 0xFF;
buf[i+2] = (v[0] >> 8) & 0xFF;
buf[i+3] = v[0] & 0xFF;

buf[i+4] = (v[1] >> 24) & 0xFF;
buf[i+5] = (v[1] >> 16) & 0xFF;
buf[i+6] = (v[1] >> 8) & 0xFF;
buf[i+7] = v[1] & 0xFF;
}

// 去掉 PKCS7 填充
int pad_len = buf[cipher_len - 1];
if (pad_len <= 0 || pad_len > 8) pad_len = 0; // 异常情况
*plain_len = cipher_len - pad_len;

*plaintext = (uint8_t *)malloc(*plain_len + 1);
memcpy(*plaintext, buf, *plain_len);
(*plaintext)[*plain_len] = ’\0‘; // 末尾加 ’\0‘

free(buf);
}

// —————————
// 测试 TEA 加解密
// —————————
int main() {
uint8_t key[16] = ”1234567890abcdef“; // 16 字节 key
uint8_t plaintext[] = ”woshinibaba“; // 明文

uint8_t *ciphertext;
int cipher_len;

// 加密
tea_encrypt(plaintext, strlen((char *)plaintext), key, &ciphertext, &cipher_len);

printf(”密文 (HEX): “);
for (int i = 0; i < cipher_len; i++) {
printf(”%02X “, ciphertext[i]);
}
printf(”\n“);

// 解密
uint8_t *decrypted;
int decrypted_len;

tea_decrypt(ciphertext, cipher_len, key, &decrypted, &decrypted_len);
printf(”解密结果: %s\n“, decrypted);

free(ciphertext);
free(decrypted);
return 0;
}
  • Title: Tea
  • Author: HuAmI
  • Created at : 2025-12-15 22:12:57
  • Updated at : 2025-12-15 23:45:10
  • Link: https://redefine.ohevan.com/2025/12/15/Tea/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments
On this page
Tea