Featured image of post TEA 与 XXTEA

TEA 与 XXTEA

感觉还行(bushi

背景与简介

  • **TEA **:Wheeler 与 Needham 提出的一种极简分组密码。优点是实现非常简单、速度快、代码体积小;缺点是存在弱密钥问题,不建议在高强度安全场景使用。

    • 分组:64-bit(两个 uint32_t
    • 密钥:128-bit(四个 uint32_t
    • 建议轮数:32次循环(对应 64 轮 Feistel 步)
    • 常数:delta = 0x9E3779B9(取自黄金分割)
  • XXTEA :为修正 Block TEA 的缺陷而提出的改进算法。适合任意长度的 32-bit 整数数组。

    • 数据:n 个 32-bit 整数(n >= 2
    • 密钥:同样 128-bit
    • 轮数:6 + 52 / n
    • 仍然只使用移位、异或、加法等非常高效的操作

实现要点与注意

  • 整数宽度与溢出:两者都依赖 32 位无符号整数的“环”运算(模 2**32)。C++ 的 uint32_t 自带无符号溢出语义(自动按 32 位截断),无需像py一样手动 & 0xFFFFFFFF
  • 端序:示例实现中的打包/拆包函数固定使用小端(倒序?)格式,保证跨平台一致。

TEA (64-bit 分组)

这里先给出简单的实现,实际上做题或者生产是需要变种的,本人目前水平太臭(,就放自己会的了。

 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
#include <cstdint>
#include <array>

namespace tea {

static constexpr uint32_t DELTA = 0x9E3779B9u;

// key: 4×uint32_t
using Key128 = std::array<uint32_t, 4>;

// 加密一个 64-bit 块(v0,v1)
inline void encrypt_block(uint32_t &v0, uint32_t &v1, const Key128 &k, uint32_t rounds = 32) {
    uint32_t sum = 0;
    for (uint32_t 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]);
    }
}

inline void decrypt_block(uint32_t &v0, uint32_t &v1, const Key128 &k, uint32_t rounds = 32) {
    uint32_t sum = DELTA * rounds;
    for (uint32_t 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;
    }
}

} // namespace tea

XXTEA(任意长度 32-bit 数组)

 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
#include <cstdint>
#include <vector>
#include <array>

namespace xxtea {

using Key128 = std::array<uint32_t, 4>;
static constexpr uint32_t DELTA = 0x9E3779B9u; // 经典常数

// v: n 个 uint32_t,n>=2
inline void encrypt(std::vector<uint32_t> &v, const Key128 &k) {
    const size_t n = v.size();
    if (n < 2) return;
    uint32_t rounds = 6u + static_cast<uint32_t>(52u / n);
    uint32_t sum = 0;
    uint32_t z = v[n - 1], y;
    while (rounds--) {
        sum += DELTA;
        uint32_t e = (sum >> 2) & 3u;
        for (size_t p = 0; p < n - 1; ++p) {
            y = v[p + 1];
            v[p] += (((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4)))
                  ^ ((sum ^ y) + (k[(p ^ e) & 3] ^ z));
            z = v[p];
        }
        y = v[0];
        v[n - 1] += (((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4)))
                  ^ ((sum ^ y) + (k[((n - 1) ^ e) & 3] ^ z));
        z = v[n - 1];
    }
}

inline void decrypt(std::vector<uint32_t> &v, const Key128 &k) {
    const size_t n = v.size();
    if (n < 2) return;
    uint32_t rounds = 6u + static_cast<uint32_t>(52u / n);
    uint32_t sum = rounds * DELTA;
    uint32_t z, y = v[0];
    while (rounds--) {
        uint32_t e = (sum >> 2) & 3u;
        for (size_t p = n - 1; p > 0; --p) {
            z = v[p - 1];
            v[p] -= (((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4)))
                  ^ ((sum ^ y) + (k[(p ^ e) & 3] ^ z));
            y = v[p];
        }
        z = v[n - 1];
        v[0] -= (((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4)))
              ^ ((sum ^ y) + (k[(0 ^ e) & 3] ^ z));
        y = v[0];
        sum -= DELTA;
    }
}

} // namespace xxtea

实际上和tea一样,xxtea的解密≈ 加密的倒序(主要得益于异或的性质):

  • 轮次顺序:解密要从最后一轮往回走;

  • 运算符号:加密时加上去的量,解密就减掉;

  • 状态依赖:由于每一轮结果依赖前一轮,必须严格逆序才能还原。

需要注意的是xxtea循环之后还有一步的单独处理,原因是XXTEA 的设计是一个"环形数组"运算,所以要额外处理首尾一次。


小结

  • TEA 与 XXTEA 都以“移位 + 异或 + 加法”为核心,易实现且性能佳。
  • TEA 面向 64-bit 分组;XXTEA 直接面向 32-bit 数组,适合任意长度。
生活由投入其中的每一天构成
使用 Hugo 构建
主题 StackJimmy 设计