RAMに収まらない大きなファイルをAES-GCMで暗号化する

Nov 22 2020

このコードmyfileは、RAMに収まるファイルに対して機能します。

import Crypto.Random, Crypto.Cipher.AES   # pip install pycryptodome

nonce = Crypto.Random.new().read(16)
key = Crypto.Random.new().read(16)  # in reality, use a key derivation function, etc. ouf of topic here
cipher = Crypto.Cipher.AES.new(key, Crypto.Cipher.AES.MODE_GCM, nonce=nonce)

out = io.BytesIO()
with open('myfile', 'rb') as g:
    s = g.read()
ciphertext, tag = cipher.encrypt_and_digest(s)
out.write(nonce)
out.write(ciphertext)
out.write(tag)

しかし、この手法を使用して64GBファイルを暗号化する方法は?

明らかに、g.read(...)はより小さなバッファサイズ、たとえば128MBを使用する必要があります。

しかし、それでは、暗号部分ではどのように機能しますか?(ciphertext, tag)128 MBのチャンクごとにを保持する必要がありますか?

またはtag、ファイル全体に対して1つだけにすることは可能ですか?

回答

Basj Nov 22 2020 at 20:30

@ PresidentJamesK.Polkのコメントで述べたように、これが解決策のようです。

out.write(nonce)
while True:
    block = g.read(65536)
    if not block:
        break
    out.write(cipher.encrypt(block))
out.write(cipher.digest())  # 16-byte tag at the end of the file

唯一の問題は、復号化のためにこのファイルを読み戻すときに、16バイトを引いた最後で停止するのが少し面倒なことです。

または多分これを行う必要があります:

out.write(nonce)
out.seek(16, 1)  # go forward of 16 bytes, placeholder for tag
while True:
   ...
   ...
out.seek(16)
out.write(cipher.digest())  # write the tag at offset #16 of the output file