PyCrypto返回AES密钥大小错误

3
我正在尝试编写一个使用AES加密文件的程序,然而无论我使用什么样的密钥大小都会出现如下错误消息:

ValueError: AES密钥必须是16、24或32个字节长。

以下是用于生成AES对象的代码:

def AESEncryptor(Seed, Block = 16): #Generate AES key and Cipher
    iv = Random.new().read(Block)
    cipher = AES.new(Seed.encode('utf8'), AES.MODE_CBC, iv)
    return cipher, iv

我的生成密钥的代码如下

def genNewSeed(k=2048): #Generate seed for new AES key
    return hashlib.sha256(os.urandom(32)).hexdigest()[:11]

根据sys.getsizeof(),它等于32位,但仍返回错误。


2
仔细阅读。您说它是32位的,但需要是16位,32字节。 - Jason Hu
1
我现在感觉非常愚蠢,谢谢你的答案。 - Human Generic
1个回答

1
问题在于你只从一个包含64个字符的十六进制“种子”中切割了11个字节。请记住,密钥应具有高熵,否则更容易被暴力破解。
我建议你使用:
def AESEncryptor(Seed, Block = 16): #Generate AES key and Cipher
    iv = Random.new().read(Block)
    cipher = AES.new(Seed, AES.MODE_CBC, iv)
    return cipher, iv

def genNewSeed(k=2048): #Generate seed for new AES key
    return hashlib.sha256(os.urandom(32)).digest()

这将为您提供一个32字节的密钥,使其成为AES-256。如果您想要AES-128,则可以将最后16个字节切掉:
hashlib.sha256(os.urandom(32)).digest()[:16]

你不能使用 sys.getsizeof() 来确定键的大小,因为它包括各种内部计数器和数据。例如,一个空字符串已经有 21 个字节的大小。这就是为什么当你只得到 11 个字节时,你会认为你得到了32个字节(21 + 11 = 32)。请改用内置的 len(key)


我唯一的问题是密钥需要在之后使用RSA进行加密,而digest()返回的值似乎无法用RSA加密,使用hexdigest()会产生一个大于32的值。使用md5(Seed).hexdigest()是否会产生足够高的熵,还是我需要重新考虑这个问题? - Human Generic
(1) 我不知道你的代码,但使用至少344位((32 + 11)* 8)的RSA密钥并使用PKCS#1 v1.5填充可以加密32字节的数据。虽然现在不应该使用小于2048位的RSA密钥(3072位更好),所以应该有足够的空间将AES密钥放在那里。(2) 你不能在SHA-256的输出上使用hexdigest(),因为你会得到64个字符/字节,这将导致512位键,而这是AES不支持的。 - Artjom B.
(1) 我加密种子的代码是 return r.encrypt(str(seed).encode('utf8'), crt),其中crt是公钥。我不确定您所说的PKCS#1 v1.5填充是什么,因为我相对较新于此。当我使用您的代码时,我会收到错误'ascii' codec can't decode byte 0xe1 in position 0: ordinal not in range(128)。(2) 您建议我们使用大于2048位的RSA密钥吗?您推荐哪个大小以在安全性和性能之间取得良好平衡? - Human Generic
(1) 关键是已经是字节串。你不需要将其转换为字符串,然后再次编码。尝试使用 r.encrypt(seed, crt)。 (2) 这取决于您要多么安全地保护数据。2048 现在和接下来的几年似乎都可以。您应该测试一下在系统上可以承受哪种性能惩罚。 - Artjom B.
(1) 现在正在工作,谢谢你的帮助,应该会大大增加安全性。(2) 好的,由于这个客户并不是一个高调的目标,我们现在可以使用2048位的密钥,并在几年后提高密钥大小。谢谢。 - Human Generic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接