TEA

TEA加密算法

TEA加密算法与C比较相关,其实是我的python功力不过关,所以本篇文章使用C++来展示TEA的代码实现,及其解密

不过多介绍历史,维基百科

基本介绍

微型加密算法(Tiny Encryption Algorithm,TEA)是一种对称分组密码算法,它以实现简单、代码量小、运算速度快著称,非常适合资源受限的环境。

基本参数

分组长度:64 位(8 字节)

密钥长度:128 位(16 字节)

结构:Feistel 网络

轮数:64 轮(通常实现为 32 个循环,每个循环包含两轮)

基本运算

  • 加法(模 $2^{32}$)
  • 异或(XOR)
  • 左移、右移

加密过程

明文分组

首先将明文进行分组,将一个 64 位明文分为两个 32 位数据块

分成v0以及v1,一般是前半部分是v0,后半部分是v1

v0和v1构成一个数据分组

密钥分组

128 位密钥分为四个 32 位子密钥

key[0] key[1] key[2] key[3]

每轮进行以下运算

sum += delta

v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1)

v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3)

其中

delta = 0x9E3779B9

这个值是根据黄金比例构造的常数,用于避免轮函数出现规律性。

值得注意的是

delta的值并不是固定的,它通常可以被开发者所修改,而且轮运算的过程,也能略微进行修改

比如说(v1 << 4)4是可供修改的值,(v1 >> 5)中的5也是同样可以修改的值

当然也可修改单元运算,具体情况具体分析

使用时候的注意事项

密钥固定要求为128位,即16字节

TEA 每次只能处理 8 字节数据。v0+v1=8字节

如果明文的总长度不是8字节的整数倍,那么需要进行填充

C++代码实现加密

直接上demo

为了确保结果直观,TEA没有出错,也为了逆向工程,我们同时写一个解密函数来证明数据正确加密了

#include<iostream>
#include<cstdint>
#include<Windows.h>
using namespace std;


void TEAencrypt(uint32_t *v,uint32_t *key)
{
    uint32_t v0=*v;
    uint32_t v1=v[1];
    uint32_t sum=0;
    uint32_t delta=0x9e3779b9;
    for(int i=0;i<32;i++)
    { 
        sum += delta;
        v0 += ((v1 << 4) + *key) ^ (v1 + sum) ^ ((v1 >> 5) + key[1]);//一个轮加密
        v1 += ((v0 << 4) + key[2]) ^ (v0 + sum) ^ ((v0 >> 5) + key[3]);//两个轮加密
    }//循环32次,共进行64轮加密
    v[0]=v0; v[1]=v1;
}

void decrypt(uint32_t *v,uint32_t *key)
{
    uint32_t v0=v[0];
    uint32_t v1=v[1];
    uint32_t sum=0xC6EF3720;
    uint32_t delta=0x9e3779b9;
    for(int i=0;i<32;i++)
    {
        v1 -= ((v0 << 4) + key[2]) ^ (v0 + sum) ^ ((v0 >> 5) + key[3]);
        v0 -= ((v1 << 4) + *key) ^ (v1 + sum) ^ ((v1 >> 5) + key[1]);
        sum -= delta;
    }
    v[0]=v0; v[1]=v1;

}

int main()
{
     SetConsoleOutputCP(CP_UTF8); 
     SetConsoleCP(CP_UTF8);
     uint32_t data[]={0x11223344, 0x55667788};//密钥长度要是8字节的整数倍
     uint32_t key[]={0x11223344, 0x55667788, 0x99aabbcc, 0xddeeff00};//key的长度固定为128位,16字节
     TEAencrypt(data,key);
     cout<<"加密后的密文为:"<<hex<<data[0]<<" "<<data[1]<<endl;
     decrypt(data,key);
     cout<<"解密后的明文为:"<<hex<<data[0]<<" "<<data[1]<<endl;
     uint32_t sum = 0;
     for(int i=0;i<32;i++)
     {
        sum+=0x9e3779b9;
     }
     cout<<"sum最后的值是:"<<sum<<endl;
     system("pause");

}
//加密后的密文为:d9e2cb2b 5be32685
//解密后的明文为:11223344 55667788
//sum最后的值是:c6ef3720

求sum的值是因为逆向需要

作者使用的是g++编译,字符串常量是UTF-8编码,终端是GBK编码,双击运行时候会出现乱码,所以使用了

    SetConsoleOutputCP(CP_UTF8); 
    SetConsoleCP(CP_UTF8);

让CMD能以UTF-8编码去解释字节

下面我们用一道例题来展示TEA解密

逆向工程部分

题目名称:[Reisen]NSSCTF2025入门题目-Tea

题目来源:NSSCTF

DIE看看成分

image-20260804170538093

可以用IDA打开一下,注意!!!下面的结果可能和你的IDA反编译结果不一样,我为了教学的直观性改了变量的名称

image-20260804170603094

 printf("please input flag:");
  scanf("%s", Str);
  Size = strlen(Str);
  v10 = (Size + 7) >> 3;
  v9 = 8 * v10 - 1;
  v3 = alloca(16 * ((8 * v10 + 15) >> 4));
  v8 = v5;
  memset(v5, 0, 8 * v10);
  memcpy(v8, Str, Size);

接收输入的flag做一些前置处理,这部分可以忽略不记,不在加密算法内

重点是下面的

tea_encrypt(&v6, key_1);

将输入的字符串进行处理,推测是TEA加密,进去看看

image-20260804170842779

是一个TEA加密,但是并不标准,存在魔改部分,下面我会指出魔改的地方

首先delta的值进行了修改,这里的delta的值是0x414554

然后轮运算也进行了修改,比如说

(16 * v1 + *key)

这里存在明显的修改,但是在实际逆向过程中,其实我们并不需要指出所有的魔改点,我们可以复用代码

TEA的解密十分简单,我们可以看到这里的加密是

sum += 4277588;
v0 += (v1 + sum) ^ (16 * v1 + *key) ^ ((v1 >> 5) + key[1]);
v1 += (v0 + sum) ^ (16 * v0 + key[2]) ^ ((v0 >> 5) + key[3]);

异或是可逆的运算可以不用修改,根据逆向思维,我们要求做加法前的数,就要减去它原本加上的值,加密顺序原本是v0先,v1后的话,解密理应就是v1先解密,v0先加密,sum的值同样如此,既然最先加了sum的值,那么再加密的时候它就是最后逆向的

因此一个轮运算的解密可以是

 uint32_t delta=0x414554;
    for(int i=0;i<32;i++)
    {
        sum+=delta;
    };
 for(int i=0;i<32;i++)
    {
        v1-= (v0 + sum) ^ (16 * v0 + key[2]) ^ ((v0 >> 5) + key[3]);
        v0 -= (v1 + sum) ^ (16 * v1 + *key) ^ ((v1 >> 5) + key[1]);
        sum -= delta;
    }

值得注意的是,sum的值在解密开始时已经经历了32轮累加delta的运算,因此此处的初始值也需要经过32轮累加运算

根据题目我们也可以找到,密文以及密钥

image-20260804171709697

使用export data可以快速导出c风格的数据

image-20260804171747793

key在题目中非常显眼,请自己去寻找

完整的EXP

#include <iostream>
#include <cstdint>
#include <windows.h>
using namespace std;
 
void decrypt(uint32_t *v,uint32_t *key)
{
    uint32_t v0=*v;
    uint32_t v1=v[1];
    uint32_t sum=0;
    uint32_t delta=0x414554;
    for(int i=0;i<32;i++)
    {
        sum+=delta;
    };
    for(int i=0;i<32;i++)
    {
        v1-= (v0 + sum) ^ (16 * v0 + key[2]) ^ ((v0 >> 5) + key[3]);
        v0 -= (v1 + sum) ^ (16 * v1 + *key) ^ ((v1 >> 5) + key[1]);
        sum -= delta;
    }
    v[0]=v0; v[1]=v1;
}


int main()
{
     SetConsoleOutputCP(CP_UTF8); 
     SetConsoleCP(CP_UTF8);
    uint8_t enc[] =
{
  0xE4, 0x6E, 0x00, 0xF0, 0x91, 0x73, 0x9A, 0xBE, 0xCA, 0xF1, 
  0x2A, 0x60, 0x0E, 0x8F, 0x74, 0x83, 0xE0, 0x8E, 0x6C, 0x34, 
  0xD7, 0x99, 0xDE, 0x36, 0x8B, 0x86, 0xC4, 0x90, 0xC2, 0x0B, 
  0xC4, 0x59
};
   uint8_t key[] =
{
  0xEF, 0xBE, 0xAD, 0xDE, 0x0D, 0xF0, 0xAD, 0xBA, 0xDE, 0xC0, 
  0xAD, 0xDE, 0xCC, 0x10, 0xAD, 0xDE
};
    for (int i = 0; i < sizeof(enc); i+=8)
    {
        decrypt((uint32_t*)(enc + i), (uint32_t*)key);
    }
    cout<<(char*)enc;
    system("pause");
}

结果就请自己运行试试看啦,如果你觉得本篇文章对你有帮助不妨点个赞,如果觉得存在问题欢迎在评论区以及私信作者

posted @ 2026-08-04 17:24  DrD1Di  阅读(2)  评论(0)    收藏  举报