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; }
|