TEA这段时间遇到的是真多,有直接原始加密,也有 XTEA,XXTEA,更有在此上魔改的,之前也是能认出来,知道还是不够。
en,TEA加密解密脚本还是用 C 好一些,什么溢出之类不用考虑。
打印明文:
char* p = (char*)flag;
for (int j = 0; j < 8 * 4; j++)
{
printf("%c", *(p + j));
}
printf("}");
void print_char(int enc){
cout << (unsigned char)((enc >> 24) & 0xff);
cout << (unsigned char)((enc >> 16) & 0xff);
cout << (unsigned char)((enc >> 8) & 0xff);
cout << (unsigned char)(enc & 0xff);
}
第二种更通用吧。
TEA
也有可能是 64 轮迭代
def encrypt(v, k):
v0, v1 = v[0], v[1]
sum = 0
delta = 0x9e3779b9
k0, k1, k2, k3 = k[0], k[1], k[2], k[3]
for i in range(32):
sum = (sum + delta) & 0xffffffff
v0 = (v0 + (((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1))) & 0xffffffff
v1 = (v1 + (((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3))) & 0xffffffff
return [v0, v1]
#确保它们在 32 位整数范围内
if __name__ == "__main__":
data = [1234, 5678]
key = [1, 2, 3, 4]
enc = encrypt(data, key)
print(enc)
def decrypt(v,k):
v0,v1=v[0],v[1]
delta=0x9e3779b9
k0,k1,k2,k3=k[0],k[1],k[2],k[3]
sum=(delta*32)&0xffffffff
for i in range(32):
v1 = (v1 - (((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3))) & 0xffffffff
v0 = (v0 - (((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1))) & 0xffffffff
sum = (sum - delta) & 0xffffffff
v[0],v[1]=v0,v1
return v
if __name__=="__main__":
data=[731179895, 2211051369]
key=[1,2,3,4]
res=decrypt(data,key)
print(res)
在python中, 最好不要使用 “-=”,和 C 不同,害我改了半天,xp。
XTEA
就是每轮加密不同
def encrypt(v, k):
v0, v1 = v[0], v[1]
sum = 0
delta = 0x9e3779b9
k0, k1, k2, k3 = k[0], k[1], k[2], k[3]
for i in range(32):
v0=v0+((((v1<<4) ^ (v1>>5))+v1) ^ (sum+k[sum&3]))&0xffffffff
sum=(sum+delta)&0xffffffff
v1=v1+((((v0<<4) ^ (v0>>5))+v0) ^ (sum+k[(sum>>11)&3]))&0xffffffff
return [v0, v1]
#确保它们在 32 位整数范围内
if __name__ == "__main__":
data = [1234, 5678]
key = [1,2, 3, 4]
enc = encrypt(data, key)
print(enc)
key[sum & 3 ]
sum & 3 保证索引在 k0 到 k3 之间循环, 3 是 ‘11’,故只保留sum后两位
(sum + k[sum & 3])
这个操作首先将 sum
右移 11 位,然后再进行按位与操作 & 3
。这个操作同样可以确保结果在 0 到 3 之间,但它使用的是 sum
的第 12 和 13 位
def encrypt(v, k):
v0, v1 = v[0], v[1]
sum = (0x9e3779b9*32)&0xffffffff
delta = 0x9e3779b9
k0, k1, k2, k3 = k[0], k[1], k[2], k[3]
for i in range(32):
v1 = v1 - ((((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum >> 11) & 3])) & 0xffffffff
sum=(sum-delta)&0xffffffff
v0 = v0 - ((((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3])) & 0xffffffff
return [v0, v1]
#确保它们在 32 位整数范围内
if __name__ == "__main__":
data = [1787803488, 3495090297]
key = [1,2, 3, 4]
enc = encrypt(data, key)
print(enc)
XXTEA
有点复杂
还有 C 的版本:
例题:
[HNCTF 2022 WEEK2]TTTTTTTTTea
应该是XTEA加密
key 都是 32位数,故写成四个八位的数组
key=[0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f]
也可以按 D 换成 dw ,dd
唉,没几个大佬分析前面的,是我太菜了!
exp:
大佬都是用 C 写的,确实好写一些好像
为加强理解,我用 python写一个,还是有一点小问题:
enc = [0xC11EE75A, 0xA4AD0973, 0xF61C9018, 0x32E37BCD, 0x2DCC1F26, 0x344380CC]
def decrypt(enc1, enc2):
key = [0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f]
delta = 0x9e3779b9
sum = (delta * 32) & 0xffffffff
for i in range(32):
enc2 = (enc2 - ((((enc1 >> 5) ^ (enc1 << 4)) + enc1) ^ (key[(sum >> 11) & 3] + sum))) & 0xffffffff
sum = (sum - delta) & 0xffffffff
enc1 = (enc1 - ((((enc2 >> 5) ^ (enc2 << 4)) + enc2) ^ (key[sum & 3] + sum))) & 0xffffffff
return enc1, enc2
data = []
for i in range(0, 6, 2):
res1, res2 = decrypt(enc[i], enc[i + 1])
data.append(res1)
data.append(res2)
print(data)
for value in data:
print(chr((value >> 24) & 0xff) + chr((value >> 16) & 0xff) + chr((value >> 8) & 0xff) + chr(value & 0xff), end='')
#CSSNT{FTT_aeT_AET_Ae}+aE
啊!差了一点,去看看哪里有问题,啊,没找到
#include<stdio.h>
int main()
{
unsigned int enc[6] = { 0xC11EE75A, 0xA4AD0973, 0xF61C9018, 0x32E37BCD, 0x2DCC1F26, 0x344380CC };
unsigned int key[4] = { 0x10203, 0x4050607, 0x8090A0B, 0x0C0D0E0F };
int i, j;
long sum = 0, delta = 0x61C88647;
// 解码
for (i = 0; i < 6; i += 2) {
sum = 0 - (32 * delta);
for (j = 0; j < 32; j++) {
enc[i + 1] -= (((enc[i] >> 5) ^ (16 * enc[i])) + enc[i]) ^ (key[((sum >> 11) & 3)] + sum);
sum += delta;
enc[i] -= ((((enc[i + 1] >> 5) ^ (16 * enc[i + 1])) + enc[i + 1]) ^ key[sum & 3] + sum);
}
}
// 打印
for (i = 0; i < 6; i++)
{
for (j = 0; j <= 3; j++)
{
printf("%c", (enc[i] >> (j * 8)) & 0xFF);
}
}
return 0;
}
[MoeCTF 2022]ezTea
#include <stdio.h>
#include <stdint.h>
void encrypt (uint32_t* v, uint32_t* k) { // 主要加密函数,试着搞定它
uint32_t v0 = v[0], v1 = v[1], sum = 0;
uint32_t delta = 0xd33b470;
for (int i = 0; i < 32; i++) {
sum += delta;
v0 += ((v1<<4) + k[0]) ^ (v1 + sum) ^ ((v1>>5) + k[1]);
v1 += ((v0<<4) + k[2]) ^ (v0 + sum) ^ ((v0>>5) + k[3]);
}
v[0] = v0;
v[1] = v1;
}
void decrypt(uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1], sum = 0;
uint32_t delta = 0xd33b470*32;
for (int i = 0; i < 32; i++) {
v1 -= ((v0 << 4) + k[2]) ^ (v0 + sum) ^ ((v0 >> 5) + k[3]);
v0 -= ((v1 << 4) + k[0]) ^ (v1 + sum) ^ ((v1 >> 5) + k[1]);
sum -= delta;
}
v[0] = v0;
v[1] = v1;
}
int main() {
uint32_t k[4] = {1, 2, 3, 4};
int8_t input[33] = { 0x17, 0x65, 0x54, 0x89, 0xed, 0x65, 0x46, 0x32, 0x3d, 0x58, 0xa9, 0xfd, 0xe2, 0x5e,
0x61, 0x97, 0xe4, 0x60, 0xf1, 0x91, 0x73, 0xe9, 0xe9, 0xa2, 0x59, 0xcb, 0x9a, 0x99,
0xec, 0xb1, 0xe1, 0x7d };
scanf("%32s", input);
for (int i = 0; i < 32; i+=8) {
uint32_t v[2] = {*(uint32_t *)&input[i], *(uint32_t *)&input[i+4]};
decrypt(v, k);
for (int j = 0; j < 2; j++) { // 这一段主要是把 v 按单字节输出,另外可以了解一下 “大小端序” 在这题是如何体现的
for (int k = 0; k < 4; k++) {
printf("%#x, ", v[j] & 0xff);
v[j] >>= 8;
}
}
}
return 0;
}
直接对照 encrypt()函数来写 decrypt()函数,然后修改一些问题。
#include <stdio.h>
#include <stdint.h>
void encrypt(uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1], sum = 0;
uint32_t delta = 0xd33b470;
for (int i = 0; i < 32; i++) {
sum += delta;
v0 += ((v1 << 4) + k[0]) ^ (v1 + sum) ^ ((v1 >> 5) + k[1]);
v1 += ((v0 << 4) + k[2]) ^ (v0 + sum) ^ ((v0 >> 5) + k[3]);
}
v[0] = v0;
v[1] = v1;
}
void decrypt(uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1];
uint32_t delta = 0xd33b470;
uint32_t sum = delta * 32;
for (int i = 0; i < 32; i++) {
v1 -= ((v0 << 4) + k[2]) ^ (v0 + sum) ^ ((v0 >> 5) + k[3]);
v0 -= ((v1 << 4) + k[0]) ^ (v1 + sum) ^ ((v1 >> 5) + k[1]);
sum -= delta;
}
v[0] = v0;
v[1] = v1;
}
int main() {
uint32_t k[4] = { 1, 2, 3, 4 };
uint8_t input[33] = { 0x17, 0x65, 0x54, 0x89, 0xed, 0x65, 0x46, 0x32, 0x3d, 0x58, 0xa9, 0xfd, 0xe2, 0x5e,
0x61, 0x97, 0xe4, 0x60, 0xf1, 0x91, 0x73, 0xe9, 0xe9, 0xa2, 0x59, 0xcb, 0x9a, 0x99,
0xec, 0xb1, 0xe1, 0x7d };
//scanf("%32s", input);
for (int i = 0; i < 32; i += 8) {
uint32_t v[2] = { *(uint32_t*)&input[i], *(uint32_t*)&input[i + 4] };
decrypt(v, k);
for (int j = 0; j < 2; j++) {
for (int b = 0; b < 4; b++) {
printf("%c", (v[j] >> (8 * b)) & 0xff);
}
}
}
return 0;
}
//moectf{Th3_TEA_!S_s0_t4s7y~~!!!}
[HGAME 2023 week1]a_cup_of_tea
难道每一个 Buf2[i]都进行了TEA加密?
si128 = _mm_load_si128((const __m128i *)&xmmword_1400022B0);
英特尔的 SIMD指令集的一个SSE2指令,从内存中加载一个 128 位的整数向量到一个 __m128i 类型的寄存器中 .
先得到 key
ant='0x45678901345678902345678912345678'[2:]
print(ant)
print(len(ant))
key=[]
for i in range(0,len(ant),8):
key.append(int(ant[i:i+8],16))
print(key)
开始写脚本时发现好像不是标准的 TEA 加密,不对就是的
然后 v10 也不知道是干嘛的,还有 scanf 输入的字符存在哪,在 v10 吗?
还需要动调一下,看看,先在加密前下个断点,判断处下一个
输入了 50 个字符,v10前面有 16 个字符,是给 Buf1 的,后面 34个好像都是 v10的。
嗯,输入是有50个的限制,v10最多就34个。
首先第一个问题:
嗯,前面是我想错了,每两个Buf2对应一个 TEA,刚好8个,调用了四次。
int v1 = buf & 0xffff; //低十六位
int v2 = (buf >> 16) & 0xffff; // 先右移高十六位变低十六位,再去除前面
en,第二个:前面 key 忘记端序的问题了
str='hello' print(str[::-1])
ant='0x45678901345678902345678912345678'[2:]
print(ant)
print(len(ant))
key=[]
for i in range(0,len(ant),8):
key.append(int(ant[len(ant)-8-i:len(ant)-i],16))
print(key)
#[305419896, 591751049, 878082192, 1164413185]
第三个:
C版本中的 uint32_t
和 C++ 版本中的 int
,它们的位宽可能不一致。
第四个:
delta的问题:
好像是要防止什么溢出的问题;
delta*32
#include <iostream>
#include <cstdint>
using namespace std;
int main() {
int32_t delta = 0x543210DD; // 初始化 delta
int64_t sum = -(delta * 32LL); // 使用 64 位整型计算 sum,避免溢出
uint32_t final_sum = static_cast<uint32_t>(sum); // 将 sum 转换为无符号 32 位整数
std::cout << "sum = 0x" << std::hex << final_sum << std::endl;
// 从 sum 计算 delta
int32_t delta_from_sum = final_sum / 32;
std::cout << "delta = 0x" << std::hex << delta_from_sum << std::endl;
return 0;
}
得到flag。
[GDOUCTF 2023]Tea
7个数,不太合理
这是得到的密文
直接微调代码,写出解密脚本:
#include <iostream>
using namespace std;
int main() {
unsigned int enc[10];
enc[0] = 0x1A800BDA;
enc[1] = 0xF7A6219B;
enc[2] = 0x491811D8;
enc[3] = 0xF2013328;
enc[4] = 0x156C365B;
enc[5] = 0x3C6EAAD8;
enc[6] = 0x84D4BF28;
enc[7] = 0xF11A7EE7;
enc[8] = 0x3313B252;
enc[9] = 0xDD9FE279;
int v3; // [rsp+44h] [rbp+24h]
int i; // [rsp+64h] [rbp+44h]
unsigned int v5; // [rsp+84h] [rbp+64h]
unsigned int v6;
int key[4] = { 2233,4455,6677,8899 };
for (i = 0; i <= 8; ++i) // 应该要进行九次TEA加密
{
v5 = 0;
// v6 = 0xF462900 * i * 33;
v6 = 0xF462900 * (i + 33);
v3 = i + 1;
do
{
++v5;
v6 -= 0xF462900;
enc[i + 1] -= (v6 + key[((v6 >> 11) & 3)]) ^ (enc[i] + ((enc[i] >> 5) ^ (16 * enc[i])));
//*(enc + 4i64 * i) += v6 ^ (*(enc + 4i64 * v3) + ((*(enc + 4i64 * v3) >> 5) ^ (16 * *(enc + 4i64 * v3)))) ^ (v6 + *(key + 4i64 * (v6 & 3)));
enc[i] -= v6 ^ ((enc[i + 1]) + ((enc[i + 1] >> 5) ^ (16 * enc[i + 1]))) ^ (v6 + key[v6 & 3]);
/* *(enc + 4i64 * v3) += (v6 + *(key + 4i64 * ((v6 >> 11) & 3))) ^ (*(enc + 4i64 * i)
+ ((*(enc + 4i64 * i) >> 5) ^ (16
* *(enc + 4i64 * i))));*/
} while (v5 <= 32);
}
for (int i = 0; i < 10; i++) {
//cout << enc[i]<<endl;
printf("%08x", enc[i]);
}
cout << endl;
//438fdda6f4c68c79c2815bf8e85dc4e1b010d0013bf4357f65ef9185635d747c982d9a24b9b3e05
return 0;
}
但遇到三个问题:
一,忘记逆序
应该是,不是 i=0;i<8;i++
二, 解密时 sum 的初始值
// v6 = 0xF462900 * i * 33;
v6 = 0xF462900 * (i + 33);
仔细想想确实是的:每次加密迭代的初始值 v6
包括了一个基数 33
,从而避免小的 i
值导致的弱加密。这也确保了每次迭代都从一个较高的起点开始,有助于增强加密强度。
并且如果是第一种,i=0时,sum=0;肯定不对。
三,最后想加一个直接转换成字符串的操作
for (int i = 0; i < 10; i++) {
cout << (unsigned char)((enc[i] >> 24) & 0xff);
cout << (unsigned char)((enc[i] >> 16) & 0xff);
cout << (unsigned char)((enc[i] >> 8) & 0xff);
cout << (unsigned char)(enc[i] & 0xff);
}
这个操作是正确的,但是加上有问题:
enc打印直接变了:
f4c68c79c2815bf8e85dc4e1b010d0013bf4357f65ef9185635d747c982d9a24b9b3e05
这个不知道为什么
但是第一个问题解决再加上去是没问题的
最终exp:
#include <iostream>
using namespace std;
int main() {
unsigned int enc[10];
enc[0] = 0x1A800BDA;
enc[1] = 0xF7A6219B;
enc[2] = 0x491811D8;
enc[3] = 0xF2013328;
enc[4] = 0x156C365B;
enc[5] = 0x3C6EAAD8;
enc[6] = 0x84D4BF28;
enc[7] = 0xF11A7EE7;
enc[8] = 0x3313B252;
enc[9] = 0xDD9FE279;
int v3; // [rsp+44h] [rbp+24h]
int i; // [rsp+64h] [rbp+44h]
unsigned int v5; // [rsp+84h] [rbp+64h]
unsigned int v6;
int key[4] = { 2233,4455,6677,8899 };
for (i = 8; i >= 0; i--) // 应该要进行九次TEA加密
{
v5 = 0;
// v6 = 0xF462900 * i * 33;
v6 = 0xF462900 * (i + 33);
v3 = i + 1;
do
{
++v5;
v6 -= 0xF462900;
enc[i + 1] -= (v6 + key[((v6 >> 11) & 3)]) ^ (enc[i] + ((enc[i] >> 5) ^ (16 * enc[i])));
//*(enc + 4i64 * i) += v6 ^ (*(enc + 4i64 * v3) + ((*(enc + 4i64 * v3) >> 5) ^ (16 * *(enc + 4i64 * v3)))) ^ (v6 + *(key + 4i64 * (v6 & 3)));
enc[i] -= v6 ^ ((enc[i + 1]) + ((enc[i + 1] >> 5) ^ (16 * enc[i + 1]))) ^ (v6 + key[v6 & 3]);
/* *(enc + 4i64 * v3) += (v6 + *(key + 4i64 * ((v6 >> 11) & 3))) ^ (*(enc + 4i64 * i)
+ ((*(enc + 4i64 * i) >> 5) ^ (16
* *(enc + 4i64 * i))));*/
} while (v5 <= 32);
}
for (int i = 0; i < 10; i++) {
//cout << enc[i]<<endl;
printf("%08x", enc[i]);
}
cout << endl;
for (int i = 0; i < 10; i++) {
cout << (unsigned char)((enc[i] >> 24) & 0xff);
cout << (unsigned char)((enc[i] >> 16) & 0xff);
cout << (unsigned char)((enc[i] >> 8) & 0xff);
cout << (unsigned char)(enc[i] & 0xff);
}
return 0;
}
[FSCTF 2023]Tea_apk
package com.tutdroid;
import java.io.UnsupportedEncodingException;
/* loaded from: classes.dex */
public final class FlagChecker {
static final /* synthetic */ boolean $assertionsDisabled = false;
private static final int DELTA = -1640531527;
private static int MX(int i, int i2, int i3, int i4, int i5, int[] iArr) {
return ((i ^ i2) + (iArr[(i4 & 3) ^ i5] ^ i3)) ^ (((i3 >>> 5) ^ (i2 << 2)) + ((i2 >>> 3) ^ (i3 << 4)));
}
private FlagChecker() {
}
public static final byte[] encrypt(byte[] bArr, byte[] bArr2) {
return bArr.length == 0 ? bArr : toByteArray(encrypt(toIntArray(bArr, true), toIntArray(fixKey(bArr2), false)), false);
}
public static final byte[] encrypt(String str, String str2) {
try {
return encrypt(str.getBytes("UTF-8"), str2.getBytes("UTF-8"));
} catch (UnsupportedEncodingException unused) {
return null;
}
}
public static final String encryptToBase64String(String str, String str2) {
byte[] encrypt = encrypt(str, str2);
if (encrypt == null) {
return null;
}
return Base64.encode(encrypt);
}
private static int[] encrypt(int[] iArr, int[] iArr2) {
int length = iArr.length - 1;
if (length < 1) {
return iArr;
}
int i = (52 / (length + 1)) + 6;
int i2 = iArr[length];
int i3 = 0;
while (true) {
int i4 = i - 1;
if (i <= 0) {
return iArr;
}
i3 += DELTA;
int i5 = (i3 >>> 2) & 3;
int i6 = i2;
int i7 = 0;
while (i7 < length) {
int i8 = i7 + 1;
i6 = iArr[i7] + MX(i3, iArr[i8], i6, i7, i5, iArr2);
iArr[i7] = i6;
i7 = i8;
}
i2 = MX(i3, iArr[0], i6, i7, i5, iArr2) + iArr[length];
iArr[length] = i2;
i = i4;
}
}
private static byte[] fixKey(byte[] bArr) {
if (bArr.length == 16) {
return bArr;
}
byte[] bArr2 = new byte[16];
if (bArr.length < 16) {
System.arraycopy(bArr, 0, bArr2, 0, bArr.length);
} else {
System.arraycopy(bArr, 0, bArr2, 0, 16);
}
return bArr2;
}
private static int[] toIntArray(byte[] bArr, boolean z) {
int[] iArr;
int length = (bArr.length & 3) == 0 ? bArr.length >>> 2 : (bArr.length >>> 2) + 1;
if (z) {
iArr = new int[length + 1];
iArr[length] = bArr.length;
} else {
iArr = new int[length];
}
int length2 = bArr.length;
for (int i = 0; i < length2; i++) {
int i2 = i >>> 2;
iArr[i2] = iArr[i2] | ((bArr[i] & 255) << ((i & 3) << 3));
}
return iArr;
}
private static byte[] toByteArray(int[] iArr, boolean z) {
int length = iArr.length << 2;
if (z) {
int i = iArr[iArr.length - 1];
int i2 = length - 4;
if (i < i2 - 3 || i > i2) {
return null;
}
length = i;
}
byte[] bArr = new byte[length];
for (int i3 = 0; i3 < length; i3++) {
bArr[i3] = (byte) (iArr[i3 >>> 2] >>> ((i3 & 3) << 3));
}
return bArr;
}
public static boolean check(String str) {
return encryptToBase64String(str, "ABvWW7hqwNvHUhfP").equals("vlgg9nNjUcYuWzBSSOwKxbMD2rhFgf4zuiyMpLxpNkM=");
}
}
太长了,看不了一点。
看 wp:就是原封不动的 XXTEA (刚好还没看的),去学吧。