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

 


免責聲明!

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



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