我最近遇到了以下代码示例,用于使用 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。