前几天我跟我队友写了一道逆向,说是逆向题其实是个密码学的题目
是这样的:
出题人构造了一个 AES cipher
给出了密钥(key),明文(plainText),密文(cipherText),使用的是 密码分组链接 CBC(Chiper Block Chaining) 模式。要求出 初始化向量 IV(Initalization Vector)
其实要是熟悉 CBC 模式的话很快就能求出来。
下面是 CBC 的加密流程
加密:
PlainText = pad(PlainText)
enc_msg = xor(PlainText, IV)
CipherText = encrypt(key, enc_msg)
解密:
解密是加密的逆过程
fake_msgN = encrypt(key, CipherTextN)
PlainTextN = xor(key, CipherTextN-1)
现在看题目
之前我写的题目是道逆向题,.net 写的,为了方便,这个题目是我用 python 复现的
from Crypto.Cipher import AES
key = "09e6855d293a1b86ff44f18948b19bac".decode("hex")
cipherText1 = "ed64978b91ef5b62561a44c8f529b91f".decode("hex")
cipherText = "fd6dd5e0f9ab258b2bc9c813177e3ad677116d2f08c69517d0e7796c1f5e06ba95c3de5a139bb687bf3e779a0730e47c".decode(
"hex")
plainText = "CBC_Cr4cked_succ"
iv = raw_input("give me iv :> ")
aes = AES.new(key, AES.MODE_CBC, iv)
aes1 = AES.new(key, AES.MODE_CBC, iv)
if aes.decrypt(cipherText1) == plainText:
flag = input("give me flag :> ")
if aes1.encrypt(flag) == cipherText:
print("you get it")
else:
print("nonono")
else:
print("nonono")
上面的可以得到的信息
key = "09e6855d293a1b86ff44f18948b19bac".decode("hex")
cipherText1 = "ed64978b91ef5b62561a44c8f529b91f".decode("hex")
cipherText = "fd6dd5e0f9ab258b2bc9c813177e3ad677116d2f08c69517d0e7796c1f5e06ba95c3de5a139bb687bf3e779a0730e47c".decode("hex")
plainText = "CBC_Cr4cked_succ"
iv = ‘‘
现在我们有了明文密文和密钥,直接逆向 CBC
步骤是这样的:
这里我要讲一下第 4,5 步 为什么使用伪造的 IV -- fakeIV 异或 再和 明文 异或就能得到 真的 IV 了呢
我们现在有了 key 和密文和明文,只要再构造一个 假的 IV -- fakeIV 就能构造起一个 Cipher,enc_msg(使用 key 加密后得到的) 异或 fakeIV 得到错误的明文(fakePlainText),只要把 fakePlainText 和 fakeIV 异或自然能得到 enc_msg。
像是:
1 ^ 11110 = 11111
11111 ^ 1 = 11110
其实仔细观察的话会发现 IV 和用 key 加密后的密文(enc_msg)和 明文(cipherText1)是异或(xor)关系。这样的话只要把 enc_msg 和 cipherText1 作异或运算就能得到 IV,因为 cipherText1 是使用正确 IV 加密过的。
这个是猜解 IV 的 demo 脚本:
iv 是随机的,运行后会发现 crackIV 和 iv 一样
import os
from Crypto.Cipher import AES
iv = os.urandom(16)
key = os.urandom(16)
def pad(plainText):
return plainText + (chr(len(plainText)) * (16 - (len(plainText) % 16)))
aes = AES.new(key, AES.MODE_CBC, iv)
plainText = raw_input(">")
print("plainText : " + pad(plainText).encode(‘hex‘))
cipherText = aes.encrypt(pad(plainText))
print("cipherText : " + cipherText.encode("hex"))
iv1 = "a" * 16
aes2 = AES.new(key, AES.MODE_CBC, iv1)
fakePlainText = aes2.decrypt(cipherText)
crackIV = ‘‘
for i in range(16):
crackIV += chr(ord(fakePlainText[i]) ^ ord(iv1[i]) ^ ord(pad(plainText)[i]))
print("True iv : " + iv.encode("hex"))
print("Crack iv : " + crackIV.encode("hex"))
回到上面的题目
题目的解:
from Crypto.Cipher import AES
def xor(p1, p2):
tmp = ‘‘
for i in range(len(p2)):
tmp += chr(ord(p1[i]) ^ ord(p2[i]))
return tmp
key = "\t\xe6\x85]):\x1b\x86\xffD\xf1\x89H\xb1\x9b\xac"
cipherText1 = "ed64978b91ef5b62561a44c8f529b91f".decode("hex")
cipherText = "fd6dd5e0f9ab258b2bc9c813177e3ad677116d2f08c69517d0e7796c1f5e06ba95c3de5a139bb687bf3e779a0730e47c".decode("hex")
plainText = "CBC_Cr4cked_succ"
fakeIV = "aaaaaaaaaaaaaaaa"
fakeIVAes = AES.new(key, AES.MODE_CBC, fakeIV)
fakePlainText = fakeIVAes.decrypt(cipherText1)
enc_msg = xor(fakePlainText, fakeIV)
iv = xor(enc_msg, plainText)
print len(iv)
print "iv is : " + iv
aes = AES.new(key, AES.MODE_CBC, iv)
flag = aes.decrypt(cipherText)
print flag
flag:we_ax{cr4ck_43s_CBC_Cr4cked_succ3ssfu11y!_asdfg}
一道通过密文明文求解 IV 的密码学题目(crack AES-CBC IV)
原文:https://www.cnblogs.com/crybaby/p/12940219.html