CBC 模式下的 HMAC-SHA256 和 AES-256

2024-04-07

我最近遇到以下代码示例 http://code.activestate.com/recipes/576980-authenticated-encryption-with-pycrypto/用于使用 AES-256 CBC 和 SHA-256 HMAC 加密文件进行身份验证和验证:

aes_key, hmac_key = self.keys
# create a PKCS#7 pad to get us to `len(data) % 16 == 0`
pad_length = 16 - len(data) % 16
data = data + (pad_length * chr(pad_length))
# get IV
iv = os.urandom(16)
# create cipher
cipher = AES.new(aes_key, AES.MODE_CBC, iv)
data = iv + cipher.encrypt(data)
sig = hmac.new(hmac_key, data, hashlib.sha256).digest()
# return the encrypted data (iv, followed by encrypted data, followed by hmac sig):
return data + sig

因为就我而言,我加密的不仅仅是一个字符串,而是一个相当大的文件,因此我修改了代码以执行以下操作:

aes_key, hmac_key = self.keys
iv = os.urandom(16)
cipher = AES.new(aes_key, AES.MODE_CBC, iv)

with open('input.file', 'rb') as infile:
    with open('output.file', 'wb') as outfile:
        # write the iv to the file:
        outfile.write(iv)

        # start the loop
        end_of_line = True

        while True:
            input_chunk = infile.read(64 * 1024)

            if len(input_chunk) == 0:
                # we have reached the end of the input file and it matches `% 16 == 0`
                # so pad it with 16 bytes of PKCS#7 padding:
                end_of_line = True
                input_chunk += 16 * chr(16)
            elif len(input_chunk) % 16 > 0:
                # we have reached the end of the input file and it doesn't match `% 16 == 0`
                # pad it by the remainder of bytes in PKCS#7:
                end_of_line = True
                input_chunk_remainder = 16 - (len(input_chunk) & 16)
                input_chunk += input_chunk_remainder * chr(input_chunk_remainder)

            # write out encrypted data and an HMAC of the block
            outfile.write(cipher.encrypt(input_chunk) + hmac.new(hmac_key, data, 
                    hashlib.sha256).digest())

            if end_of_line:
                break

简而言之,它一次读取 64KB 块的输入文件,并对这些块进行加密,使用加密数据的 SHA-256 生成 HMAC,并将该 HMAC 附加在每个块之后。解密将通过读取 64KB + 32B 块并计算前 64KB 的 HMAC 并将其与占用块中最后 32 字节的 SHA-256 总和进行比较来进行。

这是使用 HMAC 的正确方法吗?它是否确保数据未被修改并使用正确的密钥解密的安全性和身份验证?

仅供参考,AES 和 HMAC 密钥均源自相同的密码短语,该密码短语是通过 SHA-512、bcrypt、然后再次通过 SHA-512 运行输入文本生成的。最终 SHA-512 的输出被分成两部分,一个用于 AES 密码,另一个用于 HMAC。


是的,有两个安全问题。

但首先,我假设最后有这样的声明:

# write out encrypted data and an HMAC of the block
outfile.write(cipher.encrypt(input_chunk) + hmac.new(hmac_key, data, hashlib.sha256).digest())

你实际上的意思是:

# write out encrypted data and an HMAC of the block
data = cipher.encrypt(input_chunk)
outfile.write(data + hmac.new(hmac_key, data, hashlib.sha256).digest())

Because data没有在任何地方定义。

第一个安全问题是您要独立于其他部分来验证每个部分,而不是组合。换句话说,攻击者可以重新洗牌、复制或删除任何块,而接收者不会注意到。

一种更安全的方法是仅拥有一个 HMAC 实例,通过以下方式将所有加密数据传递给它:update https://www.dlitz.net/software/pycrypto/api/current/Crypto.Hash.HMAC.HMAC-class.html#update方法,并在最后输出一个摘要。

或者,如果您想让接收方在接收整个文件之前检测到篡改,您可以输出每个文件的中间 MAC。事实上,调用digest不改变HMAC的状态;你可以继续打电话update然后。

第二个安全问题是您不使用盐来派生密钥(我这么说是因为您不发送它)。除了密码破解之外,如果您使用相同的密码加密 2 个以上的文件,攻击者还可以自由混合任一加密文件所占用的块 - 因为 HMAC 密钥是相同的。解决方法:用盐。

最后一件小事:infile.read(64 * 1024)可能返回小于64*1024字节,但是这并不意味着您已到达文件末尾 https://stackoverflow.com/questions/4426581/python-eof-for-multi-byte-requests-of-file-read.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CBC 模式下的 HMAC-SHA256 和 AES-256 的相关文章

随机推荐