TEA
TEA加密算法
TEA加密算法与C比较相关,其实是我的python功力不过关,所以本篇文章使用C++来展示TEA的代码实现,及其解密
不过多介绍历史,维基百科
基本介绍
微型加密算法(Tiny Encryption Algorithm,TEA)是一种对称分组密码算法,它以实现简单、代码量小、运算速度快著称,非常适合资源受限的环境。
基本参数
分组长度:64 位(8 字节)
密钥长度:128 位(16 字节)
结构:Feistel 网络
轮数:64 轮(通常实现为 32 个循环,每个循环包含两轮)
基本运算:
- 加法(模 $2^{32}$)
- 异或(XOR)
- 左移、右移
加密过程
明文分组
首先将明文进行分组,将一个 64 位明文分为两个 32 位数据块
分成v0以及v1,一般是前半部分是v0,后半部分是v1
v0和v1构成一个数据分组
密钥分组
128 位密钥分为四个 32 位子密钥
key[0] key[1] key[2] key[3]
每轮进行以下运算
sum += delta
v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1)
v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3)
其中
delta = 0x9E3779B9
这个值是根据黄金比例构造的常数,用于避免轮函数出现规律性。
值得注意的是
delta的值并不是固定的,它通常可以被开发者所修改,而且轮运算的过程,也能略微进行修改
比如说(v1 << 4)中4是可供修改的值,(v1 >> 5)中的5也是同样可以修改的值
当然也可修改单元运算,具体情况具体分析
使用时候的注意事项
密钥固定要求为128位,即16字节
TEA 每次只能处理 8 字节数据。v0+v1=8字节
如果明文的总长度不是8字节的整数倍,那么需要进行填充
C++代码实现加密
直接上demo
为了确保结果直观,TEA没有出错,也为了逆向工程,我们同时写一个解密函数来证明数据正确加密了
#include<iostream>
#include<cstdint>
#include<Windows.h>
using namespace std;
void TEAencrypt(uint32_t *v,uint32_t *key)
{
uint32_t v0=*v;
uint32_t v1=v[1];
uint32_t sum=0;
uint32_t delta=0x9e3779b9;
for(int i=0;i<32;i++)
{
sum += delta;
v0 += ((v1 << 4) + *key) ^ (v1 + sum) ^ ((v1 >> 5) + key[1]);//一个轮加密
v1 += ((v0 << 4) + key[2]) ^ (v0 + sum) ^ ((v0 >> 5) + key[3]);//两个轮加密
}//循环32次,共进行64轮加密
v[0]=v0; v[1]=v1;
}
void decrypt(uint32_t *v,uint32_t *key)
{
uint32_t v0=v[0];
uint32_t v1=v[1];
uint32_t sum=0xC6EF3720;
uint32_t delta=0x9e3779b9;
for(int i=0;i<32;i++)
{
v1 -= ((v0 << 4) + key[2]) ^ (v0 + sum) ^ ((v0 >> 5) + key[3]);
v0 -= ((v1 << 4) + *key) ^ (v1 + sum) ^ ((v1 >> 5) + key[1]);
sum -= delta;
}
v[0]=v0; v[1]=v1;
}
int main()
{
SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(CP_UTF8);
uint32_t data[]={0x11223344, 0x55667788};//密钥长度要是8字节的整数倍
uint32_t key[]={0x11223344, 0x55667788, 0x99aabbcc, 0xddeeff00};//key的长度固定为128位,16字节
TEAencrypt(data,key);
cout<<"加密后的密文为:"<<hex<<data[0]<<" "<<data[1]<<endl;
decrypt(data,key);
cout<<"解密后的明文为:"<<hex<<data[0]<<" "<<data[1]<<endl;
uint32_t sum = 0;
for(int i=0;i<32;i++)
{
sum+=0x9e3779b9;
}
cout<<"sum最后的值是:"<<sum<<endl;
system("pause");
}
//加密后的密文为:d9e2cb2b 5be32685
//解密后的明文为:11223344 55667788
//sum最后的值是:c6ef3720
求sum的值是因为逆向需要
作者使用的是g++编译,字符串常量是UTF-8编码,终端是GBK编码,双击运行时候会出现乱码,所以使用了
SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(CP_UTF8);
让CMD能以UTF-8编码去解释字节
下面我们用一道例题来展示TEA解密
逆向工程部分
题目名称:[Reisen]NSSCTF2025入门题目-Tea
题目来源:NSSCTF
DIE看看成分

可以用IDA打开一下,注意!!!下面的结果可能和你的IDA反编译结果不一样,我为了教学的直观性改了变量的名称

printf("please input flag:");
scanf("%s", Str);
Size = strlen(Str);
v10 = (Size + 7) >> 3;
v9 = 8 * v10 - 1;
v3 = alloca(16 * ((8 * v10 + 15) >> 4));
v8 = v5;
memset(v5, 0, 8 * v10);
memcpy(v8, Str, Size);
接收输入的flag做一些前置处理,这部分可以忽略不记,不在加密算法内
重点是下面的
tea_encrypt(&v6, key_1);
将输入的字符串进行处理,推测是TEA加密,进去看看

是一个TEA加密,但是并不标准,存在魔改部分,下面我会指出魔改的地方
首先delta的值进行了修改,这里的delta的值是0x414554
然后轮运算也进行了修改,比如说
(16 * v1 + *key)
这里存在明显的修改,但是在实际逆向过程中,其实我们并不需要指出所有的魔改点,我们可以复用代码
TEA的解密十分简单,我们可以看到这里的加密是
sum += 4277588;
v0 += (v1 + sum) ^ (16 * v1 + *key) ^ ((v1 >> 5) + key[1]);
v1 += (v0 + sum) ^ (16 * v0 + key[2]) ^ ((v0 >> 5) + key[3]);
异或是可逆的运算可以不用修改,根据逆向思维,我们要求做加法前的数,就要减去它原本加上的值,加密顺序原本是v0先,v1后的话,解密理应就是v1先解密,v0先加密,sum的值同样如此,既然最先加了sum的值,那么再加密的时候它就是最后逆向的
因此一个轮运算的解密可以是
uint32_t delta=0x414554;
for(int i=0;i<32;i++)
{
sum+=delta;
};
for(int i=0;i<32;i++)
{
v1-= (v0 + sum) ^ (16 * v0 + key[2]) ^ ((v0 >> 5) + key[3]);
v0 -= (v1 + sum) ^ (16 * v1 + *key) ^ ((v1 >> 5) + key[1]);
sum -= delta;
}
值得注意的是,sum的值在解密开始时已经经历了32轮累加delta的运算,因此此处的初始值也需要经过32轮累加运算
根据题目我们也可以找到,密文以及密钥

使用export data可以快速导出c风格的数据

key在题目中非常显眼,请自己去寻找
完整的EXP
#include <iostream>
#include <cstdint>
#include <windows.h>
using namespace std;
void decrypt(uint32_t *v,uint32_t *key)
{
uint32_t v0=*v;
uint32_t v1=v[1];
uint32_t sum=0;
uint32_t delta=0x414554;
for(int i=0;i<32;i++)
{
sum+=delta;
};
for(int i=0;i<32;i++)
{
v1-= (v0 + sum) ^ (16 * v0 + key[2]) ^ ((v0 >> 5) + key[3]);
v0 -= (v1 + sum) ^ (16 * v1 + *key) ^ ((v1 >> 5) + key[1]);
sum -= delta;
}
v[0]=v0; v[1]=v1;
}
int main()
{
SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(CP_UTF8);
uint8_t enc[] =
{
0xE4, 0x6E, 0x00, 0xF0, 0x91, 0x73, 0x9A, 0xBE, 0xCA, 0xF1,
0x2A, 0x60, 0x0E, 0x8F, 0x74, 0x83, 0xE0, 0x8E, 0x6C, 0x34,
0xD7, 0x99, 0xDE, 0x36, 0x8B, 0x86, 0xC4, 0x90, 0xC2, 0x0B,
0xC4, 0x59
};
uint8_t key[] =
{
0xEF, 0xBE, 0xAD, 0xDE, 0x0D, 0xF0, 0xAD, 0xBA, 0xDE, 0xC0,
0xAD, 0xDE, 0xCC, 0x10, 0xAD, 0xDE
};
for (int i = 0; i < sizeof(enc); i+=8)
{
decrypt((uint32_t*)(enc + i), (uint32_t*)key);
}
cout<<(char*)enc;
system("pause");
}
结果就请自己运行试试看啦,如果你觉得本篇文章对你有帮助不妨点个赞,如果觉得存在问题欢迎在评论区以及私信作者

浙公网安备 33010602011771号