Questo documento descrive il modo corretto di utilizzare le strutture di crittografia di Android e include alcuni esempi di utilizzo. Se la tua app richiede maggiore sicurezza delle chiavi, utilizza il sistema Android Keystore.
Specifica un provider solo con il sistema Android Keystore
Se utilizzi il sistema Android Keystore, devi specificare un provider.
In altre situazioni, tuttavia, Android non garantisce un determinato provider per un determinato algoritmo. La specifica di un provider senza utilizzare il sistema Android Keystore può causare problemi di compatibilità nelle release future.
Scegliere un algoritmo consigliato
Quando hai la libertà di scegliere quale algoritmo utilizzare (ad esempio quando non richiedi la compatibilità con un sistema di terze parti), ti consigliamo di utilizzare i seguenti algoritmi:
Classe | Consiglio |
---|---|
Cipher | AES in modalità CBC o GCM con chiavi a 256 bit (ad esempio AES/GCM/NoPadding ) |
MessageDigest | Famiglia SHA-2 (ad esempio SHA-256 ) |
Mac | HMAC della famiglia SHA-2 (ad esempio HMACSHA256 ) |
Firma | Famiglia SHA-2 con ECDSA (ad esempio SHA256withECDSA ) |
Eseguire operazioni crittografiche comuni
Le seguenti sezioni includono snippet che mostrano come completare operazioni di crittografia comuni nella tua app.
Criptare un messaggio
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();
Generare un riepilogo dei messaggi
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);
Generare una firma digitale
Devi avere un oggetto PrivateKey
contenente la chiave di firma, che puoi generare in fase di esecuzione, leggere da un file incluso nella tua app o ottenere da un'altra fonte, a seconda delle tue esigenze.
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();
Verificare una firma digitale
Devi disporre di un oggetto PublicKey
contenente la chiave pubblica del firmatario,
che puoi leggere da un file in bundle con la tua app, estrarre da un
certificato o
ottenere da un'altra fonte a seconda delle tue esigenze.
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);
Complessità di implementazione
Esistono alcuni dettagli dell'implementazione della crittografia Android che sembrano insoliti, ma sono presenti a causa di problemi di compatibilità. In questa sezione vengono descritti quelli che incontrerai molto probabilmente.
Digest del messaggio MGF1 OAEP
Le cifre RSA OAEP sono parametrizzate da due diversi digest dei messaggi: il digest "principale" e il digest MGF1. Esistono identificatori Cipher
che includono nomi di digest, come Cipher.getInstance("RSA/ECB/OAEPwithSHA-256andMGF1Padding")
,
che specifica il digest principale e lascia indefinito il digest MGF1. Per Android Keystore, viene utilizzato SHA-1 per il digest MGF1, mentre per altri fornitori di crittografia Android i due digest sono uguali.
Per avere un maggiore controllo sui digest utilizzati dalla tua app, richiedi un'operazione di crittografia con OAEPPadding, come in Cipher.getInstance("RSA/ECB/OAEPPadding")
, e fornisci un valore OAEPParameterSpec
a init()
per scegliere esplicitamente entrambi i digest.
Ciò viene mostrato nel codice che segue:
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));
Funzionalità ritirate
Le sezioni seguenti descrivono le funzionalità ritirate. Non utilizzarlo nella tua app.
Algoritmi di Bouncy Castle
Le implementazioni di Bouncy Castle di molti algoritmi sono ritirate. Questo riguarda solo i casi in cui richiedi esplicitamente il provider Castello gonfiabile, come mostrato nell'esempio seguente:
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"));
Come indicato nella sezione relativa a specificare un provider solo con il sistema Android Keystore, sconsigliamo di richiedere un provider specifico. Se segui queste linee guida, il ritiro non ti interessa.
Cifrari di crittografia basati su password senza un vettore di inizializzazione
Gli algoritmi di crittografia con password (PBE) che richiedono un vettore di inizializzazione (IV) possono ottenerlo dalla chiave, se è opportunamente costruita, o da un IV passato esplicitamente. Se passi una chiave PBE che non contiene un IV e non passi un IV esplicito, al momento le crittografie PBE su Android presuppongono un IV pari a zero.
Quando utilizzi i cifrari PBE, passa sempre un IV esplicito, come mostrato nel seguente s snippet di codice:
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));
Fornitore di criptovalute
A partire da Android 9 (livello API 28), il provider JCA (Crypto Java Cryptography Architecture)
è stato rimosso. Se la tua app richiede un'istanza del fornitore di crittografia, ad esempio chiamando il seguente metodo, si verifica un NoSuchProviderException
.
Kotlin
SecureRandom.getInstance("SHA1PRNG", "Crypto")
Java
SecureRandom.getInstance("SHA1PRNG", "Crypto");
Libreria di crittografia per la sicurezza di Jetpack
La libreria di crittografia di Jetpack Security è deprecata. Questo riguarda solo i casi in cui
hai le seguenti dipendenze nel file build.gradle
del modulo dell'app:
Alla moda
dependencies { implementation "androidx.security:security-crypto:1.0.0" }
Kotlin
dependencies { implementation("androidx.security:security-crypto:1.0.0") }
Algoritmi supportati
Questi sono gli identificatori degli algoritmi JCA supportati su 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