13

我试图弄清楚为什么我的 Python 客户端和 Ruby 服务器在如何加密数据方面存在分歧。我在 Ruby 代码和我的代码中看到的唯一区别是它们没有指定初始化向量,因此它回退到所有 \x0 的默认值

当我尝试在没有 iv 的情况下实例化 PyCrypto 时,它给了我一个错误。这是一个例子:

from Crypto.Cipher import AES
test = "Very, very confidential data"
key = b'Thirty Two Byte key, made Beef y' 

gryp = AES.new(key, AES.MODE_CBC)

(这个例子本质上是来自 PyCrypto 文档的示例代码,没有指定 IV)文档说 w/r/t IV“它是可选的,当不存在时,它将被赋予全零的默认值。” 但是我收到错误“ValueError: IV must be 16 bytes long”。

所以我可以指定IV,这不是问题本身,但我试图弄清楚它是否认为它不能使用默认值,如果我使用库的方式有其他问题。

4

2 回答 2

17

这似乎是 Pycrypto 的AES的类文档中的一个错误,因为 AES 实现已更改,因此 IV对于那些需要 1 的模式不是可选的(即,您必须自己传递 16 个字节的零,如果是你想怎么做)。

有关某人未指定 IV 并查找在线文档的相同问题,请参阅此错误报告。有一个明确需要 IV 的更改,基本上,没有人更新在线文档来反映这一点。Pycrypto 源中的类文档已更新,但需要重新生成在线文档以反映这一点。

来源的新文档指出:

对于所有其他模式,它必须是block_size字节长。

而不是旧版本的

对于所有其他模式,它必须是block_size字节长。它是可选的,当不存在时,它将被赋予全零的默认值。

源中指定 iv 的更新示例是:

from Crypto.Cipher import AES
from Crypto import Random

key = b'Sixteen byte key'
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CFB, iv)
msg = iv + cipher.encrypt(b'Attack at dawn')
于 2013-01-17T23:49:30.120 回答
3

这是一个对我有用的实现,有一些修复:

class AESCipher:

    def __init__(self, key):
        self.bs = 32
        if len(key) >= 32:
            self.key = key[:32]
        else:
            self.key = self._pad(key)

    def encrypt(self, raw):
        raw = self._pad(raw)
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return base64.b64encode(iv + cipher.encrypt(raw))

    def decrypt(self, enc):
        enc = base64.b64decode(enc)
        iv = enc[:AES.block_size]
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return self._unpad(cipher.decrypt(enc[AES.block_size:]))

    def _pad(self, s):
        return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)

    def _unpad(self, s):
        return s[:-ord(s[len(s)-1:])]
于 2014-02-21T08:03:40.660 回答