TEA/XTEA/XXTEA系列算法


前言:自己有時間做了幾道攻防世界的幾道逆向題目,發現TEA系列的算法是很常見的,這里的話就想順便學習下

TEA算法

TEA算法介紹

"TEA" 的全稱為"Tiny Encryption Algorithm" 是1994年由英國劍橋大學的David j.wheeler發明的。

TEA算法也算是一種微型加密算法的。

在安全學領域,TEA(Tiny Encryption Algorithm)是一種分組加密算法,它的實現非常簡單,通常只需要很精短的幾行代碼。

TEA算法使用64位的明文分組和128位的密鑰,它使用Feistel分組加密框架,需要進行64輪迭代,但是作者認為32輪已經足夠了,所以32輪迭代加密后最后得到的密文就是64位

簡單的說就是,TEA加密解密是以原文以8字節(64位bit)為一組,密鑰16字節(128位bit)為一組,(char為1字節,int為4字節,double為8字節),該算法加密輪次可變,作者建議為32輪,因為被加密的明文為64位,所以最終加密的結果也是64位。

該算法使用了一個神秘常數δ作為倍數,它來源於黃金比率,以保證每一輪加密都不相同。但δ的精確值似乎並不重要,這里TEA把它定義為 δ=「(√5 - 1)231」,這個δ對應的數指就是0×9E3779B9,所以這個值在TEA加密或者解密中會有用到。

TEA算法圖解分析

TEA算法的圖解如下圖所示

從圖解中可以看到運算有加法運算,位運算,異或運算。

流程1:

1、首先TEA加密解密是以原文以8字節,所以從兩邊各自傳入四個字節

2、右邊傳入的4個字節,這里將這4個字節稱呼為M,M進行了三個部分的操作,M左移4位與密鑰[0]相加,M右移5位與密鑰[1]相加,M與δ相加,最后這三個算出的值再異或

3、左邊傳入的4個字節,這里將這4個字節稱呼為N,N=N+M
流程2:

接着就到了下面這個部分,這里的話M和N交換了位置,

2、右邊傳入的4個字節,N進行了三個部分的操作,N左移4位與密鑰[2]相加,N右移5位與密鑰[3]相加,N與δ相加,最后這三個算出的值再異或

3、左邊傳入的4個字節,M=M+N

4、此時拿到的M和N就是加密過后的M和N

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算法逆向

1、tea算法的特征就是DELTA值和十六個字節的密鑰(也就是128位)。

2、在逆向程序的時候,可以利用ida的插件findcypto識別tea算法

3、x-=0x61c88647和x+=0x9e3779b9,這兩個值是等價的,可能會在反匯編中看到

這里將上面測試的代碼編譯好拖入IDA中進行觀察

可以看到δ就被反編譯為v4 -= 1640531527;

但是反匯編中就是0x9e3779b9,如下圖所示

我們這里用findcypto插件來進行識別測試,0x9e3779b9特征碼被識別,如下圖所示

TEA算法的變化技巧

前面有提到關於"但δ的精確值似乎並不重要",所以δ的值不一定需要0x9E3779B9,所以這里的話在加密解密的時候可以改變這個δ的值,改了之后就會導致部分識別加密的工具失效來達到算法魔改的目的。

測試代碼,改變其中的δ的值

//加密函數
void encrypt(uint32_t* v, uint32_t* k) {
	uint32_t v0 = v[0], v1 = v[1], sum = 0, i;           /* set up */
	uint32_t delta = 0x12345678;                     /* 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 = 0x468acf00, i;  /* set up */
	uint32_t delta = 0x12345678;                     /* 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;
}

這里將上面測試的代碼編譯好拖入IDA中進行觀察,可以看到這個插件就無法識別出TEA算法了,因為改了0x9E3779B9特征碼

騰訊TEA算法分析

每次處理64位數據,使用128位密鑰。數據和密鑰都分割成32為無符號整型處理。

不同點:TEA標准中使用的32輪加密,而騰訊只用了16輪。

可以看到其他都一樣的,就是迭代次數為16次

#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 < 16; 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], i;  /* set up */
    uint32_t delta=0x9e3779b9;                     /* a key schedule constant */
    uint32_t sum = delta << 4;
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
    for (i=0; i<16; 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;
}

XTEA算法

XTEA算法介紹

XTEA算法也被稱作為Corrected Block TEA

XTEA是TEA的升級版,增加了更多的密鑰表,移位和異或操作等等,設計者是Roger Needham, David Wheeler

之后 TEA 算法被發現存在缺陷,作為回應,設計者提出了一個 TEA 的升級版本——XTEA(有時也被稱為"tean")。XTEA 跟 TEA 使用了相同的簡單運算,但它采用了截然不同的順序,為了阻止密鑰表攻擊,四個子密鑰(在加密過程中,原 128 位的密鑰被拆分為 4 個 32 位的子密鑰)采用了一種不太正規的方式進行混合,但速度更慢了。

XTEA算法圖解

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算法

XXTEA算法介紹

XXTEA就被稱作為Corrected Block TEA。

特點:原字符串長度可以不是4的倍數了

XXTEA算法圖解

XXTEA算法實現

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM