Kryptografie

In diesem Dokument wird die ordnungsgemäße Verwendung der kryptografischen Funktionen von Android beschrieben. Außerdem finden Sie einige Beispiele für deren Verwendung. Wenn für Ihre App eine höhere Schlüsselsicherheit erforderlich ist, 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 Fällen kann Android jedoch keinen bestimmten Anbieter für einen bestimmten Algorithmus garantieren. Wenn Sie einen Anbieter angeben, ohne das Android-Schlüsselspeichersystem zu verwenden, kann dies zu Kompatibilitätsproblemen bei zukünftigen Releases führen.

Empfohlenen Algorithmus auswählen

Wenn Sie den Algorithmus frei auswählen können (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)

Gängige kryptografische Vorgänge ausführen

In den folgenden Abschnitten finden Sie Snippets, die zeigen, wie Sie gängige kryptografische Vorgänge in Ihrer App ausführen.

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();

Nachrichten-Digest 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 prüfen

Sie benötigen ein PublicKey-Objekt mit dem öffentlichen Schlüssel des Unterzeichners. Sie können diesen aus einer Datei lesen, die mit Ihrer App gebündelt ist, aus einem Zertifikat extrahieren oder je nach Bedarf 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 wirken auf den ersten Blick ungewöhnlich, sind aber aus Kompatibilitätsgründen erforderlich. In diesem Abschnitt werden die Probleme beschrieben, die am ehesten auftreten.

OAEP MGF1-Nachrichten-Digest

RSA-OAEP-Verschlüsselungen werden durch zwei verschiedene Nachrichten-Digests parametrisiert: den „Haupt-Digest“ und den MGF1-Digest. Es gibt Cipher-IDs, die Digestnamen enthalten, z. B. Cipher.getInstance("RSA/ECB/OAEPwithSHA-256andMGF1Padding"), die den Haupt-Digest angibt und den MGF1-Digest nicht spezifiziert. Für den Android Keystore wird SHA-1 für den MGF1-Digest verwendet, während bei anderen kryptografischen Anbietern von Android die beiden Digests identisch sind.

Wenn Sie mehr Kontrolle über die von Ihrer App verwendeten Hash-Werte haben möchten, fordern Sie eine Chiffre mit OAEPPadding an, wie in Cipher.getInstance("RSA/ECB/OAEPPadding"), und geben Sie OAEPParameterSpec bis init() an, um beide Hash-Werte explizit auszuwählen. Dies wird im folgenden Code veranschaulicht:

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 sie nicht in Ihrer App.

Bouncy Castle-Algorithmen

Die Bouncy Castle-Implementierungen vieler Algorithmen sind eingestellt. Dies gilt nur für Fälle, in denen Sie den Bouncy Castle-Anbieter ausdrücklich 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 über das Android Keystore-System angeben erwähnt, wird davon abgeraten, einen bestimmten Anbieter anzufordern. Wenn Sie dieser Richtlinie folgen, sind Sie von der Einstellung nicht betroffen.

Passwortbasierte Verschlüsselungschiffren ohne Initialisierungsvektor

Bei PBE-Verschlüsselungen (Password-Based Encryption), die einen Initialisierungsvektor (IV) erfordern, kann dieser aus dem Schlüssel abgerufen werden, sofern er entsprechend aufgebaut ist, oder aus einem explizit übergebenen IV. Wenn Sie einen PBE-Schlüssel übergeben, der keine IV enthält, und keine explizite IV übergeben, wird bei den PBE-Verschlüsselungen unter Android derzeit eine IV von null angenommen.

Wenn Sie PBE-Chiffren verwenden, geben Sie immer eine explizite IV an, 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));

Krypto-Anbieter

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

Kotlin

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

Java

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

Krypto-Bibliothek für Jetpack-Sicherheit

Die Krypto-Bibliothek von Jetpack Security wird nicht mehr unterstützt. Dies betrifft nur Fälle, in denen die folgenden Abhängigkeiten in der build.gradle-Datei Ihres App-Moduls enthalten sind:

Groovy

dependencies {
    implementation "androidx.security:security-crypto:1.0.0"
}

Kotlin

dependencies {
    implementation("androidx.security:security-crypto:1.0.0")
}

Unterstützte Algorithmen

Folgende JCA-Algorithmus-IDs werden auf Android-Geräten unterstützt: