Dies ist die erste Seite, die über Google angezeigt wird, und die Sicherheitslücken in allen Implementierungen lassen mich zusammenzucken. Ich poste diese Seite, um Informationen zur Verschlüsselung für andere hinzuzufügen, da dies 7 Jahre nach dem ursprünglichen Beitrag der Fall war. Ich habe einen Master-Abschluss in Computertechnik und viel Zeit damit verbracht, Kryptographie zu studieren und zu lernen. Deshalb werfe ich meine zwei Cent, um das Internet sicherer zu machen.
Beachten Sie auch, dass viele Implementierungen für eine bestimmte Situation sicher sein können. Warum sollten Sie diese jedoch verwenden und möglicherweise versehentlich einen Fehler machen? Verwenden Sie die stärksten verfügbaren Tools, es sei denn, Sie haben einen bestimmten Grund, dies nicht zu tun. Insgesamt empfehle ich dringend, eine Bibliothek zu benutzen und sich von den Details fernzuhalten, wenn Sie können.
UPDATE 05.04.18: Ich habe einige Teile umgeschrieben, um das Verständnis zu vereinfachen, und die empfohlene Bibliothek von Jasypt in Googles neue Bibliothek Tink geändert. Ich würde empfehlen, Jasypt vollständig aus einem vorhandenen Setup zu entfernen .
Vorwort
Ich werde im Folgenden die Grundlagen der sicheren symmetrischen Kryptographie skizzieren und auf häufige Fehler hinweisen, die ich online sehe, wenn Leute Krypto selbst mit der Standard-Java-Bibliothek implementieren. Wenn Sie nur alle Details überspringen möchten, die in die neue Google-Bibliothek Tink übertragen wurden, importieren Sie diese in Ihr Projekt und verwenden Sie den AES-GCM-Modus für alle Ihre Verschlüsselungen. So sind Sie sicher.
Wenn Sie nun die wichtigsten Details zum Verschlüsseln in Java erfahren möchten, lesen Sie weiter :)
Blockchiffren
Als erstes müssen Sie einen Blockchiffre mit symmetrischem Schlüssel auswählen. Eine Blockverschlüsselung ist eine Computerfunktion / ein Computerprogramm, mit dem Pseudozufälligkeit erzeugt wird. Pseudozufälligkeit ist eine gefälschte Zufälligkeit, die kein anderer Computer als ein Quantencomputer in der Lage wäre, den Unterschied zwischen ihm und der realen Zufälligkeit zu erkennen. Die Blockverschlüsselung ist wie der Baustein für die Kryptografie, und wenn sie mit verschiedenen Modi oder Schemata verwendet wird, können wir Verschlüsselungen erstellen.
Nun in Bezug auf Block - Cipher Algorithmen heute verfügbar, Achten Sie darauf, nie , ich wiederhole NIE verwenden DIE , ich würde sogar sagen nie verwenden 3DES . Die einzige Blockverschlüsselung, mit der sogar die NSA-Version von Snowden nachweisen konnte, dass sie Pseudo-Random so nahe wie möglich kommt, ist AES 256 . Es gibt auch AES 128; Der Unterschied besteht darin, dass AES 256 in 256-Bit-Blöcken arbeitet, während AES 128 in 128 Blöcken arbeitet. Alles in allem gilt AES 128 als sicher, obwohl einige Schwachstellen entdeckt wurden, aber 256 ist so solide wie es nur geht.
Unterhaltsame Tatsache DES wurde von der NSA bei ihrer Gründung gebrochen und tatsächlich einige Jahre lang geheim gehalten. Obwohl einige Leute immer noch behaupten, 3DES sei sicher, gibt es einige Forschungsarbeiten, die Schwachstellen in 3DES gefunden und analysiert haben .
Verschlüsselungsmodi
Die Verschlüsselung wird erstellt, wenn Sie eine Blockverschlüsselung verwenden und ein bestimmtes Schema verwenden, sodass die Zufälligkeit mit einem Schlüssel kombiniert wird, um etwas zu erstellen, das reversibel ist, solange Sie den Schlüssel kennen. Dies wird als Verschlüsselungsmodus bezeichnet.
Hier ist ein Beispiel für einen Verschlüsselungsmodus und den einfachsten Modus, der als EZB bezeichnet wird, damit Sie visuell verstehen können, was passiert:
Die Verschlüsselungsmodi, die Sie am häufigsten online sehen, sind die folgenden:
EZB CTR, CBC, GCM
Es gibt andere als die aufgeführten Modi, und die Forscher arbeiten ständig an neuen Modi, um bestehende Probleme zu verbessern.
Kommen wir nun zu den Implementierungen und dem, was sicher ist. Verwenden Sie die EZB NIEMALS. Dies ist schlecht, wenn Sie sich wiederholende Daten verbergen, wie der berühmte Linux-Pinguin zeigt .
Beachten Sie bei der Implementierung in Java, dass der EZB-Modus standardmäßig festgelegt ist, wenn Sie den folgenden Code verwenden:
Cipher cipher = Cipher.getInstance("AES");
... GEFAHR DAS IST EINE VULNERABILITÄT! und leider ist dies überall in StackOverflow und online in Tutorials und Beispielen zu sehen.
Nonces und IVs
Als Reaktion auf das Problem im EZB-Modus wurden Substantive, auch IVs genannt, erstellt. Die Idee ist, dass wir eine neue Zufallsvariable generieren und sie an jede Verschlüsselung anhängen, damit beim Verschlüsseln von zwei gleichen Nachrichten unterschiedliche Nachrichten ausgegeben werden. Das Schöne daran ist, dass eine IV oder Nonce öffentlich bekannt ist. Das bedeutet, dass ein Angreifer Zugriff darauf haben kann, aber solange er nicht über Ihren Schlüssel verfügt, kann er mit diesem Wissen nichts anfangen.
Häufige Probleme, die ich sehen werde, sind, dass Benutzer die IV als statischen Wert festlegen, wie in demselben festen Wert in ihrem Code. und hier ist die Gefahr für IVs, sobald Sie eine wiederholen, gefährden Sie tatsächlich die gesamte Sicherheit Ihrer Verschlüsselung.
Zufällige IV generieren
SecureRandom randomSecureRandom = SecureRandom.getInstance("SHA1PRNG");
byte[] iv = new byte[cipher.getBlockSize()];
randomSecureRandom.nextBytes(iv);
IvParameterSpec ivParams = new IvParameterSpec(iv);
Hinweis: SHA1 ist defekt, aber ich konnte nicht finden, wie SHA256 in diesem Anwendungsfall richtig implementiert werden kann. Wenn also jemand eine Pause einlegen und es aktualisieren möchte, wäre es fantastisch! Auch SHA1-Angriffe sind immer noch unkonventionell, da es einige Jahre dauern kann, bis ein riesiger Cluster geknackt ist. Details finden Sie hier.
CTR-Implementierung
Für den CTR-Modus ist keine Auffüllung erforderlich.
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
CBC-Implementierung
Wenn Sie den CBC-Modus implementieren möchten, gehen Sie wie folgt mit PKCS7Padding vor:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
CBC- und CTR-Sicherheitsanfälligkeit und warum Sie GCM verwenden sollten
Obwohl einige andere Modi wie CBC und CTR sicher sind, tritt das Problem auf, dass ein Angreifer die verschlüsselten Daten umdrehen und ihren Wert beim Entschlüsseln ändern kann. Nehmen wir also an, Sie verschlüsseln eine imaginäre Banknachricht "Sell 100". Ihre verschlüsselte Nachricht sieht wie folgt aus: "eu23ng". Der Angreifer ändert ein Bit in "eu53ng". Wenn Ihre Nachricht entschlüsselt wird, lautet sie plötzlich "Sell 900".
Um dies zu vermeiden, verwendet der Großteil des Internets GCM, und jedes Mal, wenn Sie HTTPS sehen, verwenden sie wahrscheinlich GCM. GCM signiert die verschlüsselte Nachricht mit einem Hash und überprüft, ob die Nachricht mit dieser Signatur nicht geändert wurde.
Ich würde die Implementierung von GCM aufgrund seiner Komplexität vermeiden. Sie sind besser dran, wenn Sie Googles neue Bibliothek Tink verwenden, denn auch hier gefährden Sie, wenn Sie versehentlich eine IV wiederholen, den Schlüssel im Fall von GCM, was die ultimative Sicherheitslücke darstellt. Neue Forscher arbeiten an IV-Wiederholungs-resistenten Verschlüsselungsmodi, bei denen der Schlüssel selbst dann nicht gefährdet ist, wenn Sie die IV wiederholen, aber dies ist noch kein Mainstream.
Wenn Sie nun GCM implementieren möchten, finden Sie hier einen Link zu einer netten GCM-Implementierung . Ich kann jedoch die Sicherheit nicht gewährleisten oder wenn sie ordnungsgemäß implementiert ist, aber die Basis ist schlecht. Beachten Sie auch, dass bei GCM keine Polsterung vorhanden ist.
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
Schlüssel gegen Passwörter
Ein weiterer sehr wichtiger Hinweis ist, dass bei der Kryptografie ein Schlüssel und ein Passwort nicht dasselbe sind. Ein Schlüssel in der Kryptographie muss ein gewisses Maß an Entropie und Zufälligkeit aufweisen, um als sicher zu gelten. Aus diesem Grund müssen Sie sicherstellen, dass Sie die richtigen kryptografischen Bibliotheken verwenden, um den Schlüssel für Sie zu generieren.
Sie haben also wirklich zwei Implementierungen, die Sie hier ausführen können. Die erste besteht darin, den Code in diesem StackOverflow-Thread für die Zufallsschlüsselgenerierung zu verwenden . Diese Lösung verwendet einen sicheren Zufallszahlengenerator, um einen Schlüssel von Grund auf neu zu erstellen, den Sie verwenden können.
Die andere weniger sichere Option ist die Verwendung von Benutzereingaben wie einem Kennwort. Das Problem, das wir besprochen haben, ist, dass das Passwort nicht genug Entropie hat, daher müssten wir PBKDF2 verwenden , einen Algorithmus, der das Passwort nimmt und es verstärkt. Hier ist eine StackOverflow-Implementierung, die mir gefallen hat . In der Google Tink-Bibliothek ist all dies integriert, und Sie sollten es nutzen.
Android-Entwickler
Ein wichtiger Punkt, auf den Sie hier hinweisen sollten, ist zu wissen, dass Ihr Android-Code rückentwickelbar ist und in den meisten Fällen auch der meiste Java-Code. Das heißt, wenn Sie das Passwort im Klartext in Ihrem Code speichern. Ein Hacker kann es leicht abrufen. Normalerweise möchten Sie für diese Art der Verschlüsselung die asymmetrische Kryptographie usw. verwenden. Dies liegt außerhalb des Rahmens dieses Beitrags, daher werde ich vermeiden, darauf einzugehen.
Eine interessante Lektüre aus dem Jahr 2013 : Weist darauf hin, dass 88% der Crypto-Implementierungen in Android nicht ordnungsgemäß durchgeführt wurden.
Abschließende Gedanken
Noch einmal, ich würde vorschlagen, die Java-Bibliothek für Krypto nicht direkt zu implementieren und Google Tink zu verwenden. Dies erspart Ihnen Kopfschmerzen, da sie wirklich gute Arbeit geleistet haben, um alle Algorithmen richtig zu implementieren. Und selbst dann sollten Sie sich über Probleme informieren, die auf dem Tink-Github aufgetreten sind. Hier und da tauchen Schwachstellen auf.
Wenn Sie Fragen oder Feedback haben, können Sie diese gerne kommentieren! Die Sicherheit ändert sich ständig und Sie müssen Ihr Bestes geben, um Schritt zu halten :)