这道题来自NewStar CTF
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| from Crypto.Cipher import AES from Crypto.Util.number import * import os
KEY = b"fake_key_fake_ke" FLAG = "flag{fake_flag_fake_flag}"
def decrypt(c): AES_ECB = AES.new(KEY, AES.MODE_ECB) decrypted = AES_ECB.decrypt(long_to_bytes(c))
return decrypted.hex()
def encrypt(): iv = os.urandom(16) AES_CBC = AES.new(KEY, AES.MODE_CBC, iv) encrypted = AES_CBC.encrypt(FLAG.encode()) print('iv:',iv.hex())
return iv.hex() + encrypted.hex()
c=encrypt() print('encrypt:',c) print('decrypt:',decrypt(int(c,16)))
''' 什么都会做?那就去学习一下AES吧…… 我这次就先给你解一下好了,不用谢喵 decrypt: f9899749fec184d81afecd35da430bc394686e847d72141b3a955a4f6e920e7d91cb599d92ba2a6ba51860bb5b32f23b 这对吗?哦不对不对,哦对的对的。 '''
|
可以看到加密使用CBC模式,解密是用ECB模式,这样肯定是会出错的,我们先要想想这么操作会发生什么?
CBC依赖于初始向量IV和key,每个后续块依赖于前一个加密块(通过 XOR 操作,先异或再单独加密)
ECB只有单一的key,解密特点是一对一,也就是说解密是块独立的
我们需要先将这两个字符串转换成字节形式并分块(这里是16字节一块),方便AES后续计算
由于CBC解密时,是当前块先解密再和前一个加密块异或,那么现在当前独立的解密块知道了,前一个加密块也知道了,不久可以进行还原了吗
这里还有一个细节,因为出题人是将iv加在前面的,而又因为16个字节一组,所以这并不影响我们获取flag,不用管加密的第一组块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| from binascii import unhexlify
cbc_en = 'f2040fe3063a5b6c65f66e1d2bf47b4cddb206e4ddcf7524932d25e92d57d3468398730b59df851cbac6d65073f9e138' ecb_de = 'f9899749fec184d81afecd35da430bc394686e847d72141b3a955a4f6e920e7d91cb599d92ba2a6ba51860bb5b32f23b'
cbc_bytes = unhexlify(cbc_en) ecb_bytes = unhexlify(ecb_de)
cbc_blocks = [cbc_bytes[i:i + 16] for i in range(0, len(cbc_bytes), 16)] ecb_blocks = [ecb_bytes[i:i + 16] for i in range(0, len(ecb_bytes), 16)]
decrypted_blocks = []
for i in range(1, len(cbc_blocks)): current_cbc_block = cbc_blocks[i] previous_cbc_block = cbc_blocks[i - 1] decrypted_block = ecb_blocks[i]
recovered_block = bytes(a ^ b for a, b in zip(decrypted_block, previous_cbc_block)) decrypted_blocks.append(recovered_block)
final_decrypted_bytes = b''.join(decrypted_blocks) print(final_decrypted_bytes)
|