Crypto知识 S
Crypto知识 S
Hash
Hash是将任意长度的消息压缩成固定长度散列值的算法。常见的Hash加密算法有MD5,SHA系列等等。
由于Hash算法不可逆,所以想要获得原消息基本上是采取正向爆破的方法。方法有使用python脚本和Hashcat。
Hashcat
比如现在知道hash值是2d6c7ed3df6905dfeb89a99e7322eadd5482f1295679416bfe3e9cea1a63243d,消息是九位,前三位是ycF,sha256加密(-m 1400)。那么使用命令(-a 3掩码攻击):
.\hashcat.exe -a 3 -m 1400 --force 2d6c7ed3df6905dfeb89a99e7322eadd5482f1295679416bfe3e9cea1a63243d ycF?a?a?a?a?a?a
可以爆破原文为ycFm@5t3r。
python
import itertools
#import hmac
key = '2100'
dir = '1234567890'//爆破所用到的字典,这里猜全是数字
dir_list = itertools.product(dir, repeat=6)
for i in dir_list:
data=i[0]+i[1]+i[2]+i[3]+i[4]+i[5]
secrets=sha256((key+data).encode('utf-8')).hexdigest()
if(secrets=='3a5137149f705e4da1bf6742e62c018e3f7a1784ceebcb0030656a2b42f50b6a'):
print(data)
break
识别
一般Py、Java、C#这些都有Hash相关库,直接看名字。
不过还有加盐哈希之类的,暂时还没遇到。
之前看到做Crypto的大佬听绿wyc做hash相关密码题,还有什么维纳攻击,真是可怕呀这群人.jpg
TEA家族
其实TEA算法的难点(对个人)不在于设计算法,毕竟加密那三步倒过来就是解密,而在于从IDA Pro里面提取正确的数据,编写exp的时候也要注意数据类型......感觉除了那种密码里面的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加密的单位是一个8bytes即64bits大小的整数,v[0],v[1]分别是32bits。然而我们通过IDA Pro获取到的往往是unsigned char类型的数组。因此我们在用C/C++编写exp的时候,应使用uint32_t*来对密文数组进行访问。例如Newstar 2024 week2 drink_tea的exp:
#include<stdio.h>
#include<stdint.h>
using namespace std;
void decrypt(uint32_t *v,uint32_t *k)
{
uint32_t delta=2654435769;
uint32_t v0=v[0],v1=v[1],sum=(32)*delta;
for(int i=0;i<32;i++)
{
v1 -= (k[3] + (v0 >> 5)) ^ (sum + v0) ^ (k[2] + 16 * v0);
v0 -= (k[1] + (v1 >> 5)) ^ (sum+ v1) ^ (*k + 16 * v1);
sum-=delta;
}
v[0]=v0;
v[1]=v1;
}
int main()
{
unsigned char key[]="WelcomeToNewStar";
unsigned char enc[] =
{
0x78, 0x20, 0xF7, 0xB3, 0xC5, 0x42, 0xCE, 0xDA, 0x85, 0x59,
0x21, 0x1A, 0x26, 0x56, 0x5A, 0x59, 0x29, 0x02, 0x0D, 0xED,
0x07, 0xA8, 0xB9, 0xEE, 0x36, 0x59, 0x11, 0x87, 0xFD, 0x5C,
0x23, 0x24
};
uint32_t* k=(uint32_t*)key;
uint32_t* v=(uint32_t*)enc;
for(int i=0;i<8;i+=2)
{
decrypt(v+i,k);
}
for(int i=0;i<32;i++)
printf("%c",enc[i]);
return 0;
}
//flag{There_R_TEA_XTEA_and_XXTEA}
值得注意的有几点:
1.从21~28行可见key与enc是unsigned char类型的数组;
2.从29~30行可见,分别使用了k,v两个uint32_t类型的指针指向两个unsigned char数组的首地址。
3.循环时,v的地址变化是0,2,4,6,共有四组,这意味着enc数组中的32个字符被分为4组,每组8个作为一个64位整数进行加密。
XTEA
XTEA是TEA的加强版。
与TEA类似,XTEA加密中的重要数据有:密钥,δ,轮数等。
这里的密钥可以是128bits,256bits,512bits等等。而δ和轮数也一般是黄金分割率和32/64轮。
其实跟TEA没有太大区别,只是每轮加密算法稍微复杂一些,写exp的思路也没有变,就是照猫画虎倒着写:
#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
进一步加强,key的长度可以不是4的倍数了。
#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;
}
改天贴几道XTEA和XXTEA的例题。