AES 加密
AES ECB模式
最简单的加密模式即为 电子密码本(Electronic codebook,ECB)模式。需要加密的消息按照块密码的块大小被分为数个块,并对每个块进行独立加密。
加密模式:

解密模式:

本方法的缺点在于同样的明文块会被加密成相同的密文块;因此,它不能很好的隐藏数据模式。在某些场合,这种方法不能提供严格的数据保密性,因此并不推荐用于密码协议中。下面的例子显示了ECB在密文中显示明文的模式的程度:该图像的一个位图版本(左图)通过ECB模式可能会被加密成中图,而非ECB模式通常会将其加密成右图。



右图是使用 CBC,CTR 或任何其它的更安全的模式加密左图可能产生的结果——与随机噪声无异。注意右图看起来的随机性并不能表示图像已经被安全的加密;许多不安全的加密法也可能产生这种“随机的”输出。
ECB模式也会导致使用它的协议不能提供数据完整性保护,易受到重放攻击的影响,因为每个块是以完全相同的方式解密的。
AES CBC模式
学习一下 CryptoHack 的 AES 部分:https://aes.cryptohack.org/lazy_cbc/
1976 年,IBM 发明了 密码分组链接(CBC,Cipher-block chaining)模式。在 CBC 模式中,每个明文块先与前一个密文块进行异或后,再进行加密。在这种方法中,每个密文块都依赖于它前面的所有明文块。同时,为了保证每条消息的唯一性,在第一个块中需要使用初始化向量。
加密模式:
CBC模式的加密过程为

而其解密过程则为

CBC 是最为常用的工作模式。它的主要缺点在于加密过程是串行的,无法被并行化,而且消息必须被填充到块大小的整数倍。解决后一个问题的一种方法是利用密文窃取。
注意在加密时,明文中的微小改变会导致其后的全部密文块发生改变,而在解密时,从两个邻接的密文块中即可得到一个明文块。因此,解密过程可以被并行化,而解密时,密文中一位的改变只会导致其对应的明文块完全改变和下一个明文块中对应位发生改变,不会影响到其它明文的内容。
[IrisCTF 2022] babymixup
例题:
from Crypto.Cipher import AES
import os
key = os.urandom(16)
flag = b"flag{REDACTED}"
assert len(flag) % 16 == 0
iv = os.urandom(16)
cipher = AES.new(iv, AES.MODE_CBC, key)
print("IV1 =", iv.hex())
print("CT1 =", cipher.encrypt(b"Hello, this is a public message. This message contains no flags.").hex())
iv = os.urandom(16)
cipher = AES.new(key, AES.MODE_CBC, iv )
print("IV2 =", iv.hex())
print("CT2 =", cipher.encrypt(flag).hex())
# IV1 = 4ee04f8303c0146d82e0bbe376f44e10
# CT1 = de49b7bb8e3c5e9ed51905b6de326b39b102c7a6f0e09e92fe398c75d032b41189b11f873c6cd8cdb65a276f2e48761f6372df0a109fd29842a999f4cc4be164
# IV2 = 1fe31329e7c15feadbf0e43a0ee2f163
# CT2 = f6816a603cefb0a0fd8a23a804b921bf489116fcc11d650c6ffb3fc0aae9393409c8f4f24c3d4b72ccea787e84de7dd0
分析题目:
已知量:第一部分加密的偏移量 IV1 ,明文 和 对应的密文 CT1,第一部分加密的偏移量 IV2 和密文 CT2
从第一部分加密的代码
cipher = AES.new(iv, AES.MODE_CBC, key)
可以知道 这里的 iv 应该为密钥 key ,而这里的 key,才是作为的偏移量 iv
所以我们已知量 IV1,准确的来说应该是作为的密钥,而不是作为偏移量执行的。
根据 CBC 解密模式的流程图:

我们已知密钥 IV1 和 明文、密文 CT1 的话,块解码器选择 ECB 模式 就能将真正的偏移量 key 解出来。
先用密钥 IV1 和 ECB 模式解码密文的第一个加密块,然后和第一个密文块进行异或就能得到偏移量了。
cipher = AES.new(IV1, AES.MODE_ECB)
enc1 = cipher.decrypt(CT1[:16])
iv = xor(enc1,msg[:16])
因为第一部分加密使用的偏移量 key ,也是第二部分加密使用的密钥 key。所以我们第二部分已知的参数为:密钥key ,偏移量 IV2 和密文 CT2 ,那么我们直接使用 AES CBC 的解密模式就能将明文全部解出来了。
完整 EXP:
import binascii
from Crypto.Cipher import AES
import os
from pwn import xor
# 第一部分
msg = b"Hello, this is a public message. This message contains no flags."
IV1 = b'4ee04f8303c0146d82e0bbe376f44e10'
CT1 = 'de49b7bb8e3c5e9ed51905b6de326b39b102c7a6f0e09e92fe398c75d032b41189b11f873c6cd8cdb65a276f2e48761f6372df0a109fd29842a999f4cc4be164'
key = binascii.unhexlify(IV1)
CT1 = binascii.unhexlify(CT1)
# print(key)
# print(CT1)
cipher = AES.new(key, AES.MODE_ECB)
enc1 = cipher.decrypt(CT1[:16])
iv = xor(enc1,msg[:16])
print(iv)
# 第二部分
key2 = iv
IV2 = '1fe31329e7c15feadbf0e43a0ee2f163'
CT2 = 'f6816a603cefb0a0fd8a23a804b921bf489116fcc11d650c6ffb3fc0aae9393409c8f4f24c3d4b72ccea787e84de7dd0'
iv = binascii.unhexlify(IV2)
CT2 = binascii.unhexlify(CT2)
cipher = AES.new(key2, AES.MODE_CBC, iv)
flag = cipher.decrypt(CT2)
print(flag)
恢复密钥 key,逆序还原 iv
例题:
from Crypto.Cipher import AES
import binascii
import hashlib
from secret import flag
assert flag[:5] == "flag{" and flag[-1:] == "}"
key = b"J1fx2g1jDak1c***"
l = len(key)
message = b"I have had my invitation to this world's festival, and thus my life has been blessed" + binascii.unhexlify(hashlib.sha256(key).hexdigest())[:10]
iv = flag[5:-1]
message = message + bytes((l - len(message) % l) * chr(l - len(message) % l), encoding = "utf-8")
aes = AES.new(key, AES.MODE_CBC, iv)
print(binascii.hexlify(aes.encrypt(message)))
#******************************************************************************************************************************************************6ece036e495d363b647d7f2749c4c2f3dd78f8637b
分析题目可知:首先 key 有部分是未知的,需要先还原出正确的 key 值。偏移量 iv 就是我们需要求的 flag。
明文 message 也是经过了填充的,填充的 key 的sha256 哈希值转字节取前 10 位。
1、恢复密钥 key
这里采用爆破的方式,我们通过 CBC 解密模式流程可知,最后一段密文块通过解码器解码,然后再与最后一段明文块异或就能恢复出上一段的密文块。这里我们可以直接使用 ECB 模式的解码器,原理一样的。

爆破的 exp:
from pwn import *
from Crypto.Cipher import AES
import binascii
import hashlib
# 定义待破解的key
key = b"J1fx2g1jDak1c***"
l = 16
# 定义字符集合,包括数字和大小写字母
charset = string.digits + string.ascii_letters
# 循环尝试每一种可能的key
for c1 in charset:
for c2 in charset:
for c3 in charset:
# 尝试当前的组合
current_key = key.replace(b"***", c1.encode() + c2.encode() + c3.encode())
# print(current_key)
message = b"I have had my invitation to this world's festival, and thus my life has been blessed" + binascii.unhexlify(
hashlib.sha256(current_key).hexdigest())[:10]
message = message + bytes((l - len(message) % l) * chr(l - len(message) % l), encoding="utf-8")
x = b'**************6ece036e495d363b647d7f2749c4c2f3dd78f8637b'
part_enc = x[-32:]
enc = binascii.unhexlify(part_enc)
aes = AES.new(current_key, AES.MODE_ECB)
恢复密钥为 key = b'J1fx2g1jDak1c7s4'
2、还原偏移量 iv
根据 CBC 解密模式的原理,逆序还原即可:
from pwn import *
from Crypto.Cipher import AES
import binascii
import hashlib
key = b"J1fx2g1jDak1c7s4"
l = len(key)
message = b"I have had my invitation to this world's festival, and thus my life has been blessed" + binascii.unhexlify(hashlib.sha256(key).hexdigest())[:10]
message = message + bytes((l - len(message) % l) * chr(l - len(message) % l), encoding = "utf-8")
print('message =',message)
part_enc = b'******************************************************************************************************************************************************6ece036e495d363b647d7f2749c4c2f3dd78f8637b'
msg = message
enc = binascii.unhexlify(part_enc[-32:])
aes = AES.new(key, AES.MODE_ECB)
enc1 = xor(aes.decrypt(enc),msg[80:96])
enc2 = xor(aes.decrypt(enc1),msg[64:80])
enc3 = xor(aes.decrypt(enc2),msg[48:64])
enc4 = xor(aes.decrypt(enc3),msg[32:48])
enc5 = xor(aes.decrypt(enc4),msg[16:32])
iv = xor(aes.decrypt(enc5),msg[0:16])
print(iv)
# b'welcome_1234_igd'
AES OFB模式
输出反馈模式(Output feedback, OFB)可以将块密码变成同步的流密码。它产生密钥流的块,然后将其与明文块进行异或,得到密文。与其它流密码一样,密文中一个位的翻转会使明文中同样位置的位也产生翻转。这种特性使得许多错误校正码,例如奇偶校验位,即使在加密前计算,而在加密后进行校验也可以得出正确结果。
由于XOR操作的对称性,加密和解密操作是完全相同的:


每个使用 OFB 的输出块与其前面所有的输出块相关,因此不能并行化处理。然而,由于明文和密文只在最终的异或过程中使用,因此可以事先对 IV 进行加密,最后并行的将明文或密文进行并行的异或处理。
可以利用输入全 0 的 CBC 模式产生 OFB 模式的密钥流。这种方法十分实用,因为可以利用快速的 CBC 硬件实现来加速 OFB 模式的加密过程。
[IrisCTF 2022] Nonces and Keys
题目信息:
Because of our revolutionary AES-128-OFB technology we have encrypted your user data so securely that even with the key (k=0x13371337133713371337133713371337) evil hackers can't read out the passwords!!!
题目文件格式为:challenge_enc.sqlite3
sqlite3的数据库文件格式:

得到明文的第一个块,长度为 16,然后将 明文和密文的第一个块进行异或
已知 key 的值了,所以用 ECB 模式进行解密就能得到 iv 的值,然后再进行 OFB 模式的解密即可得到 flag