在CBC模式下具有AES-256的HMAC-SHA256 [英] HMAC-SHA256 with AES-256 in CBC mode

查看:397
本文介绍了在CBC模式下具有AES-256的HMAC-SHA256的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I recently came across the following code sample for encrypting a file with AES-256 CBC with a SHA-256 HMAC for authentication and validation:

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

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

Since, in my case, I'm encrypting much more than a string, rather a fairly large file, I modified the code to do the following:

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总和进行比较来进行。

Simply put, this reads an input file in blocks of 64KB at a time and encrypts these blocks, generating a HMAC using SHA-256 of the encrypted data, and appending that HMAC after each block. Decryption will happen by reading in 64KB + 32B chunks and calculating the HMAC of the first 64KB and comparing it against the SHA-256 sum occupying the last 32 bytes in the chunk.

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

Is this the right way to use an HMAC? Does it ensure security and authentication that the data was unmodified and decrypted with the right key?

FYI,AES和HMAC密钥都来自相同的密码,该密码是通过先通过SHA-512,然后通过bcrypt,然后通过SHA- 512。然后将最终SHA-512的输出分为两个块,一个块用于AES密码,另一个块用于HMAC。

FYI, the AES and HMAC keys are both derived from the same passphrase which is generated by running the input text through SHA-512, then through bcrypt, then through SHA-512 again. The output from the final SHA-512 is then split into two chunks, one used for the AES password and the other used for the HMAC.

推荐答案

是的,有两个安全问题。

但是首先,我假设最后的声明如下:

But first, I assume that with this statement at the end:

# 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())

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

Because data is not defined anywhere.

第一个安全问题是您要独立验证每个数据块,但没有组成。换句话说,攻击者可以重新组合,复制或删除任何块,接收者将不会注意到。

The 1st security problem is that you are authenticating each piece independently of the others, but not the composition. In other words, the attacker can reshuffle, duplicate, or remove any of the chunks and the receiver will not notice.

一种更安全的方法是拥有一个HMAC实例。仅通过 update 方法,并在最后输出一个摘要。

A more secure approach is to have one instance of HMAC only, pass all the encrypted data to it via the update method, and output one digest, at the very end.

或者,如果要使接收器能够在接收整个文件之前检测到篡改,则可以为每个输出中间MAC。实际上,对 digest 的调用不会更改HMAC的状态。您可以在此之后继续调用 update

Alternatively, if you want to enable the receiver to detect tampering before receiving the whole file, you can output the intermediate MAC for each piece. In fact, a call to digest does not change the state of the HMAC; you can keep calling update afterwards.

第二个安全问题是您不使用盐作为密钥派生(我之所以这样说是因为您不发送)。除了密码破解以外,如果您使用相同的密码对两个以上的文件进行加密,则攻击者还可以自由地混合两个加密文件所占用的数据块-因为HMAC密钥是相同的。解决方案:使用盐。

The 2nd security problem is that you don't use salt for your key derivation (I say that because you don't send it). Apart from password cracking, if you encrypt more than 2 files using the same password the attacker will also be able to freely mix chunks taken by either encrypted file - because the HMAC key is the same. Solution: use salt.

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

One last minor thing: infile.read(64 * 1024) may return less than 64*1024 bytes, but that does not mean you reached the end of the file.

这篇关于在CBC模式下具有AES-256的HMAC-SHA256的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆