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

void encrypt (uint32_t* v, uint32_t* k) {
uint32_t v0=v[0], v1=v[1], sum=0, i; /* set up */
uint32_t delta=0x9e3779b9; /* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
for (i=0; i < 32; i++) { /* basic cycle start */
sum += delta;
v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
} /* end cycle */
v[0]=v0; v[1]=v1;
}

void decrypt (uint32_t* v, uint32_t* k) {
uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i; /* set up */
uint32_t delta=0x9e3779b9; /* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
for (i=0; i<32; i++) { /* basic cycle start */
v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
sum -= delta;
} /* end cycle */
v[0]=v0; v[1]=v1;
}

在 Tea 算法中其最主要的识别特征就是 拥有一个 magic number :0x9e3779b9 。当然,这 Tea 算法也有魔改的,感兴趣的可以看 2018 0ctf Quals milk-tea。

概念

解析 TEA 加密算法(C语言、python):

TEA系列概述:

TEA算法是由剑桥大学计算机实验室的 David Wheeler 和 Roger Needham于1994年发明,TEA 是Tiny Encryption Algorithm的缩写,以加密解密速度快,实现简单著称。

TEA 算法每一次可以操作 64bit(8byte),采用 128bit(16byte) 作为 key,算法采用迭代的形式,推荐的迭代轮数是 64轮,最少 32 轮。

为解决 TEA 算法密钥表攻击的问题,TEA 算法先后经历了几次改进,从 XTEA 到 BLOCK TEA,直至最新的XXTEA。

XTEA 也称做 TEAN:

它使用与 TEA 相同的简单运算,但四个子密钥采取不正规的方式进行混合以阻止密钥表攻击。

Block TEA 算法可以对 32 位的任意整数倍长度的变量块进行加解密的操作:

该算法将 XTEA 轮循函数依次应用于块中的每个字,并且将它附加于被应用字的邻字。

XXTEA使用跟Block TEA相似的结构:

但在处理块中每个字时利用了相邻字,且用拥有两个输入量的 MX 函数代替了 XTEA 轮循函数。

上面提到的相邻字其实就是数组中相邻的项。

TEA 系列算法中均使用了一个 DELTA 常数,但 DELTA 的值对算法并无什么影响,只是为了避免不良的取值,推荐DELTA 的值取为黄金分割数 (5√-2)/2 与 232 的乘积,取整后的十六进制值为 0x9e3779B9,用于保证每一轮加密都不相同。

TEA 加密:

TEA算法介绍:

TEA 采用与 DES 算法类似的 Feistel 结构,迭代的每次循环使用加法和移位操作,对明文和密钥进行扩散和混乱,实现明文的非线性变换。TEA 密钥长度和迭代次数都是 DES 的两倍,抗“试错法”攻击的强度不低于 DES 算法。算法以32bits 的字为运算单位,而不是耗费计算能力的逐位运算。算法没有采用 DES 那样的转换矩阵,它安全、高效、占用存储空间少,非常适合在嵌入式系统中应用, 据说 QQ 就是使用 16 轮迭代的 TEA 算法。

加密过程:(解密过程逆过来即可)

1731483334148-b86d80a7-758e-4958-954e-c1f769b059cf.png

c脚本

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
#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;
}
void decrypt (uint32_t *v,uint32_t *k){
uint32_t v0=v[0],v1=v[1],sum=0xC6EF3720,i; //这里的sum是0x9e3779b9*32后截取32位的结果,截取很重要。
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 v[2]={1,2},k[4]={2,2,3,4};
printf("加密前的数据:%u %u\n",v[0],v[1]); //%u 以十进制形式输出无符号整数
encrypt(v,k);
printf("加密后数据:%u %u\n",v[0],v[1]);
decrypt(v,k);
printf("解密后数据:%u %u\n",v[0],v[1]);
return 0;
}

python脚本

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
from ctypes import *


def encrypt(v, k):
v0 = c_uint32(v[0])
v1 = c_uint32(v[1])
sum1 = c_uint32(0)
delta = 0x9e3779b9
for i in range(32):
sum1.value += delta
v0.value += ((v1.value << 4) + k[0]) ^ (v1.value + sum1.value) ^ ((v1.value >> 5) + k[1])
v1.value += ((v0.value << 4) + k[2]) ^ (v0.value + sum1.value) ^ ((v0.value >> 5) + k[3])
return v0.value, v1.value


def decrypt(v, k):
v0 = c_uint32(v[0])
v1 = c_uint32(v[1])
delta = 0x9e3779b9
sum1 = c_uint32(delta * 32)
for i in range(32):
v1.value -= ((v0.value << 4) + k[2]) ^ (v0.value + sum1.value) ^ ((v0.value >> 5) + k[3])
v0.value -= ((v1.value << 4) + k[0]) ^ (v1.value + sum1.value) ^ ((v1.value >> 5) + k[1])
sum1.value -= delta
return v0.value, v1.value


if __name__ == '__main__':
a = [1, 2]
k = [2, 2, 3, 4]
print("加密前数据:", a)
res = encrypt(a, k)
print("加密后的数据:", res)
res = decrypt(res, k)
print("解密后数据:", res)

原文链接:https://blog.csdn.net/xiao__1bai/article/details/123307059

XTEA加密

首先我们还是先了解一下XTEA算法

跟TEA算法很类似,差别就是将r的变化结果和l变化结果进行了交替赋值,同时位移次数进行了一些变化,也掺杂了一些与操作

1741071893775-0ce51887-c1a4-444a-acf3-1fc22abe7c73.png

这里是典型的XTEA加密和异或加密,但是根据给定的key和算法,计算出来的是一个假flag:
fakeflag_plz_Try_more_hard_to_find_the_true_flag

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

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 v[2]={1,2};
uint32_t const k[4]={2,2,3,4};
unsigned int r=32; //这里是加密轮数,自己设置
printf("加密前原始数据:%u %u\n",v[0],v[1]);
encipher(r,v,k);
printf("加密后原始数据:%u %u\n",v[0],v[1]);
decipher(r,v,k);
printf("解密后原始数据:%u %u\n",v[0],v[1]);
return 0;
}

TEA例题

1、

先查壳,放入64

1721463402576-04d877a3-3083-429d-8842-70924b64c583.png

直接运行exe是个fakeflag哈哈哈哈哈

1721463517559-d0f3fb8b-b846-4d69-8057-2a0bf5d39813.png

去string里面找关键语句,然后x快捷键去查看调用的函数

1721463784208-50523ef6-e788-4572-b8d2-33d6210bf472.png

1721463842200-a2f6e9f1-73c9-4883-be32-8e7f9480c713.png

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
for ( j = 0; j < 10; ++j )
// 输入函数,scanf
sub_1400111FE("%x", &v8[j]);
// v7重新赋值
sub_140011339(v7);
// v8备份到v9
sub_140011145(v8, v9);
// v7为key,v8为输入的值,进行tea加密
sub_1400112B7(v8, v7);
// 验证加密的结果是否符合预期
v6 = sub_140011352(v8);
if ( v6 )
{
// sub_140011195 为打印函数
printf("you are right\n");
for ( k = 0; k < 10; ++k )
{
for ( m = 3; m >= 0; --m )
printf("%c", (v9[k] >> (8 * m)));
}
}
else
{
printf("fault!\nYou can go online and learn the tea algorithm!");
}

跟进 sub_140011339(v7),发现v7被重新赋值

1721464236278-d2535e23-d7c9-402b-a19a-86b3f115c12f.png

原来的———————————————————>改后的

1
2
3
4
v7[0] = 1234;
v7[1] = 5678;
v7[2] = 9012;
v7[3] = 3456;
1
2
3
4
5
6
7
8
v6 = 2233;
v7 = 4455;
v8 = 6677;
v9 = 8899;
*a1 = 2233;
a1[1] = v7;
a1[2] = v8;
a1[3] = v9;

// v8备份到v9;

跟进sub_140011145(v8, v9);发现就是一个备份功能的函数

1721464330297-37f9c77a-2c20-4c0d-9c48-c57216d8e13b.png

// v7为key,v8为输入的值,进行tea加密

sub_1400112B7(v8, v7);

1721464401788-9100f9f8-425b-4b90-b9fc-8eacfbef4e37.png

进入 sub_140011B60 函数,得到加密后的数据,开始写脚本

1721464531316-d3667f6e-f3c0-4e89-bcc4-3217d96cca10.png

cexp

经典c代码

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

int main() {
int key[] = {2233, 4455, 6677, 8899}; // 密钥数组
unsigned int value[10]; // 用于存储加密数据的数组

// 初始化加密数据
value[0] = 0x1A800BDA;
value[1] = 0xF7A6219B;
value[2] = 0x491811D8;
value[3] = 0xF2013328;
value[4] = 0x156C365B;
value[5] = 0x3C6EAAD8;
value[6] = 0x84D4BF28;
value[7] = 0xF11A7EE7;
value[8] = 0x3313B252;
value[9] = 0xDD9FE279;

int delta = 0xF462900; // 一个常量,用于加密算法
int i = 0;
int wheel; // 轮数
int sum = 0;

// 逆算法解密
for (i = 8; i >= 0; i--) {
wheel = 33; // 33轮加密
sum = delta * (i + wheel);
while (wheel--) {
sum -= delta;
value[i + 1] -= (sum + key[(sum >> 11) & 3]) ^ (value[i] + ((value[i] >> 5) ^ (16 * value[i])));
value[i] -= sum ^ (value[i + 1] + ((value[i + 1] >> 5) ^ (16 * value[i + 1]))) ^ (sum + key[sum & 3]);
}
}

// 将解密后的数据转换为字符并输出
for (i = 0; i <= 9; i++) {
printf("%c", (value[i] >> 24) & 0xFF); // 高8位
printf("%c", (value[i] >> 16) & 0xFF); // 次高8位
printf("%c", (value[i] >> 8) & 0xFF); // 次低8位
printf("%c", value[i] & 0xFF); // 低8位
}

return 0;
}

pyexp(会有乱码)

python代码可以会输出乱码,主要是溢出的问题,去掉乱码投机正确,还是c比较科学一点

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
def main():
key = [2233, 4455, 6677, 8899] # 密钥数组
value = [0x1A800BDA, 0xF7A6219B, 0x491811D8, 0xF2013328, 0x156C365B,
0x3C6EAAD8, 0x84D4BF28, 0xF11A7EE7, 0x3313B252, 0xDD9FE279] # 初始化加密数据

delta = 0x0F462900 # 一个常量,用于加密算法
sum = 0

# 逆算法解密
for i in range(8, -1, -1):
wheel = 33 # 33轮加密
sum = delta * (i + wheel)
while wheel > 0:
sum -= delta
sum &= 0xFFFFFFFF # 保持为32位
value[i + 1] -= ((sum + key[(sum >> 11) & 3]) ^ (value[i] + ((value[i] >> 5) ^ (16 * value[i]))))
value[i + 1] &= 0xFFFFFFFF # 保持为32位
value[i] -= (sum ^ (value[i + 1] + ((value[i + 1] >> 5) ^ (16 * value[i + 1]))) ^ (sum + key[sum & 3]))
value[i] &= 0xFFFFFFFF # 保持为32位
wheel -= 1

# 将解密后的数据转换为字符并输出
for val in value:
print(chr((val >> 24) & 0xFF), end='') # 高8位
print(chr((val >> 16) & 0xFF), end='') # 次高8位
print(chr((val >> 8) & 0xFF), end='') # 次低8位
print(chr(val & 0xFF), end='') # 低8位


if __name__ == "__main__":
main()

2、

1722054641314-437f3875-8b54-40ad-b516-4b8aeb067346.png

代码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
scanf("%s", v5);
v9 = v5;
// 将输入的值赋入 v4的后八位
for ( i = 0; i <= 5; ++i )
v4[i + 8] = *v9++;
// 两两进行XTea加密
for ( j = 0; j <= 2; ++j )
tea_encrypt(&v4[2 * j + 8], &key);
// 加密后的字符串要等于这些
v4[0] = -1054939302;
v4[1] = -1532163725;
v4[2] = -165900264;
v4[3] = 853769165;
v4[4] = 768352038;
v4[5] = 876839116;
for ( k = 0; k <= 5; ++k )
{
if ( v4[k] != v4[k + 8] )
{
printf("ERROR!");
exit(9);
}
}

按d,将key合成为4位、8字节的形式,再提取

1722055208022-54aca640-c283-4a51-97c1-ff089748e031.png

tea加密函数

1722054654216-26498323-00c8-402e-ba33-5de480f1e045.png

exp

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

int main()
{
unsigned int enc[6] = {0xC11EE75A, 0xA4AD0973, 0xF61C9018, 0x32E37BCD, 0x2DCC1F26, 0x344380CC};
unsigned int key[4] = {0x10203, 0x4050607, 0x8090A0B, 0x0C0D0E0F};
int i, j;
long sum = 0, delta = 0x61C88647;
// 解码
for(i=0;i < 6;i+=2){
sum = 0 - (32 * delta);
for(j = 0; j < 32; j++) {
enc[i+1] -= (((enc[i] >> 5) ^ (16 * enc[i])) + enc[i]) ^ (key[((sum >> 11) & 3)] + sum);
sum += delta;
enc[i] -= ((((enc[i+1] >> 5) ^ (16 * enc[i+1])) + enc[i+1]) ^ key[sum & 3] + sum);
}
}
// 打印
for (i = 0; i < 6; i++)
{
for (j = 0; j<=3; j++)
{
printf("%c", (enc[i] >> (j * 8)) & 0xFF);
}
}

return 0;
}

1722054984122-9065a0d4-00c2-489e-be39-81b6ca45ea63.png

ezzzz

先每8位转化成一个数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def string_to_hex_with_prefix(input_string):
# 创建一个空的结果数组
hex_result = []

# 每 8 个字符一组
for i in range(0, len(input_string), 8):
chunk = input_string[i:i + 8]

# 将每组字符转为十六进制并加上 '0x' 前缀
hex_value = int(chunk.encode('utf-8').hex())

# 添加到数组中
hex_result.append(hex_value)

return hex_result


# 示例
input_string = "f1f186b25a96c782e6c63a0b70b61b5ced6bf84889700d6b09381b5ccb2f24fab1c79e796d822d9cdcc55f760f780e750d65c4afb89084a9e978c3827a8dd81091f28df3a84dbacab4d75f75f19af8e5b90f80fcfc10a5c3d20679fb2bc734c8ccb31c921ac52ad3e7f922b72e24d923fb4ce9f53548a9e571ebc25adf38862e10059186327509463dd4d54c905abc36c26d5312d2cd42c0772d99e50cd4c4665c3178d63a7ffe71ada251c070568d5a5798c2921ec0f7fc3ae9d8418460762930ca6a2dccef51d2a1a8085491b0f82d686ca34774c52d0f0f26449fc28d362c86f3311b8adc4fb1a4497e34e0f0915d" # 输入字符串
hex_output = string_to_hex_with_prefix(input_string)

# 输出结果
print("Hexadecimal array:", hex_output)

1731845706786-36a034f2-3c1d-4e61-8f9d-7216d9758903.png

喝茶

上面为密文,记得转成十六进制

提取key和密文

1745052012351-cc6c7c61-56f5-434f-b0ef-3c82a32d04d2.png

1745051399450-e208442e-27e9-427f-bb86-3ad4f52dabe3.png

每两个一组进行tea解密,一共6个三组解密完成

1745052212499-e1eab54c-dd00-4422-9ff1-1829e6f25aa7.png

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


void decrypt (uint32_t *v,uint32_t *k){
uint32_t v0=v[0],v1=v[1],sum=0x1919810*32,i;
uint32_t delta=0x1919810;
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 input[] = {0x12287745, 0x3692f306, 0x0ee7c0e2, 0xb97f85b7, 0xaa966689, 0x46b81a67};
uint32_t k[4]={0x73656372,0x65746b65,0x79313233,0x34353637};
for (int i=0;i<6;i+=2)
{
uint32_t v[2]={input[i],input[i+1]};
decrypt(v,k);
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 4; k++) {
printf("%c", v[j] & 0xff);
v[j] >>= 8;
}
}
}
return 0;
}

XTEA例题

1、

1741071893775-0ce51887-c1a4-444a-acf3-1fc22abe7c73.png

这里是典型的XTEA加密和异或加密,但是根据给定的key和算法,计算出来的是一个假flag:
fakeflag_plz_Try_more_hard_to_find_the_true_flag

更新: 2025-04-19 16:44:05
原文: https://www.yuque.com/chaye-apqbl/vsc85q/rqg1uagfufcb8ylp


http://example.com/2026/01/19/RE/算法逆向/TEA/
Author
chaye
Posted on
January 19, 2026
Licensed under