TEA系列加密

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

有些题目会把这种位移操作换成这种形式,也要识别出来

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值