Ce document décrit la bonne utilisation des systèmes cryptographiques d'Android et inclut quelques exemples d'utilisation. Si votre application nécessite une sécurité renforcée des clés, utilisez le système Android Keystore.
Spécifier un fournisseur uniquement si vous utilisez le système Android Keystore
Si vous utilisez le système Android Keystore, vous devez spécifier un fournisseur.
Dans d'autres cas, Android ne garantit toutefois pas de fournisseur particulier pour un algorithme donné. Si vous spécifiez un fournisseur sans utiliser le système Android Keystore, vous risquez de rencontrer des problèmes de compatibilité dans les prochaines versions.
Choisir un algorithme recommandé
Lorsque vous êtes libre de choisir l'algorithme à utiliser (par exemple, lorsque vous n'avez pas à vous soucier de la compatibilité avec un système tiers), nous vous recommandons d'utiliser les algorithmes suivants :
Classe | Recommandation |
---|---|
Algorithme de chiffrement | AES en mode CBC ou GCM avec des clés 256 bits (comme AES/GCM/NoPadding ) |
Condensé du message | Famille SHA-2 (SHA-256 , par exemple) |
Mac | HMAC de la famille SHA-2 (HMACSHA256 , par exemple) |
Signature | Famille SHA-2 avec ECDSA (SHA256withECDSA , par exemple) |
Effectuer des opérations cryptographiques courantes
Les sections suivantes incluent des extraits qui montrent comment effectuer des opérations cryptographiques courantes dans votre application.
Chiffrer un message
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();
Générer un condensé du message
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);
Générer une signature numérique
Vous devez disposer d'un objet PrivateKey
contenant la clé de signature, que vous pouvez générer lors de l'exécution, lire à partir d'un fichier fourni avec votre application ou obtenir auprès d'une autre source selon vos besoins.
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();
Valider une signature numérique
Vous devez disposer d'un objet PublicKey
contenant la clé publique du signataire, que vous pouvez lire à partir d'un fichier fourni avec votre application, extraire d'un certificat ou obtenir à partir d'une autre source en fonction de vos besoins.
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);
Complexité de l'implémentation
Certains détails d'implémentation de la cryptographie Android, qui semblent inhabituels, sont dus à des problèmes de compatibilité. Cette section présente ceux que vous êtes le plus susceptible de rencontrer.
Condensé du message OAEP MGF1
Les algorithmes de chiffrement OAEP RSA sont paramétrés par deux condensés de messages différents : le condensé principal ("main") et le condensé MGF1. Il existe des identifiants Cipher
qui incluent des noms de condensé, tels que Cipher.getInstance("RSA/ECB/OAEPwithSHA-256andMGF1Padding")
, qui spécifie le condensé principal et ne spécifie pas le condensé MGF1. Pour Android Keystore, SHA-1 est utilisé pour le condensé MGF1, tandis que pour les autres fournisseurs de chiffrement Android, les deux condensés sont identiques.
Pour mieux contrôler les condensés utilisés par votre application, vous devez demander un chiffrement avec OAEPPadding, comme dans Cipher.getInstance("RSA/ECB/OAEPPadding")
, et fournir un élément OAEPParameterSpec
à init()
pour choisir explicitement les deux condensés.
Ce processus est illustré dans le code suivant :
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));
Fonctionnalité obsolète
Les sections suivantes décrivent des fonctionnalités obsolètes. Ne les utilisez pas dans votre application.
Algorithmes "Bouncy Castle"
Les implémentations Bouncy Castle de nombreux algorithmes sont obsolètes. Cela ne concerne que les cas où vous demandez explicitement le fournisseur Bouncy Castle, comme illustré dans l'exemple suivant :
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"));
Comme indiqué dans la section expliquant comment spécifier un fournisseur uniquement avec le système Android Keystore, il est déconseillé de demander un fournisseur spécifique. Si vous suivez cette consigne, cette obsolescence ne vous concerne pas.
Chiffrement par mot de passe sans vecteur d'initialisation
Les algorithmes de chiffrement basés sur des mots de passe, également appelés algorithmes de chiffrement PBE (Password-Based Encryption), nécessitent un vecteur d'initialisation. Ils peuvent l'obtenir à partir de la clé, si sa construction est correcte, ou si le vecteur d'initialisation a été explicitement transmis. Lors du transfert d'une clé PBE qui ne contient pas de vecteur d'initialisation et qui n'implique aucun vecteur d'initialisation explicite, les algorithmes de chiffrement PBE sur Android supposent actuellement un vecteur d'initialisation de zéro.
Lorsque vous utilisez des algorithmes de chiffrement PBE, transmettez toujours un vecteur d'initialisation explicite, comme indiqué dans l'extrait de code suivant :
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));
Fournisseur Crypto
À partir d'Android 9 (niveau d'API 28), le fournisseur JCA (Java Cryptography Architecture) Crypto a été supprimé. Si votre application demande une instance de ce fournisseur, par exemple en appelant la méthode suivante, une exception NoSuchProviderException
se produit.
Kotlin
SecureRandom.getInstance("SHA1PRNG", "Crypto")
Java
SecureRandom.getInstance("SHA1PRNG", "Crypto");
Bibliothèque de chiffrement de sécurité Jetpack
La bibliothèque de chiffrement de sécurité Jetpack est obsolète. Cela ne concerne que les cas où vous avez les dépendances suivantes dans le fichier build.gradle
de votre module d'application :
Groovy
dependencies { implementation "androidx.security:security-crypto:1.0.0" }
Kotlin
dependencies { implementation("androidx.security:security-crypto:1.0.0") }
Algorithmes compatibles
Voici les identifiants de l'algorithme JCA compatibles avec Android :
AlgorithmParameterGenerator
AlgorithmParameters
CertPathBuilder
CertPathValidator
CertStore
CertificateFactory
Cipher
KeyAgreement
KeyFactory
KeyGenerator
KeyManagerFactory
KeyPairGenerator
KeyStore
Mac
MessageDigest
SSLContext
SSLEngine.Supported
SSLSocket.Supported
SecretKeyFactory
SecureRandom
Signature
TrustManagerFactory