13

我试图了解 PyCrypto 如何在项目中使用,但我并不完全理解初始化向量 (IV) 的重要性。我发现在解码字符串时我可以使用错误的 IV,除了前 16 个字节(块大小)之外,我似乎仍然可以得到消息。只是使用错误或不理解某些东西吗?

这是一个示例代码来演示:

import Crypto
import Crypto.Random
from Crypto.Cipher import AES

def pad_data(data):
    if len(data) % 16 == 0:
        return data
    databytes = bytearray(data)
    padding_required = 15 - (len(databytes) % 16)
    databytes.extend(b'\x80')
    databytes.extend(b'\x00' * padding_required)
    return bytes(databytes)

def unpad_data(data):
    if not data:
        return data

    data = data.rstrip(b'\x00')
    if data[-1] == 128: # b'\x80'[0]:
        return data[:-1]
    else:
        return data


def generate_aes_key():
    rnd = Crypto.Random.OSRNG.posix.new().read(AES.block_size)
    return rnd

def encrypt(key, iv, data):
    aes = AES.new(key, AES.MODE_CBC, iv)
    data = pad_data(data)
    return aes.encrypt(data)

def decrypt(key, iv, data):
    aes = AES.new(key, AES.MODE_CBC, iv)
    data = aes.decrypt(data)
    return unpad_data(data)

def test_crypto ():
    key = generate_aes_key()
    iv = generate_aes_key() # get some random value for IV
    msg = b"This is some super secret message.  Please don't tell anyone about it or I'll have to shoot you."
    code = encrypt(key, iv, msg)

    iv = generate_aes_key() # change the IV to something random

    decoded = decrypt(key, iv, code)

    print(decoded)

if __name__ == '__main__':
    test_crypto()

我正在使用 Python 3.3。

输出会因执行而异,但我得到如下信息:b"1^,Kp}Vl\x85\x8426M\xd2b\x1aer secret message. Please don't tell anyone about it or I'll have to shoot you."

4

2 回答 2

21

您看到的行为特定于 CBC 模式。使用 CBC,解密可以通过以下方式可视化(来自维基百科):

CBC解密

您可以看到 IV 仅对明文的前 16 个字节有贡献。如果 IV 在传输到接收器的过程中损坏,CBC 仍将正确解密除第一个块之外的所有块。在 CBC 中,IV 的目的是使您能够使用相同的密钥加密相同的消息,并且每次仍然获得完全不同的密文(即使消息长度可能会泄露一些东西)。

其他模式不那么宽容。如果你弄错了 IV,整个消息在解密时就会出现乱码。以 CTR 模式为例,其中nonce的含义与IV几乎相同:

点击率模式

于 2013-02-06T07:52:10.973 回答
3

PyCrypto 的开发人员从 NIST 中提取了 AES CBC 模式的规范:

AES Mode_CBC -> 参考NIST 800-38a(密码模式操作的建议)

从那开始,第 8 页:

5.3 初始化向量

除了明文之外,CBC、CFB 和 OFB 模式的加密过程的输入还包括一个称为初始化向量 (IV) 的数据块,表示为 IV。IV 用于消息加密的初始步骤和消息的相应解密。IV不必保密;但是,对于 CBC 和 CFB 模式,加密过程的任何特定执行的 IV 必须是不可预测的,并且对于 OFB 模式,必须为每次执行加密过程使用唯一的 IV。附录 C 中讨论了 IV 的生成。


需要记住的是,每次撰写消息时都需要使用随机 IV,这会为消息添加“盐”,从而使消息独一无二;即使“盐”公开,如果 AES 加密密钥未知,它也无助于破解加密。例如,如果您不使用随机 IV,则每条消息使用相同的 16 个字节,如果您重复自己的消息,那么您的消息在传输过程中看起来是一样的,并且您可能会受到频率和/或重放攻击。

随机 IV 与静态结果的测试:

def test_crypto ():
    print("Same IVs same key:")
    key = generate_aes_key()
    iv = b"1234567890123456"
    msg = b"This is some super secret message.  Please don't tell anyone about it or I'll have to shoot you."
    code = encrypt(key, iv, msg)
    print(code.encode('hex'))
    decoded = decrypt(key, iv, code)
    print(decoded)

    code = encrypt(key, iv, msg)
    print(code.encode('hex'))
    decoded = decrypt(key, iv, code)
    print(decoded)

    print("Different IVs same key:")
    iv = generate_aes_key()
    code = encrypt(key, iv, msg)
    print(code.encode('hex'))
    decoded = decrypt(key, iv, code)
    print(decoded)

    iv = generate_aes_key()
    code = encrypt(key, iv, msg)
    print(code.encode('hex'))
    decoded = decrypt(key, iv, code)
    print(decoded)

希望这可以帮助!

于 2013-02-06T04:34:03.667 回答