Kryptografie

In diesem Dokument wird die richtige Verwendung der kryptografischen Funktionen von Android beschrieben. Außerdem sind einige Beispiele für die Verwendung enthalten. Wenn Ihre App eine höhere Schlüsselsicherheit erfordert, verwenden Sie das Android Keystore-System.

Anbieter nur mit dem Android-Keystore-System angeben

Wenn Sie das Android Keystore-System verwenden, müssen Sie einen Anbieter angeben.

In anderen Situationen garantiert Android jedoch keinen bestimmten Anbieter für einen bestimmten Algorithmus. Wenn Sie einen Anbieter angeben, ohne das Android Keystore-System zu verwenden, kann dies in zukünftigen Releases zu Kompatibilitätsproblemen führen.

Empfohlenen Algorithmus auswählen

Wenn Sie die Möglichkeit haben, den zu verwendenden Algorithmus selbst zu wählen (z. B. wenn keine Kompatibilität mit einem Drittanbietersystem erforderlich ist), empfehlen wir die folgenden Algorithmen:

Klasse Empfehlung
Chiffre AES im CBC- oder GCM-Modus mit 256-Bit-Schlüsseln (z. B. AES/GCM/NoPadding)
MessageDigest SHA-2-Familie (z. B. SHA-256)
Mac HMAC der SHA-2-Familie (z. B. HMACSHA256)
Unterschrift SHA-2-Familie mit ECDSA (z. B. SHA256withECDSA)

Häufige kryptografische Vorgänge ausführen

Die folgenden Abschnitte enthalten Snippets, die zeigen, wie Sie gängige kryptografische Vorgänge in Ihrer App ausführen können.

Nachricht verschlüsseln

Kotlin

val plaintext: ByteArray = ...
val keygen = KeyGenerator.getInstance("AES")
keygen.init(256)
val key: SecretKey = keygen.generateKey()
val cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING")
cipher.init(Cipher.ENCRYPT_MODE, key)
val ciphertext: ByteArray = cipher.doFinal(plaintext)
val iv: ByteArray = cipher.iv

Java

byte[] plaintext = ...;
KeyGenerator keygen = KeyGenerator.getInstance("AES");
keygen.init(256);
SecretKey key = keygen.generateKey();
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] ciphertext = cipher.doFinal(plaintext);
byte[] iv = cipher.getIV();

Nachrichtenzusammenfassung generieren

Kotlin

val message: ByteArray = ...
val md = MessageDigest.getInstance("SHA-256")
val digest: ByteArray = md.digest(message)

Java

byte[] message = ...;
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] digest = md.digest(message);

Digitale Signatur generieren

Sie benötigen ein PrivateKey-Objekt mit dem Signaturschlüssel, das Sie je nach Bedarf zur Laufzeit generieren, aus einer mit Ihrer App gebündelten Datei lesen oder aus einer anderen Quelle abrufen können.

Kotlin

val message: ByteArray = ...
val key: PrivateKey = ...
val s = Signature.getInstance("SHA256withECDSA")
        .apply {
            initSign(key)
            update(message)
        }
val signature: ByteArray = s.sign()

Java

byte[] message = ...;
PrivateKey key = ...;
Signature s = Signature.getInstance("SHA256withECDSA");
s.initSign(key);
s.update(message);
byte[] signature = s.sign();

Digitale Signatur überprüfen

Sie benötigen ein PublicKey-Objekt mit dem öffentlichen Schlüssel des Unterzeichners. Dieses können Sie je nach Bedarf aus einer Datei lesen, die mit Ihrer App gebündelt ist, aus einem Zertifikat extrahieren oder aus einer anderen Quelle abrufen.

Kotlin

val message: ByteArray = ...
val signature: ByteArray = ...
val key: PublicKey = ...
val s = Signature.getInstance("SHA256withECDSA")
        .apply {
            initVerify(key)
            update(message)
        }
val valid: Boolean = s.verify(signature)

Java

byte[] message = ...;
byte[] signature = ...;
PublicKey key = ...;
Signature s = Signature.getInstance("SHA256withECDSA");
s.initVerify(key);
s.update(message);
boolean valid = s.verify(signature);

Komplexität der Implementierung

Einige Details der Android-Kryptografieimplementierung scheinen ungewöhnlich, sind aber aus Kompatibilitätsgründen vorhanden. In diesem Abschnitt werden die Fehler behandelt, die am wahrscheinlichsten auftreten.

OAEP-MGF1-Nachrichtendigest

RSA-OAEP-Chiffren werden durch zwei verschiedene Message Digests parametrisiert: den „Haupt“-Digest und den MGF1-Digest. Es gibt Cipher-Kennungen, die Digest-Namen enthalten, z. B. Cipher.getInstance("RSA/ECB/OAEPwithSHA-256andMGF1Padding"). Damit wird der Haupt-Digest angegeben, der MGF1-Digest bleibt jedoch unspezifiziert. Für Android Keystore wird SHA-1 für den MGF1-Digest verwendet, während die beiden Digests für andere kryptografische Android-Anbieter identisch sind.

Wenn Sie mehr Kontrolle über die Digests haben möchten, die von Ihrer App verwendet werden, fordern Sie eine Chiffre mit OAEPPadding an, wie in Cipher.getInstance("RSA/ECB/OAEPPadding"), und geben Sie einen OAEPParameterSpec für init() an, um beide Digests explizit auszuwählen. Dies wird im folgenden Code gezeigt:

Kotlin

val key: Key = ...
val cipher = Cipher.getInstance("RSA/ECB/OAEPPadding")
        .apply {
            // To use SHA-256 the main digest and SHA-1 as the MGF1 digest
            init(Cipher.ENCRYPT_MODE, key, OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT))
            // To use SHA-256 for both digests
            init(Cipher.ENCRYPT_MODE, key, OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT))
        }

Java

Key key = ...;
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding");
// To use SHA-256 the main digest and SHA-1 as the MGF1 digest
cipher.init(Cipher.ENCRYPT_MODE, key, new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT));
// To use SHA-256 for both digests
cipher.init(Cipher.ENCRYPT_MODE, key, new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));

Eingestellte Funktionen

In den folgenden Abschnitten werden eingestellte Funktionen beschrieben. Verwenden Sie es nicht in Ihrer App.

Bouncy Castle-Algorithmen

Die Bouncy Castle-Implementierungen vieler Algorithmen sind veraltet. Dies betrifft nur Fälle, in denen Sie den Bouncy Castle-Provider explizit anfordern, wie im folgenden Beispiel gezeigt:

Kotlin

Cipher.getInstance("AES/CBC/PKCS7PADDING", "BC")
// OR
Cipher.getInstance("AES/CBC/PKCS7PADDING", Security.getProvider("BC"))

Java

Cipher.getInstance("AES/CBC/PKCS7PADDING", "BC");
// OR
Cipher.getInstance("AES/CBC/PKCS7PADDING", Security.getProvider("BC"));

Wie im Abschnitt Anbieter nur mit dem Android-Keystore-System angeben beschrieben, wird davon abgeraten, einen bestimmten Anbieter anzufordern. Wenn Sie diese Richtlinie einhalten, sind Sie von der Einstellung nicht betroffen.

Passwortbasierte Verschlüsselungschiffren ohne Initialisierungsvektor

PBE-Verschlüsselungen (Password-Based Encryption), die einen Initialisierungsvektor (IV) erfordern, können diesen aus dem Schlüssel beziehen, sofern er entsprechend aufgebaut ist, oder aus einem explizit übergebenen IV. Wenn Sie einen PBE-Schlüssel übergeben, der keinen IV enthält, und keinen expliziten IV übergeben, gehen die PBE-Chiffren auf Android derzeit von einem IV von null aus.

Wenn Sie PBE-Chiffren verwenden, übergeben Sie immer einen expliziten IV, wie im folgenden Code-Snippet gezeigt:

Kotlin

val key: SecretKey = ...
val cipher = Cipher.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC")
val iv = ByteArray(16)
SecureRandom().nextBytes(iv)
cipher.init(Cipher.ENCRYPT_MODE, key, IvParameterSpec(iv))

Java

SecretKey key = ...;
Cipher cipher = Cipher.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC");
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));

Kryptoanbieter

Ab Android 9 (API-Level 28) wurde der Crypto JCA-Provider (Java Cryptography Architecture) entfernt. Wenn Ihre App eine Instanz des Krypto-Anbieters anfordert, z. B. durch Aufrufen der folgenden Methode, tritt ein NoSuchProviderException auf.

Kotlin

SecureRandom.getInstance("SHA1PRNG", "Crypto")

Java

SecureRandom.getInstance("SHA1PRNG", "Crypto");

Jetpack-Bibliothek „security-crypto“

Alle APIs in der security-crypto-Jetpack-Bibliothek wurden in der stabilen Version 1.1.0 verworfen. Es wird keine weiteren Releases dieser Bibliothek geben.

Die Hinweise zur Einstellung sind sichtbar, wenn Sie eine der folgenden Abhängigkeiten in der build.gradle-Datei Ihres App-Moduls haben:

Groovy

dependencies {
    implementation "androidx.security:security-crypto:1.1.0"
    // or
    implementation "androidx.security:security-crypto-ktx:1.1.0"
}

Kotlin

dependencies {
    implementation("androidx.security:security-crypto:1.1.0")
    // or
    implementation("androidx.security:security-crypto-ktx:1.1.0")
}

Unterstützte Algorithmen

Dies sind die JCA-Algorithmuskennungen, die unter Android unterstützt werden: