HMAC-SHA256采用CBC模式的AES-256

Naf*_*Kay 2 python encryption aes hmac pycrypto

我最近遇到了以下代码示例,用于使用带有SHA-256 HMAC的AES-256 CBC加密文件进行身份验证和验证:

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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

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

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

仅供参考,AES和HMAC密钥都来自相同的密码短语,这是通过SHA-512运行输入文本,然后通过bcrypt,然后再通过SHA-512生成的.然后将最终SHA-512的输出分成两个块,一个用于AES密码,另一个用于HMAC.

Squ*_*ree 5

是的,有2个安全问题.

但首先,我假设最后这句话:

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

你的意思是:

# 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())
Run Code Online (Sandbox Code Playgroud)

因为data没有在任何地方定义.

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

更安全的方法是只有一个HMAC实例,通过该update方法将所有加密数据传递给它,并在最后输出一个摘要.

或者,如果要在接收整个文件之前启用接收器检测篡改,则可以为每个部分输出中间MAC.实际上,呼叫digest不会改变HMAC的状态; 你可以继续打电话update.

第二个安全问题是你不使用salt来进行密钥推导(我说是因为你没有发送它).除了密码破解之外,如果使用相同的密码加密2个以上的文件,攻击者也可以自由地混合加密文件所占用的块 - 因为HMAC密钥是相同的.解决方案:使用盐.

最后一件小事:infile.read(64 * 1024)可能返回少于64*1024字节,但这并不意味着你到达文件的末尾.