it-swarm.com.de

Java AES / GCM / NoPadding - Was gibt mir cipher.getIV ()?

Ich verwende die Verschlüsselung AES/GCM/NoPadding In Java 8 und frage mich, ob mein Code eine Sicherheitslücke aufweist. Mein Code scheint zu funktionieren verschlüsselt und entschlüsselt Text, einige Details sind jedoch unklar.

Meine Hauptfrage lautet:

Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] iv = cipher.getIV(); // ?????

Erfüllt diese IV die Anforderung von "Für einen bestimmten Schlüssel darf die IV NICHT wiederholt werden." von RFC 4106 ?

Ich würde mich auch über Antworten/Einblicke für meine verwandten Fragen freuen (siehe unten), aber diese erste Frage nervt mich am meisten. Ich weiß nicht, wo ich Quellcode oder Dokumentation finden kann, die darauf antworten.


Hier ist ungefähr der vollständige Code. Ich entschuldige mich, falls ich beim Schreiben dieses Beitrags Fehler gemacht habe:

class Encryptor {
  Key key;

  Encryptor(byte[] key) {
    if (key.length != 32) throw new IllegalArgumentException();
    this.key = new SecretKeySpec(key, "AES");
  }

  // the output is sent to users
  byte[] encrypt(byte[] src) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    cipher.init(Cipher.ENCRYPT_MODE, key);
    byte[] iv = cipher.getIV(); // See question #1
    assert iv.length == 12; // See question #2
    byte[] cipherText = cipher.doFinal(src);
    assert cipherText.length == src.length + 16; // See question #3
    byte[] message = new byte[12 + src.length + 16]; // See question #4
    System.arraycopy(iv, 0, message, 0, 12);
    System.arraycopy(cipherText, 0, message, 12, cipherText.length);
    return message;
  }

  // the input comes from users
  byte[] decrypt(byte[] message) throws Exception {
    if (message.length < 12 + 16) throw new IllegalArgumentException();
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    GCMParameterSpec params = new GCMParameterSpec(128, message, 0, 12);
    cipher.init(Cipher.DECRYPT_MODE, key, params);
    return cipher.doFinal(message, 12, message.length - 12);
  }
}

Angenommen, Benutzer knacken meinen geheimen Schlüssel = Spiel vorbei.


Weitere detaillierte Fragen/verwandte Fragen:

  1. Ist die von cipher.getIV () zurückgegebene IV für mich sicher?

    • Vermeidet es die Katastrophe, die IV-Tastenkombination im Galois/Counter-Modus wiederzuverwenden?
    • Ist es immer noch sicher, wenn mehrere Anwendungen diesen Code gleichzeitig ausführen und alle Benutzern verschlüsselte Nachrichten aus denselben Quelldaten anzeigen (möglicherweise in derselben Millisekunde)?
    • Woraus besteht die zurückgegebene IV? Ist es ein Atomzähler plus ein zufälliges Rauschen?
    • Muss ich cipher.getIV() vermeiden und selbst eine IV mit meinem eigenen Zähler erstellen?
    • Ist der Quellcode, der cipher.getIV() implementiert, irgendwo online verfügbar, vorausgesetzt, ich verwende die Erweiterung Oracle JDK 8 + JCE Unlimited Strength?
  2. Ist die IV immer 12 Bytes lang?

  3. Ist das Authentifizierungs-Tag immer 16 Byte (128 Bit) lang?

  4. Bedeutet dies, dass meine verschlüsselten Nachrichten mit den Ziffern 2 und 3 und der fehlenden Auffüllung immer 12 + src.length + 16 Byte lang sind? (Und so kann ich sie sicher in ein Byte-Array zerquetschen, für das ich die richtige Länge kenne?)

  5. Ist es für mich sicher, Benutzern eine unbegrenzte Anzahl von src-Datenverschlüsselungen anzuzeigen, wenn den Benutzern konstante src-Daten bekannt sind?

  6. Ist es für mich sicher, Benutzern eine unbegrenzte Anzahl von src-Datenverschlüsselungen anzuzeigen, wenn sich die src-Daten jedes Mal unterscheiden (z. B. einschließlich System.currentTimeMillis() oder Zufallszahlen)?

  7. Wäre es hilfreich, wenn ich die src-Daten vor der Verschlüsselung mit Zufallszahlen auffüllen würde? Sprich 8 zufällige Bytes vorne und hinten oder nur an einem Ende? Oder würde das überhaupt nicht helfen/meine Verschlüsselung verschlimmern?

(Da sich diese Fragen alle auf den gleichen Block meines eigenen Codes beziehen und eng miteinander verwandt sind und andere möglicherweise die gleichen Fragen haben/sollten, wenn sie dieselbe Funktionalität implementieren, hat es sich als falsch erwiesen, die Fragen in mehrere zu unterteilen Ich kann sie separat neu veröffentlichen, wenn dies für das Format von StackOverflow besser geeignet ist.

32
Michael Hixson

F1: Ist die von cipher.getIV () zurückgegebene IV für mich sicher?

Ja, zumindest für die von Oracle bereitgestellte Implementierung. Sie wird separat mit der Standardimplementierung SecureRandom generiert. Da es 12 Byte groß ist (der Standard für GCM), haben Sie 96 Bit Zufälligkeit. Die Chance, dass sich der Zähler wiederholt, ist unglaublich gering. Sie können die Quelle im OpenJDK (GPL'ed) nachschlagen, auf dem das Oracle JDK basiert.

Ich würde Ihnen jedoch immer noch empfehlen, Ihre eigenen 12 zufälligen Bytes zu generieren, da sich andere Anbieter möglicherweise anders verhalten.


F2: Ist diese IV immer 12 Bytes lang?

Es ist sehr wahrscheinlich, da es sich um die GCM-Standardeinstellung handelt, aber andere Längen sind gelten für GCM. Der Algorithmus muss jedoch zusätzliche Berechnungen für eine andere Größe als 12 Byte durchführen. Aufgrund von Schwachstellen wird dringend empfohlen, den Wert bei 12 Byte/96 Bit zu halten. APIs können Sie auf die Auswahl der IV-Größe beschränken.


F3: Ist das Authentifizierungs-Tag immer 16 Byte (128 Bit) lang?

Nein, es kann eine beliebige Bytegröße von 64 Bit bis 128 Bit in Schritten von 8 Bit haben. Wenn es kleiner ist, besteht es lediglich aus den am weitesten links stehenden Bytes des Authentifizierungs-Tags. Sie können eine andere Tag-Größe angeben, indem Sie GCMParameterSpec als dritten Parameter für Ihren init -Aufruf verwenden.

Beachten Sie, dass die Stärke von GCM stark von der Größe des Tags abhängt. Ich würde empfehlen, es auf 128 Bit zu halten. 96 Bits sollten das Minimum sein besonders, wenn Sie viel Chiffretext generieren möchten.


F4: Bedeutet dies, dass meine verschlüsselten Nachrichten bei Nummer 2 und Nummer 3 und fehlender Auffüllung immer eine Länge von 12 + src.length + 16 Bytes haben? (Und so kann ich sie sicher in ein Byte-Array zerquetschen, für das ich die richtige Länge kenne?)

Siehe oben. Für den Oracle-Anbieter ist dies der Fall. Verwenden Sie GCMParameterSpec, um sich dessen sicher zu sein.


F5: Ist es für mich sicher, Benutzern eine unbegrenzte Anzahl von Quelldatenverschlüsselungen anzuzeigen, wenn die Benutzer konstante Quelldaten kennen?

praktisch ungebunden, ja. Ich würde nach ungefähr 2 ^ 48 Verschlüsselungen anfangen, mir Sorgen zu machen. Generell sollten Sie jedoch Design für Schlüssel ändern.


F6: Ist es für mich sicher, Benutzern eine unbegrenzte Anzahl von src-Datenverschlüsselungen anzuzeigen, wenn sich die src-Daten jedes Mal unterscheiden (z. B. einschließlich System.currentTimeMillis () oder Zufallszahlen)?

Siehe Antwort zu Q5


F7: Würde es helfen, wenn ich die src-Daten vor der Verschlüsselung mit Zufallszahlen auffüllte? Sprich 8 zufällige Bytes vorne und hinten oder nur an einem Ende? Oder würde das überhaupt nicht helfen/meine Verschlüsselung verschlimmern?

Nein, es würde überhaupt nicht helfen. GCM verwendet den CTR-Modus darunter, sodass er nur mit dem Schlüsselstream verschlüsselt wird. Es würde nicht als IV wirken. Wenn Sie eine praktisch unbegrenzte Anzahl von Chiffretexten benötigen (höher als 2 ^ 48!), Würde ich vorschlagen, dass Sie diese Zufallszahl und Ihren Schlüssel für eine Schlüsselableitungsfunktion oder KDF verwenden. HKDF ist derzeit das Beste, aber Sie müssen möglicherweise Bouncy Castle verwenden oder es selbst implementieren.

39
Maarten Bodewes