Leitfaden zur Cipher-Klasse

Leitfaden für die Cipher-Klasse

1. Überblick

Einfach ausgedrückt ist Verschlüsselung der Vorgang des Codierens einer Nachricht, so dass nur autorisierte Benutzer sie verstehen oder darauf zugreifen können.

Die alsplaintext bezeichnete Nachricht wird mit einem Verschlüsselungsalgorithmus - acipher - verschlüsselt, derciphertext generiert und nur von autorisierten Benutzern durch Entschlüsselung gelesen werden kann.

In diesem Artikel beschreiben wir detailliertthe core Cipher class, which provides cryptographic encryption and decryption functionality in Java.

2. Chiffrierklasse

Java Cryptography Extension (JCE) istpart of the Java Cryptography Architecture (JCA), das eine Anwendung mit kryptografischen Chiffren für die Datenverschlüsselung und -entschlüsselung sowie für das Hashing privater Daten bereitstellt.

Die KlasseCipher, die sich im Paketjavax.crypto befindet, bildet den Kern des JCE-Frameworks und bietet die Funktionalität für die Ver- und Entschlüsselung.

2.1. Verschlüsselungsinstanziierung

Um einCipher-Objekt zu instanziieren, verwenden wircall the static getInstance method, passing the name of the requested transformation. Optional kann der Name eines Providers angegeben werden.

Schreiben wir eine Beispielklasse, die die Instanziierung vonCipher veranschaulicht:

public class Encryptor {

    public byte[] encryptMessage(byte[] message, byte[] keyBytes)
      throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        //...
    }
}

Die TransformationAES/ECB/PKCS5Padding weist diegetInstance-Methode an, dasCipher-Objekt alsAES-Chiffre mit ECBmode of operation und PKCS5padding scheme zu instanziieren.

Wir können dasCipher-Objekt auch instanziieren, indem wir nur den Algorithmus in der Transformation angeben:

Cipher cipher = Cipher.getInstance("AES");

In diesem Fall werden anbieterspezifische Standardwerte für den Modus und das Auffüllschema verwendet.

EinNoSuchAlgorithmException wird ausgelöst, wenn die Transformationnull ist, leer, in einem ungültigen Format oder die angegebene Implementierung des Verschlüsselungsalgorithmus vom angegebenen Anbieter nicht verfügbar ist.

NoSuchPaddingException wird ausgelöst, wenn die Transformation ein Auffüllschema enthält, das nicht verfügbar ist.

2.2. Keys

DieKey-Schnittstelle repräsentiert Schlüssel für kryptografische Operationen. Schlüssel sind undurchsichtige Container, die einen codierten Schlüssel, das Codierungsformat des Schlüssels und seinen kryptografischen Algorithmus enthalten.

Schlüssel werden im Allgemeinen durchkey generators, Zertifikate oderkey specifications unter Verwendung vonkey factory erhalten.

Erstellen wir aus den angegebenen Schlüsselbytes ein symmetrischesKey:

SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");

2.3. Verschlüsselungsinitialisierung

We call the init() method to initialize the Cipher object mit einemKey oderCertificate und einemopmode, die den Betriebsmodus der Chiffre angeben.

Optionalwe can pass in a source of randomness. Standardmäßig wird eineSecureRandom-Implementierung des installierten Anbieters mit der höchsten Priorität verwendet. Wird keine gefunden, wird eine vom System bereitgestellte Quelle verwendet.

We can specify a set of algorithm-specific parameters optionally. Zum Beispiel können wirIvParameterSpec anspecify an initialization vector übergeben.

Hier sind die verfügbaren Verschlüsselungsmodi:

  • ENCRYPT_MODE: Initialisiert das Objekt voncipherin den Verschlüsselungsmodus

  • DECRYPT_MODE: Initialisiert das Objekt voncipherin den Entschlüsselungsmodus

  • WRAP_MODE: Initialisiert das Objekt voncipherin den Modus vonkey-wrapping

  • UNWRAP_MODE: Initialisiert das Objekt voncipherin den Modus vonkey-unwrapping

Initialisieren wir dasCipher-Objekt:

Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
// ...

EinInvalidKeyException wird ausgelöst, wenn der angegebene Schlüssel nicht zum Initialisieren der Verschlüsselung geeignet ist, z. B. wenn eine Schlüssellänge / -codierung ungültig ist.

Es wird auch ausgelöst, wenn die Verschlüsselung bestimmte Algorithmusparameter erfordert, die nicht aus dem Schlüssel ermittelt werden können, oder wenn der Schlüssel eine Schlüsselgröße hat, die die maximal zulässige Schlüsselgröße überschreitet (ermittelt aus den Richtliniendateien vonconfigured JCE jurisdiction).

Schauen wir uns ein Beispiel mitCertificatean:

public byte[] encryptMessage(byte[] message, Certificate certificate)
  throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException {

    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(Cipher.ENCRYPT_MODE, certificate);
    // ...
}

Das ObjektCiphererhält den öffentlichen Schlüssel für die Datenverschlüsselung aus dem Zertifikat, indem die MethodegetPublicKeyaufgerufen wird.

2.4. Verschlüsselung und Entschlüsselung

Nach dem Initialisieren desCipher-Objekts rufen wir diedoFinal()-Methode auf, um die Verschlüsselungs- oder Entschlüsselungsoperation durchzuführen. Diese Methode gibt ein Byte-Array zurück, das die verschlüsselte oder entschlüsselte Nachricht enthält.

Die MethodedoFinal() setzt auch das ObjektCipherauf den Zustand zurück, in dem es sich befand, als es zuvor über einen Aufruf der Methodeinit()initialisiert wurde, wodurch das ObjektCipherzum Ver- oder Entschlüsseln verfügbar wird Mitteilungen.

Rufen wirdoFinal in unsererencryptMessage-Methode auf:

public byte[] encryptMessage(byte[] message, byte[] keyBytes)
  throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException,
    BadPaddingException, IllegalBlockSizeException {

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);
    return cipher.doFinal(message);
}

Um eine Entschlüsselungsoperation durchzuführen, ändern wiropmode inDECRYPT_MODE:

public byte[] decryptMessage(byte[] encryptedMessage, byte[] keyBytes)
  throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException,
    BadPaddingException, IllegalBlockSizeException {

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");
    cipher.init(Cipher.DECRYPT_MODE, secretKey);
    return cipher.doFinal(encryptedMessage);
}

2.5. Anbieter

Entwarf, einprovider-based architecture, dasJCE allows for qualified cryptography libraries such as BouncyCastle to be plugged in as security providers and new algorithms to be added seamlessly zu verwenden.

Fügen wir nun BouncyCastle als Sicherheitsanbieter hinzu. We can add a security provider either statically or dynamically.

To add BouncyCastle statically, we modify the java.security file befindet sich im Ordner<JAVA_HOME>/jre/lib/security.

Wir fügen die Zeile am Ende der Liste hinzu:

...
security.provider.4=com.sun.net.ssl.internal.ssl.Provider
security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=sun.security.jgss.SunProvider
security.provider.7=org.bouncycastle.jce.provider.BouncyCastleProvider

Beim Hinzufügen der Anbietereigenschaft hat der Eigenschaftsschlüssel das Formatsecurity.provider.N, wobei die ZahlN eins mehr ist als die letzte in der Liste.

We can also add the BouncyCastle security provider dynamically, ohne die Sicherheitsdatei ändern zu müssen:

Security.addProvider(new BouncyCastleProvider());

Wir können jetzt den Provider während der Verschlüsselungsinitialisierung angeben:

Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC");

BC gibt BouncyCastle als Anbieter an. Wir können die Liste der registrierten Anbieter über die MethodeSecurity.getProviders()abrufen.

3. Testen der Verschlüsselung und Entschlüsselung

Schreiben wir einen Beispieltest, um die Ver- und Entschlüsselung von Nachrichten zu veranschaulichen.

In diesem Test verwenden wir einen AES-Verschlüsselungsalgorithmus mit einem 128-Bit-Schlüssel und stellen fest, dass das entschlüsselte Ergebnis dem ursprünglichen Nachrichtentext entspricht:

@Test
public void whenIsEncryptedAndDecrypted_thenDecryptedEqualsOriginal()
  throws Exception {

    String encryptionKeyString =  "thisisa128bitkey";
    String originalMessage = "This is a secret message";
    byte[] encryptionKeyBytes = encryptionKeyString.getBytes();

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    SecretKey secretKey = new SecretKeySpec(encryptionKeyBytes, "AES");
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);

    byte[] encryptedMessageBytes = cipher.doFinal(message.getBytes());

    cipher.init(Cipher.DECRYPT_MODE, secretKey);

    byte[] decryptedMessageBytes = cipher.doFinal(encryptedMessageBytes);
    assertThat(originalMessage).isEqualTo(new String(decryptedMessageBytes));
}

4. Fazit

In diesem Artikel haben wir die KlasseCipher besprochen und Verwendungsbeispiele vorgestellt. Weitere Details zur KlasseCipher und zum JCE-Framework finden Sie in den Klassenclass documentation undJava Cryptography Architecture (JCA) Reference Guide.

Implementierung all dieser Beispiele und Codefragmentecan be foundover on Github; Dies ist ein Maven-basiertes Projekt, daher sollte es einfach zu importieren und auszuführen sein.