Pycrypto:在ECB模式下使用AES进行“双重加密”不会产生纯文本

问题描述

这是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非常简单,加密和解密模式之间的唯一区别是明文和密文交换位置:在加密中,输入明文,输出密文,在解密中,输入密文,输出明文,其余的都一样。因此,再次“加密”密文应产生纯文本,但此代码不能那样工作。如果我不得不猜测encryptdecrypt所做的不只是应用块操作。无论如何,为什么双重加密无法按预期工作?

解决方法

测试您的假设是否应该在您的代码assert testbytes == plaintext中?

无论如何。加密由两部分组成,算法(此处为AES)和操作模式(此处为ECB)。该算法本身只能加密单个块。操作模式将其扩展到任何长度的纯文本。为了使您的假设正确无误,各个部分,算法和操作模式的各个处理步骤及其解密和加密的顺序必须相同。

关于ECB模式,您的假设是正确的,因为每个块都独立于其他块进行处理(这也使该模式不安全)。但是,对于AES,您的假设是不正确的,因为解密实际上是以reverse的顺序进行加密的,有关详细信息,请参见here

检查后者的最简单方法是仅加密一个块而无需填充。由于ECB模式不使用IV,因此加密被简化为AES原语本身。不必禁用填充,因为PyCryptodome不会隐式填充(与许多其他库相比)。这种情况仅与您的代码相对应(尽管您必须检查testbytesplaintext之间的相等性)。结果验证了使用AES进行的双重加密不会产生原始明文。