PyCrypto - 初始化向量如何工作?

时间:2013-02-05 20:30:36

标签: python python-3.x pycrypto initialization-vector

我正在尝试理解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."

2 个答案:

答案 0 :(得分:19)

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

CBC decryption

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

其他模式不太宽容。如果您的IV出错,整个消息在解密时会出现乱码。以CTR模式为例,其中 nonce IV 具有几乎相同的含义:

CTR mode

答案 1 :(得分:1)

PyCrypto的开发人员从NIST取消了AES CBC Mode的规范:

AES Mode_CBC - >引用NIST 800-38a (The Recommendation for Cipher Mode Operations)

从那,第8页:

5.3初始化向量

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


要记住,每次撰写邮件时都需要使用随机IV,这会在邮件中添加“盐”,从而使邮件独一无二;即使“盐”在外面打开,如果AES加密密钥未知,也无法破解加密。如果您不使用随机IV,比如说,每个消息都使用相同的16个字节,那么如果您重复自己的消息,那么您的消息看起来会相同,并且可能会受到频率和/或重放攻击。< / p>

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

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)

希望这有帮助!