问题描述
这是cryptopals挑战(cryptopals.org)的一部分
以下代码对从上一轮获得的密文执行“加密”操作:
from Crypto.Cipher import AES
def ecb(plaintext,key):
assert len(plaintext) == 16
cipher = AES.new(key,AES.MODE_ECB)
ciphertext = cipher.encrypt(plaintext)
return ciphertext
if __name__ == '__main__':
testbytes = b'a' * 16
key = b'0' * 16
ciphertext = ecb(testbytes,key)
plaintext = ecb(ciphertext,key)
assert testbytes == plaintext
从理论上讲,ECB非常简单,加密和解密模式之间的唯一区别是明文和密文交换位置:在加密中,输入明文,输出密文,在解密中,输入密文,输出明文,其余的都一样。因此,再次“加密”密文应产生纯文本,但此代码不能那样工作。如果我不得不猜测encrypt
和decrypt
所做的不只是应用块操作。无论如何,为什么双重加密无法按预期工作?
解决方法
测试您的假设是否应该在您的代码assert testbytes == plaintext
中?
无论如何。加密由两部分组成,算法(此处为AES)和操作模式(此处为ECB)。该算法本身只能加密单个块。操作模式将其扩展到任何长度的纯文本。为了使您的假设正确无误,各个部分,算法和操作模式的各个处理步骤及其解密和加密的顺序必须相同。
关于ECB模式,您的假设是正确的,因为每个块都独立于其他块进行处理(这也使该模式不安全)。但是,对于AES,您的假设是不正确的,因为解密实际上是以reverse
的顺序进行加密的,有关详细信息,请参见here。
检查后者的最简单方法是仅加密一个块而无需填充。由于ECB模式不使用IV,因此加密被简化为AES原语本身。不必禁用填充,因为PyCryptodome不会隐式填充(与许多其他库相比)。这种情况仅与您的代码相对应(尽管您必须检查testbytes
和plaintext
之间的相等性)。结果验证了使用AES进行的双重加密不会产生原始明文。