私は最近、認証と検証のために 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
私の場合、かなり大きなファイルではなく、文字列よりもはるかに多くのものを暗号化しているため、コードを次のように変更しました。
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 からの出力は、2 つのチャンクに分割されます。1 つは AES パスワードに使用され、もう 1 つは HMAC に使用されます。