TEA系列加密
TEA 是 Tiny Encryption Algorithm 的缩写,以加密解密速度快,实现简单著称。
TEA 算法每一次可以操作 64bit(8byte),就是把这8个字节分成前四个字节和后四个字节,然后分别加密,实现整体加密。
采用 128bit(16byte)作为key(常见的就是4个int,或者4个DWORD),算法采用迭代的形式,推荐的迭代轮数是 64 轮,最少 32 轮。腾讯自己改了一版,用的是16轮,因为速度更快
为解决 TEA 算法密钥表攻击的问题,TEA算法先后经历了几次改进(解决理论缺陷),tea----->xtea----->xxtea。
TEA 系列算法中均使用了一个 DELTA 常数(DWORD,usigned int),但 DELTA 的值对算法并无什么影响,只是为了避免不良的取值
推荐 DELTA 的值取为黄金分割数与 232的乘积,取整后的十六进制值为0x9e3779B9,用于保证每一轮加密都不相同。但有时该常数会以减法的形式出现,-0x61C88647=0x9E3779B9,因此出现了0x61c88647 时也应当注意。
- 这里正数和负数的形式是因为代码实现的不一样,比如:
- sum += delta ------->这里就需要一个正值,也就是0x9e3779B9
- 如果这样写:
- sum -= delta -------->这里就需要负数形式的delta,也就是-0x61C88647
当然,如果你是出题人,想实现对抗的话,你肯定会修改这个特征值,这个后续我们聊对抗混淆的时候会说的
加密流程大致为:
1.TEA以原文每8字节加解密(如果明文本身的长度不是8的倍数,那么还要进行填充以使其成为8的倍数),分成左右两边各四字节传入L(0)、R(0)。
2.右边传入的四个字节R(0),与密钥K和常数δ进行一系列左右移、相加、异或操作,得到结果F(R(0),K,δ),L(1)=L(0)+F(R(0),K,δ)。 – > 左移4,右移5
3.L(1)再与密钥K和常数δ进行一系列左右移、相加、异或操作,得到结果F(L(1),K,δ),R(1)=R(0)+F(L(1),K,δ)。
4.以此重复32轮得到加密后的L和R。
TEA
C语言实现加解密
#include <stdio.h>
#include <stdint.h>
void encrypt(uint32_t* v, uint32_t* k)
{
uint32_t sum = 0;
uint32_t v0 = v[0], v1 = v[1];
uint32_t delta = 0x9e3779b9;//加密魔数
//密钥key:
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
//前后分别加密实现整体加密:
for (int i = 0; i < 32; i++)
{
sum += delta;//sum也可以不是0,不会影响逻辑,可以在sum这里魔改
//v0和v1互相影响的过程,加密操作都是一样的,左移4,右移5,我们还可以把这个过程定义成一个宏
v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);//用掉前两个Key
v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);//用掉后两个key
}
//加密完成:
v[0] = v0;
v[1] = v1;
//这里当然可以直接用v[0]和v[1]去操作,但是速度上就没那么快,这里我们用v0和v1,就可以直接放在寄存器上,运算速度更快,但是如果用v[0]和v[1],你还要先去计算偏移距(就是数组首元素地址和数组内元素的距离),
}
void decrypt(uint32_t* v, uint32_t* k)//解密很简单的,跟加密差不多,直接拷过来改吧改吧就行
{
uint32_t v0 = v[0], v1 = v[1];
uint32_t delta = 0x9e3779b9;
uint32_t sum = delta * 32;//加密过程中,sum被叠加了32次,所以此时sum的初始值是delta * 32
//一定要记得去找到这个轮数
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
for (int 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()
{
//两个32位无符号整数,即待加密的64bit明文数据
uint32_t v[2] = { 0x12345678,0x78563412 };
//四个32位无符号整数,即128bit的key:
uint32_t k[4] = { 0x1,0x2,0x3,0x4 };
printf("Data is : %x %x\n", v[0], v[1]);
encrypt(v, k);
printf("Encrypted data is : %x %x\n", v[0], v[1]);
decrypt(v, k);
printf("Decrypted data is : %x %x\n", v[0], v[1]);
return 0;
}
特征识别:
- 我们在做题的时候,看见这种有左移,右移和异或操作结合的,基本可以怀疑是TEA系列的,不过具体是哪个tea,要根据实际情况来
- 标准delta魔数
- 加密轮数为16/32/64
- 加密结构中存在左4右5移位及异或运算
- 加密结构中存在轮加/减相同常数的语句
对抗方式:
- 修改魔数
- 修改轮数
- 修改轮加/减魔数的位置
注意,在IDA中,xmmword代表16个字节,xmm0寄存器一次可以操作16个字节,在IDA中看见了要知道啥意思
TEA例题演示
XYCTF 2024 给阿姨倒一杯卡布奇诺
本题最重要的变化就是i也参与了加密运算,所以我们就不能像之前一样,直接拷过来用了,需要写成 i = 31 ,i >= 0,i–这样的形式,因为参与每轮的i是不一样的,这里的i也不是简单的计数功能
还有就是进行异或运算,每一轮异或的data1和data2,下一轮会变成上一轮的v0和v1,所以整体的思路要逆过来,脚本如下:
void decrypt(uint32_t* v, uint32_t* k)
{
int i;
uint32_t delta = 0x6E75316C;
uint32_t sum = 32 * delta;
uint32_t v1 = v[1] ,v0 = v[0];
for (i = 31; i >= 0; i--)
{
v1 -= ((v0 >> 5) + k[3]) ^ (v0 + sum) ^ (k[2] + 16 * v0) ^ (sum + i);
v0 -= ((v1 >> 5) + k[1]) ^ (v1 + sum) ^ (k[0] + 16 * v1) ^ (sum + i);
sum -= delta;
}
v[0] = v0;
v[1] = v1;
}
int main()
{
uint32_t v[8] = {
0x9B28ED45,
0x145EC6E9,
0x5B27A6C3,
0xE59E75D5,
0xE82C2500,
0xA4211D92,
0xCD8A4B62,
0xA668F440
};
uint32_t k[4] = {
0x65766967,
0x756F795F,
0x7075635F,
0x6165745F
};
uint32_t data1, data2;
for (int i = 3; i >= 0; i--)
{
decrypt(&v[i * 2], k);
if (i == 0)
{
v[i] ^= 0x5F797274;
v[i + 1] ^= 0x64726168;
}
else
{
data1 = v[2 * (i - 1)];
data2 = v[2 * (i - 1) + 1];
v[i * 2] ^= data1;
v[i * 2 + 1] ^= data2;
}
}
printf("%s", (char*)v);
return 0;
}
XTEA
其实就是加密的过程那里变了一下下而已
void xtea_encrypt(uint32_t* v, uint32_t* k)
{
uint32_t v0 = v[0], v1 = v[1];
uint32_t sum = 0;
uint32_t delta = 0x9E3779B9;
for (int 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)]);
}
v[0] = v1;
v[1] = v0;
}
识别特征:
- 同TEA
- 加密结构中存在右移11位并&3的运算,尤其是&3,你看到&3,基本上就是XTEA了
XXTEA
XTEA升级版,加密的明文数据可以不再是64bit(两个32位无符号整数),可以一次操作很多个,并且加密轮数是由n,即待加密数据个数决定的。
C语言实现加解密
#include <stdio.h>
#include <stdint.h>
#define DELTA 0x9e3779b9
#define MX (((z >> 5 ^ y << 2)+(y >> 3 ^ z << 4))^((sum ^ y)+(key[(p&3)^e]^z)))
//加解密在一个函数实现:
void xxtea(uint32_t* v, int n, uint32_t* key)
{
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1)//根据n这个参数和1的关系决定进行加密还是解密操作
{
rounds = 6 + 52 / n;//一般都是看这里来判断XXTEA的
sum = 0;
z = v[n - 1];
do
{
sum += DELTA;
e = (sum >> 2) & 3;//其实就是在算key的下标,用这个e决定用key这个数组中的哪一个
for (p = 0; p < n - 1; p++)
{
y = v[p + 1];
z = v[p] += MX;//通过宏定义,z也会被修改
}
y = v[0];
z = v[n - 1] += MX;
} while (--rounds);
}
else if (n < -1)
{
n = -n;
rounds = 6 + 52 / n;
sum = rounds * DELTA;
y = v[0];
do
{
e = (sum >> 2) & 3;
for (p = n - 1; p > 0; p--)
{
z = v[p - 1];
y = v[p] -= MX;
}
z = v[n - 1];
y = v[0] -= MX;
sum -= DELTA;
} while (--rounds);
}
}
int main()
{
uint32_t v[2] = { 0x12345678,0x78563412 };
uint32_t k[4] = { 0x1,0x2,0x3,0x4 };
int n = 2;//这里的v里面我们切分了2个32位的块
printf("Data is: %x %x\n", v[0], v[1]);
xxtea(v, n, k);
printf("Encrypted data is: %x %x\n", v[0], v[1]);
xxtea(v, -n, k);
printf("Decrypted data is: %x %x\n", v[0], v[1]);
return 0;
}
特征识别:
- 看轮数,一般都是52 / n + 6,一般魔改也不会改这里;
- xxtea一般不太会出现,一般大的结构是不会变的
补充·:
v * (2 ^ n) == v << n
有些题目会把这种位移操作换成这种形式,也要识别出来
4686

被折叠的 条评论
为什么被折叠?



