TEA加密
之前在做逆向题的时候遇到过很多加密算法,但是都没有系统的学习过,所以准备总结一下这些算法,今天复现的是tea算法。TEA算法使用64位的明文分组和128位的密钥,使用feistel分组加框架,需要进行32轮循环得到最后的64位密文,其中magic number DELTA是由黄金分割点。
加密算法源码
#include<stdio.h>
#define DELTA 0x9e3779b9
void tea_encrypt(unsigned int* v, unsigned int* key) {
unsigned int l = v[0], r = v[1], sum = 0;
for (size_t i = 0; i < 32; i++) { //进行32次迭代加密,Tea算法作者的建议迭代次数
l += (((r << 4) ^ (r >> 5)) + r) ^ (sum + key[sum & 3]);
sum += DELTA; //累加Delta的值
r += (((l << 4) ^ (l >> 5)) + l) ^ (sum + key[(sum >> 11) & 3]); //利用多次双位移和异或将明文与密钥扩散混乱,并将两个明文互相加密
}
v[0] = l;
v[1] = r;
}
void tea_decrypt(unsigned int* v, unsigned int* key) {
unsigned int l = v[0], r = v[1], sum = 0;
sum = DELTA * 32; //32次迭代累加后delta的值
for (size_t i = 0; i < 32; i++) {
r -= (((l << 4) ^ (l >> 5)) + l) ^ (sum + key[(sum >> 11) & 3]);
sum -= DELTA;
l -= (((r << 4) ^ (r >> 5)) + r) ^ (sum + key[sum & 3]);
}
v[0] = l;
v[1] = r;
}
int main(int argc, char const *argv[])
{
unsigned int key[4]={0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f};
unsigned int v1[2] = {0xaabbccdd,0x01234567};
tea_encrypt(v1,key);
printf("tea_encrypt:%x %x\n",v1[0],v1[1]);
tea_decrypt(v1,key);
printf("tea_decrypt:%x %x\n",v1[0],v1[1]);
return 0;
tea算法最关键的是要找到DELTA值和128位的key。
在逆向程序的时候,可以利用ida的插件findcypto识别tea算法
如上图的程序,可以看出a2就是key,v4-=0x61c88647和v4+=0x9e3779b9是等价的,显然DELTA就是0x9e3779b9
例:Android CrackME TEA加密算法的逆向
在so文件的xxx()函数找到了加密算法。
其中可以发现TEA的显著特征0xC6EF3720,和 -0x61C88647(即0x9E3779B9)还有十六个字节的key
根据加密写出解密脚本
#define _DWORD unsigned int
#define HIDWORD(x) (*((_DWORD *)&(x) + 1))
#define LODWORD(x) (*((_DWORD *)&(x)))
//key="\x67\x45\x23\x01\xEF\xCD\xAB\x89\x98\xBA\xDC\xFE\x10\x32\x54\x76"
//TEA解密算法
long long xxxx_decrypt(int a1, int a2)
{
int v2;
int v3;
int v4;
unsigned int v5;
unsigned int v6;
int v7;
long long v9;
v2 = *(int *)(a2 + 8); //v2=0xFEDCBA98
v3 = *(int *)a2; //v3=0x1234567
v4 = *(int *)(a2 + 4); //v4=0x89ABCDEF
v5 = *(int *)a1;
v6 = *(int *)(a1 + 4);
HIDWORD(v9) = *(int *)(a2 + 12);
v7 = 0xC6EF3720;
LODWORD(v9) = v2; //v9=0x76543210FEDCBA98
do
{
v6 -= ((v5 >> 5) + HIDWORD(v9)) ^ (16 * v5 + v2) ^ (v5 + v7);
v5 -= ((v6 >> 5) + v4) ^ (16 * v6 + v3) ^ (v6 + v7);
v7 += 0x61C88647;
} while (v7 != 0);
*(int *)a1 = v5;
*(int *)(a1 + 4) = v6;
return v9;
}
tea算法还可以进行魔改,魔改的地方主要是DELTA值,将这个值修改会让很多加密算法识别软件失效,像下面的程序就将DELTA魔改为0x1234567,绕过来peid的插件KANAL的识别。
补充TEA及魔改TEA加密与解密源码:
初级TEA
#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; /* 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;
}
int main()
{
uint32_t v[2]={1,2},k[4]={2,2,3,4};
// v为要加密的数据是两个32位无符号整数
// k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
printf("加密前原始数据:%u %u\n",v[0],v[1]);
encrypt(v, k);
printf("加密后的数据:%u %u\n",v[0],v[1]);
decrypt(v, k);
printf("解密后的数据:%u %u\n",v[0],v[1]);
return 0;
}
TEA升级版XTEA,增加了更多的密钥表,移位和异或等操作。
#include <stdio.h>
#include <stdint.h>
/* take 64 bits of data in v[0] and v[1] and 128 bits of key[0] - key[3] */
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;//num_rounds建议取值为32
// v为要加密的数据是两个32位无符号整数
// k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
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;
}
————————————————
XXTEA,又称Corrected Block TEA,是XTEA的升级版
#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 btea(uint32_t *v, int n, uint32_t const key[4])
{
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1) /* Coding Part */
{
rounds = 6 + 52/n;
sum = 0;
z = v[n-1];
do
{
sum += DELTA;
e = (sum >> 2) & 3;
for (p=0; p<n-1; p++)
{
y = v[p+1];
z = v[p] += MX;
}
y = v[0];
z = v[n-1] += MX;
}
while (--rounds);
}
else if (n < -1) /* Decoding Part */
{
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]= {1,2};
uint32_t const k[4]= {2,2,3,4};
int n= 2; //n的绝对值表示v的长度,取正表示加密,取负表示解密
// v为要加密的数据是两个32位无符号整数
// k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
printf("加密前原始数据:%u %u\n",v[0],v[1]);
btea(v, n, k);
printf("加密后的数据:%u %u\n",v[0],v[1]);
btea(v, -n, k);
printf("解密后的数据:%u %u\n",v[0],v[1]);
return 0;
}