Cryptez un gros fichier qui ne rentre pas dans la RAM avec AES-GCM

Nov 22 2020

Ce code fonctionne pour un fichier myfilequi tient dans la 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)

Mais comment crypter un fichier de 64 Go en utilisant cette technique?

De toute évidence, le g.read(...)devrait utiliser une taille de tampon plus petite, par exemple 128 Mo.

Mais alors, comment ça marche pour la partie crypto? Devrions-nous garder un (ciphertext, tag)pour chaque bloc de 128 Mo?

Ou est-il possible d'en avoir un seul tagpour l'ensemble du fichier?

Réponses

Basj Nov 22 2020 at 20:30

Comme mentionné dans le commentaire de @ PresidentJamesK.Polk, cela semble être la solution:

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

Le seul problème est que, lors de la lecture de ce fichier pour le décryptage, s'arrêter à la fin moins 16 octets est un peu ennuyeux .

Ou peut-être devrait-on faire ceci:

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

?