Hallo Habr! Ich präsentiere Ihnen die Übersetzung des zweiten Artikels "Java Cipher" von Jakob Jenkov aus einer Reihe von Artikeln für Anfänger , die die Grundlagen der Kryptographie in Java erlernen möchten.
Inhaltsverzeichnis:
- Kryptographie
- Chiffre
- Messagedigest
- Mac
- Unterschrift
- Schlüsselpaar
- Schlüsselgenerator
- KeyPairGenerator
- Keystore
- Keytool
- Zertifikat
- CertificateFactory
- CertPath
Java-Chiffre (Chiffre)
Die Java Cipher-Klasse ( javax.crypto.Cipher ) ist ein Verschlüsselungsalgorithmus. Der Begriff "Verschlüsselung" ist ein Standardbegriff für einen Verschlüsselungsalgorithmus in der Welt der Kryptographie. Aus diesem Grund wird die Java-Klasse als Cipher bezeichnet und nicht als Encryptor / Decryptor oder etwas anderes. Sie können eine Verschlüsselungsinstanz verwenden, um Daten in Java zu verschlüsseln und zu entschlüsseln. In diesem Kapitel wird die Funktionsweise der Cipher-Klasse erläutert.
Erstellung der Chiffre
Bevor Sie eine Verschlüsselung verwenden, müssen Sie eine Instanz der Cipher- Klasse erstellen, indem Sie ihre getInstance () -Methode mit einem Parameter aufrufen, der angibt, welche Art von Verschlüsselungsalgorithmus Sie verwenden möchten. Hier ist ein Beispiel zum Erstellen einer Java Cipher-Instanz:
Cipher cipher = Cipher.getInstance("AES");
In diesem Beispiel wird eine Verschlüsselungsinstanz mithilfe des AES-Verschlüsselungsalgorithmus erstellt.
Verschlüsselungsmodi
Einige Verschlüsselungsalgorithmen können in verschiedenen Modi arbeiten. Der Verschlüsselungsmodus bestimmt die Details, wie die Daten verschlüsselt werden. Somit beeinflusst der Verschlüsselungsmodus teilweise den Verschlüsselungsalgorithmus. Verschlüsselungsmodi können manchmal in mehreren verschiedenen Verschlüsselungsalgorithmen verwendet werden - als Methode, die dem Hauptverschlüsselungsalgorithmus hinzugefügt wird. Aus diesem Grund werden Modi getrennt von den Verschlüsselungsalgorithmen selbst betrachtet, sondern als „Ergänzungen“ zu Verschlüsselungsalgorithmen. Hier sind einige der bekanntesten Verschlüsselungsmodi:
- EBC - Elektronisches Codebuch (Electronic Codebook Mode )
- CBC - Chipher Block Chaining
- CFB - Cipher Feedback (Cipher Feedback Mode )
- OFB - Ausgangsfeedback
- CTR - Zähler ( Zählermodus )
Wenn Sie eine Instanz einer Verschlüsselung erstellen, können Sie deren Modus zum Namen des Verschlüsselungsalgorithmus hinzufügen. Sie können eine AES-Verschlüsselungsinstanz im Blockkopplungsmodus - Cipher Block Chaining (CBC) wie folgt erstellen:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
Da der Kopplungsmodus der Verschlüsselungsblöcke auch ein " Auffüllschema " erfordert, wird das Auffüllschema ( PKCS5Padding ) am Ende der Zeichenfolge des Namens des Verschlüsselungsalgorithmus hinzugefügt.
Es ist wichtig zu wissen, dass nicht alle Verschlüsselungsalgorithmen und -modi vom Java SDK-Verschlüsselungsanbieter standardmäßig unterstützt werden. Um die benötigte Verschlüsselungsinstanz mit dem erforderlichen Modus und Füllmuster zu erstellen, müssen Sie möglicherweise einen Drittanbieter wie Bouncy Castle installieren.
Verschlüsselungsinitialisierung
Bevor eine Cipher-Instanz verwendet wird, muss sie initialisiert werden. Die Verschlüsselung wird durch Aufrufen ihrer init () -Methode initialisiert. Die Methode init () akzeptiert zwei Parameter:
Ein Beispiel für die Initialisierung einer Cipher-Instanz im Verschlüsselungsmodus:
Key key = ...
Und hier ist ein Beispiel für die Initialisierung einer Cipher-Instanz, die sich bereits im Entschlüsselungsmodus befindet:
Key key = ...
Datenverschlüsselung und -entschlüsselung
Um Daten mit einer Cipher-Instanz zu verschlüsseln oder zu entschlüsseln, wird eine dieser beiden Methoden aufgerufen:
Es gibt mehrere überschriebene Versionen der Methoden update () und doFinal () , die unterschiedliche Parameter annehmen. Betrachten Sie die hier am häufigsten verwendeten. Wenn Sie einen einzelnen Datenblock verschlüsseln oder entschlüsseln müssen, rufen Sie einfach doFinal () mit den zu verschlüsselnden oder zu entschlüsselnden Daten auf. Ein Beispiel:
byte[] plainText = "abcdefghijklmnopqrstuvwxyz".getBytes("UTF-8"); byte[] cipherText = cipher.doFinal(plainText);
Tatsächlich sieht der Code bei der Datenentschlüsselung ungefähr gleich aus. Denken Sie daran, dass die Cipher-Instanz im Entschlüsselungsmodus initialisiert werden muss. So sieht die Entschlüsselung eines Chiffretextblocks aus:
byte[] plainText = cipher.doFinal(cipherText);
Wenn Sie eine große Datei, die in mehrere Blöcke unterteilt ist, verschlüsseln oder entschlüsseln müssen, wird update () einmal für jeden Datenblock aufgerufen und endet mit einem Aufruf der Methode doFinal () mit dem letzten Datenblock. Hier ist ein Beispiel für die Verschlüsselung mehrerer Datenblöcke:
byte[] data1 = "abcdefghijklmnopqrstuvwxyz".getBytes("UTF-8"); byte[] data2 = "zyxwvutsrqponmlkjihgfedcba".getBytes("UTF-8"); byte[] data3 = "01234567890123456789012345".getBytes("UTF-8"); byte[] cipherText1 = cipher.update(data1); byte[] cipherText2 = cipher.update(data2); byte[] cipherText3 = cipher.doFinal(data3);
Der Grund, warum der Aufruf von doFinal () für den letzten Datenblock benötigt wird, liegt darin, dass einige Verschlüsselungsalgorithmen die Daten ergänzen müssen, um sie an eine bestimmte Größe des Verschlüsselungsblocks anzupassen ( z. B. eine 8-Byte-Grenze). Es ist nicht erforderlich, verschlüsselte Zwischendaten zu ergänzen. Daher wird die update () -Methode für die Zwischendatenblöcke und der doFinal () -Aufruf für den letzten Datenblock aufgerufen.
Wenn Sie mehrere Datenblöcke entschlüsseln, rufen Sie auch die update () -Methode für Zwischendatenblöcke und die doFinal () -Methode für den letzten Block auf. Beispiel für die Entschlüsselung mehrerer Datenblöcke:
byte[] plainText1 = cipher.update(cipherText1); byte[] plainText2 = cipher.update(cipherText2); byte[] plainText3 = cipher.doFinal(cipherText3);
Auch hier muss die Verschlüsselungsinstanz im Entschlüsselungsmodus initialisiert werden, damit dieses Beispiel funktioniert.
Verschlüsselung / Entschlüsselung eines Teils eines Byte-Arrays
Verschlüsselungs- und Entschlüsselungsmethoden der Cipher-Klasse können einige der in einem Byte-Array gespeicherten Daten verschlüsseln oder entschlüsseln. Die Methode update () und / oder doFinal () muss den Versatz und die Länge übergeben.
int offset = 10; int length = 24; byte[] cipherText = cipher.doFinal(data, offset, length);
In diesem Beispiel werden Bytes ab Index 10 und vorwärts 24 Bytes verschlüsselt (oder je nach Initialisierung der Verschlüsselung entschlüsselt).
Verschlüsselung / Entschlüsselung in ein vorhandenes Byte-Array
Alle Verschlüsselungs- und Entschlüsselungsbeispiele in diesem Kapitel geben verschlüsselte oder entschlüsselte Daten in einem neuen Byte-Array zurück. Es ist jedoch auch möglich, Daten in ein vorhandenes Byte-Array zu verschlüsseln oder zu entschlüsseln. Dies kann nützlich sein, um die Anzahl der erstellten Byte-Arrays zu verringern. Übergeben Sie dazu das Zielbyte- Array als Parameter an die Methode update () und / oder doFinal () .
int offset = 10; int length = 24; byte[] dest = new byte[1024]; cipher.doFinal(data, offset, length, dest);
In diesem Beispiel werden die Daten von 10 Index-24-Bytes vorwärts zum Zielbyte-Array mit Offset 0 verschlüsselt. Wenn Sie einen anderen Offset für das Zielbyte-Array festlegen möchten, gibt es die Versionen update () und doFinal () , die einen zusätzlichen Offset-Parameter akzeptieren. Ein Beispiel für den Aufruf der Methode doFinal () mit einem Offset im Zielarray:
int offset = 10; int length = 24; byte[] dest = new byte[1024]; int destOffset = 12 cipher.doFinal(data, offset, length, dest, destOffset);
Wiederverwendung einer Instanz einer Chiffre
Das Initialisieren einer Verschlüsselungsinstanz ist eine teure Operation, und die Wiederverwendung von Verschlüsselungsinstanzen ist eine gute Idee. Glücklicherweise wurde die Cipher-Klasse unter Berücksichtigung der Wiederverwendbarkeit entwickelt. Wenn Sie die Methode doFinal () für die Cipher-Instanz aufrufen, kehrt sie in den Zustand zurück, in dem sie sich unmittelbar nach der Initialisierung befand. Die Verschlüsselungsinstanz kann dann verwendet werden, um weitere Daten zu verschlüsseln oder zu entschlüsseln.
Ein Beispiel für die Wiederverwendung einer Java Cipher-Instanz:
Cipher cipher = Cipher.getInstance("AES"); Key key = ...
Zuerst wird eine Verschlüsselungsinstanz erstellt und initialisiert und dann zum Verschlüsseln von zwei Blöcken konsistenter Daten verwendet. Beachten Sie den Aufruf von update () und dann doFinal () für diese beiden Datenblöcke. Danach kann die Cipher-Instanz erneut zum Verschlüsseln der Daten verwendet werden. Dies erfolgt durch Aufrufen von doFinal () mit einem dritten Datenblock. Nach diesem Aufruf von doFinal () können Sie einen weiteren Datenblock mit derselben Java Cipher-Instanz verschlüsseln.