Jak zaszyfrować wiele plików za pomocą AES-GCM, bez uruchamiania funkcji wyprowadzania klucza za każdym razem?

Nov 20 2020

Powiązane pytanie: szyfrowanie AES wielu plików


W przypadku passwordmam 100 000 plików do zaszyfrowania. (Może dziś 100 tys. Plików, dziś może 50 tys., Jutro 10 tys. I w następnym tygodniu 40 tys.).

  • Do tej pory zrobiłem to (pseudokod):

    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
    

    i odszyfrować zaszyfrowany plik

    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)
    

    Oczywiście nie jest to optymalne, ponieważ uruchamiam funkcję KDF dla każdego pliku, a to jest powolne!

  • Myślałem o tym rozwiązaniu:

    # 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
    

    ale ma to tę wadę, że saltna początku każdego zaszyfrowanego pliku trzeba wstawić 16 dodatkowych bajtów ( ). Czy to powszechna praktyka?

    A przede wszystkim ma tę wadę podczas odszyfrowywania:

    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!
        ...
    

    Ponieważ saltznajduje się na początku każdego zaszyfrowanego pliku, oznacza to, że musimy uruchomić funkcję KDF ... dla każdego zaszyfrowanego pliku, który chcemy odszyfrować! Będzie to bardzo powolne.

    Moglibyśmy umieścić je w pamięci podręcznej cache[salt] = key, tak, że jeśli saltponownie znajdziemy to samo , to już mamy key, ale nie jestem pewien, czy jest to eleganckie rozwiązanie.

Pytanie: którego schematu użyć do zaszyfrowania 100k plików (w jednym przebiegu lub w wielu sesjach) za pomocą hasła z AES-GCM?

Odpowiedzi

1 fgrieu Nov 20 2020 at 15:18

Jeden poważny w kwestii kryptografii opartej na hasłach nie może odejść KDF_PBKDF2, ale biec do Argon2 (lub przeszyfrować, jeśli jest łatwiej dostępny)! Wydobywanie bitcoinów pokazało (w 2020 r.), Że dedykowane układy ASIC działające w trybie SHA-256 z wysoką szybkością (220 TH / s) i wydajnością (15 pJ / h) mogą stać się dostępne na rynku za kilka tysięcy dolarów. To sprawia, że ​​nie można polegać na PBKDF2-HMAC działającym na standardowym sprzęcie do rozciągania haseł wybranych przez użytkownika w aplikacjach o wysokim poziomie bezpieczeństwa.

Proponowana metoda ma jedną cechę: saltjest wspólna dla kilku plików, a dla szerokiego losowego salttylko wtedy, gdy zostały one zaszyfrowane razem. Jest to zarówno prawdopodobnie niechciany wyciek informacji, jak i sposób rozwiązania wspomnianej wady: kod rozciągający hasło używany do deszyfrowania może utrzymywać pamięć podręczną RAM składającą się z ( saltkey) par.

Rozważałbym zastąpienie AES-GCM AES-GCM-SIV , dla spokoju ducha w przypadku zacinania się RNG, ale należy pamiętać, że potrzebne są dwa przejścia przez dane.

Chociaż zalecam przycinanie ostatniego bajtu, gdy się liczy (np. Gdy dane znajdują się na kodzie kreskowym lub przechodzą przez powolny lub wyczerpujący baterię nośnik komunikacyjny), nie polecam oszczędzania salti noncerozmiaru w szyfrowaniu plików, tak jak my są w latach 80.