TEA家族算法详解

Sher10ck 发布于 2026-04-07 165 次阅读


1. TEA家族简介

TEA(Tiny Encryption Algorithm)是一类轻量级分组加密算法,特点是结构简单、代码量小、实现方便。
它的家族主要包括:

  • TEA
  • XTEA(eXtended TEA)
  • XXTEA(Corrected Block TEA)

在 CTF 逆向题中,TEA 家族常被用来:

  • 对 flag 做二次加密
  • 对字符串或配置表做保护
  • 混入壳、校验逻辑、JNI/native 层
  • 与异或、位运算、字节重排组合形成魔改题

TEA 家族之所以常见,是因为它的代码非常短,出题人改起来方便;但同时它又有明显的结构特征,只要掌握识别方法,逆向恢复并不难。

2. TEA 的基本原理

2.1 基本参数

TEA 的标准参数如下:

  • 分组长度:64 bit
  • 密钥长度:128 bit
  • 轮结构:通常写作 32 轮循环(每轮更新左右各一次)
  • 常量 delta0x9E3779B9

这里的 delta 来源于黄金分割相关常数,用于打破轮函数的对称性。

通常把 64 bit 明文拆成两个 32 bit:

  • v0
  • v1

128 bit 密钥拆成四个 32 bit:

  • k0
  • k1
  • k2
  • k3

2.2 标准 TEA 加密公式

TEA 每轮都更新 sum,然后交替更新左右两部分。

加密伪代码:

sum = 0;
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);
}

解密时完全反过来:

sum = delta * 32;
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;
}

3. XTEA:TEA 的扩展版本

XTEA(eXtended TEA)是对 TEA 的改进版本,主要是修改了轮函数和 key 的选取方式。

它和 TEA 最明显的区别在于:

  • key 不再固定写死成 (k0, k1)(k2, k3)
  • 而是通过 sum 的低位和高位动态选择 key 下标

标准 XTEA 常见写法:

sum = 0;
for (i = 0; i < 32; i++) {
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
sum += delta;
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum >> 11) & 3]);
}

解密:

sum = delta * 32;
for (i = 0; i < 32; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum >> 11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
}

XTEA 在逆向中的识别点

如果你在伪代码里看见:

  • sum & 3
  • (sum >> 11) & 3
  • ((x << 4) ^ (x >> 5)) + x

那大概率就是 XTEA,不是普通 TEA。

4. XXTEA:可变长度块加密

XXTEA 和 TEA / XTEA 最大的不同在于:

  • 它不再固定只处理两个 32 bit
  • 它可以处理多个 32 bit 单元组成的数组

所以 XXTEA 非常适合在 CTF 中用来加密整段字符串、整块数据。

它的核心思路是让一个数组中的各个元素互相影响,轮函数更复杂,常见代码里会看到:

  • n > 1
  • rounds = 6 + 52 / n
  • e = (sum >> 2) & 3
  • MX

经典 XXTEA 代码里最典型的特征就是:

z = v[p] += MX;
y = v[p + 1];

或者末尾还有:

z = v[n - 1] += MX;

XXTEA 的逆向特征非常强

只要你看到下面这些东西同时出现,基本就可以判定是 XXTEA:

  • 6 + 52 / n
  • 0x9E3779B9
  • 数组循环更新
  • ((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (k[(p&3)^e] ^ z))
import struct

MASK = 0xffffffff
DELTA = 0x9E3779B9


def _mx(z, y, sum_, k, p, e):
    return ((((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4))) ^ ((sum_ ^ y) + (k[(p & 3) ^ e] ^ z))) & MASK


def xxtea_encrypt_u32(v, k):
    n = len(v)
    if n < 2:
        return v[:]

    rounds = 6 + 52 // n
    sum_ = 0
    z = v[n - 1]

    v = v[:]
    while rounds > 0:
        rounds -= 1
        sum_ = (sum_ + DELTA) & MASK
        e = (sum_ >> 2) & 3
        for p in range(n - 1):
            y = v[p + 1]
            v[p] = (v[p] + _mx(z, y, sum_, k, p, e)) & MASK
            z = v[p]
        y = v[0]
        v[n - 1] = (v[n - 1] + _mx(z, y, sum_, k, n - 1, e)) & MASK
        z = v[n - 1]
    return v


def xxtea_decrypt_u32(v, k):
    n = len(v)
    if n < 2:
        return v[:]

    rounds = 6 + 52 // n
    sum_ = (rounds * DELTA) & MASK
    v = v[:]

    while sum_ != 0:
        e = (sum_ >> 2) & 3
        y = v[0]
        for p in range(n - 1, 0, -1):
            z = v[p - 1]
            v[p] = (v[p] - _mx(z, y, sum_, k, p, e)) & MASK
            y = v[p]
        z = v[n - 1]
        v[0] = (v[0] - _mx(z, y, sum_, k, 0, e)) & MASK
        y = v[0]
        sum_ = (sum_ - DELTA) & MASK
    return v


def bytes_to_u32_list(data):
    pad = (4 - len(data) % 4) % 4
    data = data + b'\x00' * pad
    return list(struct.unpack('<{}I'.format(len(data) // 4), data)), len(data) - pad


def u32_list_to_bytes(v):
    return struct.pack('<{}I'.format(len(v)), *v)


def fix_key(key_bytes):
    if len(key_bytes) < 16:
        key_bytes = key_bytes.ljust(16, b'\x00')
    elif len(key_bytes) > 16:
        key_bytes = key_bytes[:16]
    return list(struct.unpack('<4I', key_bytes))


def xxtea_encrypt(data, key_bytes):
    v, orig_len = bytes_to_u32_list(data + struct.pack('<I', len(data)))
    k = fix_key(key_bytes)
    enc = xxtea_encrypt_u32(v, k)
    return u32_list_to_bytes(enc)


def xxtea_decrypt(data, key_bytes):
    v = list(struct.unpack('<{}I'.format(len(data) // 4), data))
    k = fix_key(key_bytes)
    dec = xxtea_decrypt_u32(v, k)
    raw = u32_list_to_bytes(dec)
    orig_len = struct.unpack('<I', raw[-4:])[0]
    return raw[:orig_len]


if __name__ == "__main__":
    key = b"1234567890abcdef"
    data = b"hello xxtea reverse"

    enc = xxtea_encrypt(data, key)
    dec = xxtea_decrypt(enc, key)

    print("enc =", enc.hex())
    print("dec =", dec)
此作者没有提供个人介绍。
最后更新于 2026-04-07