Comment crypter de nombreux fichiers avec AES-GCM, sans exécuter la fonction de dérivation de clé à chaque fois?

Nov 20 2020

Question liée: AES cryptant plusieurs fichiers


Avec a password, j'ai 100k fichiers à crypter. (Peut-être 100k fichiers aujourd'hui; ou peut-être 50k aujourd'hui, 10k demain et 40k fichiers la semaine prochaine).

  • Jusqu'à présent, j'ai fait ceci (pseudo-code):

    for each file:
        plaintext = file.read()
        nonce = getrandom(bytes=16)
        key = KDF_PBKDF2(password, salt=nonce, count=1000000)  # very slow for each file!
        ciphertext, tag = AES_GCM_cipher(key, nonce=nonce).encrypt(plaintext)
        write to disk:   nonce | ciphertext | tag
    

    et pour décrypter le fichier crypté

    nonce, ciphertext, tag = file.read()
    key = KDF_PBKDF2(password, salt=nonce, count=1000000)    # very slow for each file!
    plaintext = AES_GCM_cipher(key, nonce=nonce).decrypt(ciphertext)
    

    Evidemment, ce n'est pas optimal, puisque j'exécute la fonction KDF pour chaque fichier, et c'est lent!

  • J'ai pensé à cette solution:

    # do this ONLY ONCE for each encryption session:
    salt = getrandom(bytes=16)
    key = KDF_PBKDF2(password, salt=salt, count=1000000)   # run only once
    
    for each file:
        plaintext = file.read()
        nonce = getrandom(bytes=16)
        ciphertext, tag = AES_GCM_cipher(key, nonce=nonce).encrypt(plaintext)
        write to disk:   salt | nonce | ciphertext | tag
    

    mais cela a l'inconvénient de devoir ajouter 16 octets supplémentaires ( salt) au début de chaque fichier chiffré. Est-ce une pratique courante?

    Et surtout, il présente l'inconvénient suivant lors du décryptage:

    for each encrypted file:
        salt, nonce, ciphertext, tag = file.read()           # since salt may be different for each file
                                                             # we have to run:
        key = KDF_PBKDF2(password, salt=salt, count=1000000) # very slow for each file!
        ...
    

    Puisque saltc'est au début de chaque fichier crypté, cela signifie que nous devons exécuter la fonction KDF ... pour chaque fichier crypté que nous voulons décrypter! Ce sera très lent.

    Nous pourrions les mettre en cache cache[salt] = key, de sorte que si nous retrouvons la même chose salt, nous avons déjà le key, mais je ne suis pas sûr que ce soit une solution élégante.

Question: quel schéma utiliser pour crypter 100k fichiers (en une seule passe ou en plusieurs sessions) avec un mot de passe avec AES-GCM?

Réponses

1 fgrieu Nov 20 2020 at 15:18

Un sérieux au sujet de la cryptographie basée sur les mots de passe ne doit pas s'éloigner KDF_PBKDF2, mais courir vers Argon2 (ou scrypt s'il est plus facilement disponible)! L'exploitation de Bitcoin a (en 2020) montré que les ASIC dédiés exécutant SHA-256 à un taux élevé (220 TH / s) et une efficacité (15 pJ / H) peuvent devenir disponibles dans le commerce pour quelques milliers de dollars américains. Cela rend intenable de s'appuyer sur PBKDF2-HMAC exécuté sur du matériel standard pour étirer les mots de passe choisis par l'utilisateur dans les applications de haute sécurité.

La méthode proposée a une caractéristique: elle saltest commune à plusieurs fichiers si, et pour le large aléatoire saltseulement si, ils ont été chiffrés ensemble. Il s'agit à la fois d'une fuite d'informations éventuellement indésirable et d'un moyen de résoudre l'inconvénient mentionné: le code d'étirement du mot de passe utilisé dans le décryptage peut maintenir un cache RAM de ( saltkey) paires.

J'envisagerais de remplacer AES-GCM par AES-GCM-SIV , pour la tranquillité d'esprit en cas de bégaiement du RNG, mais en gardant à l'esprit que deux passes sont nécessaires sur les données.

Autant je recommande de couper le dernier octet quand cela compte (par exemple lorsque les données se trouvent sur un code à barres ou passent par un moyen de communication lent ou / et épuisant la batterie), je ne recommanderai pas d'économiser saltet de noncetaille dans le cryptage de fichier comme nous sommes dans les années 80.