В этом документе описывается правильное использование криптографических средств Android и приводятся примеры их использования. Если вашему приложению требуется более высокая степень защиты ключей, используйте систему Android Keystore .
Укажите поставщика только с помощью системы Android Keystore
Если вы используете систему Android Keystore, вам необходимо указать поставщика.
Однако в других ситуациях Android не гарантирует наличие конкретного поставщика для заданного алгоритма. Указание поставщика без использования системы Android Keystore может привести к проблемам совместимости в будущих версиях.
Выберите рекомендуемый алгоритм
Если у вас есть свобода выбора используемого алгоритма (например, если вам не требуется совместимость со сторонней системой), мы рекомендуем использовать следующие алгоритмы:
Сорт | Рекомендация |
---|---|
Шифр | AES в режиме CBC или GCM с 256-битными ключами (например, AES/GCM/NoPadding ) |
MessageDigest | Семейство SHA-2 (например, SHA-256 ) |
Мак | Семейство SHA-2 HMAC (например, HMACSHA256 ) |
Подпись | Семейство SHA-2 с ECDSA (например, SHA256withECDSA ) |
Выполнять общие криптографические операции
В следующих разделах приведены фрагменты, демонстрирующие, как можно выполнять распространенные криптографические операции в вашем приложении.
Зашифровать сообщение
Котлин
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
Ява
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();
Сформировать дайджест сообщения
Котлин
val message: ByteArray = ... val md = MessageDigest.getInstance("SHA-256") val digest: ByteArray = md.digest(message)
Ява
byte[] message = ...; MessageDigest md = MessageDigest.getInstance("SHA-256"); byte[] digest = md.digest(message);
Создать цифровую подпись
Вам необходим объект PrivateKey
, содержащий ключ подписи, который вы можете сгенерировать во время выполнения, прочитать из файла, прилагаемого к вашему приложению, или получить из другого источника в зависимости от ваших потребностей.
Котлин
val message: ByteArray = ... val key: PrivateKey = ... val s = Signature.getInstance("SHA256withECDSA") .apply { initSign(key) update(message) } val signature: ByteArray = s.sign()
Ява
byte[] message = ...; PrivateKey key = ...; Signature s = Signature.getInstance("SHA256withECDSA"); s.initSign(key); s.update(message); byte[] signature = s.sign();
Проверить цифровую подпись
Вам необходим объект PublicKey
, содержащий открытый ключ подписчика, который вы можете прочитать из файла, прилагаемого к вашему приложению, извлечь из сертификата или получить из другого источника в зависимости от ваших потребностей.
Котлин
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)
Ява
byte[] message = ...; byte[] signature = ...; PublicKey key = ...; Signature s = Signature.getInstance("SHA256withECDSA"); s.initVerify(key); s.update(message); boolean valid = s.verify(signature);
Сложности реализации
Некоторые детали реализации криптографии в Android кажутся необычными, но присутствуют из соображений совместимости. В этом разделе рассматриваются те, с которыми вы, скорее всего, столкнётесь.
Дайджест сообщения OAEP MGF1
Шифры RSA OAEP параметризуются двумя различными дайджестами сообщений: «основным» дайджестом и дайджестом MGF1. Существуют идентификаторы Cipher
, включающие имена дайджестов, например Cipher.getInstance("RSA/ECB/OAEPwithSHA-256andMGF1Padding")
, который указывает основной дайджест, а дайджест MGF1 не указывается. В Android Keystore для дайджеста MGF1 используется SHA-1, тогда как для других криптографических поставщиков Android эти два дайджеста одинаковы.
Чтобы лучше контролировать дайджесты, используемые вашим приложением, запросите шифр с помощью OAEPPadding, как в Cipher.getInstance("RSA/ECB/OAEPPadding")
, и укажите OAEPParameterSpec
в init()
для явного выбора обоих дайджестов. Это показано в следующем коде:
Котлин
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)) }
Ява
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));
Устаревшие функции
В следующих разделах описаны устаревшие функции. Не используйте их в своём приложении.
Алгоритмы надувного замка
Реализации многих алгоритмов Bouncy Castle устарели . Это касается только случаев, когда вы явно запрашиваете поставщика Bouncy Castle, как показано в следующем примере:
Котлин
Cipher.getInstance("AES/CBC/PKCS7PADDING", "BC") // OR Cipher.getInstance("AES/CBC/PKCS7PADDING", Security.getProvider("BC"))
Ява
Cipher.getInstance("AES/CBC/PKCS7PADDING", "BC"); // OR Cipher.getInstance("AES/CBC/PKCS7PADDING", Security.getProvider("BC"));
Как отмечалось в разделе об указании поставщика только в системе Android Keystore , запрашивать конкретного поставщика не рекомендуется. Если вы будете следовать этому правилу, данное прекращение поддержки вас не коснётся.
Шифры шифрования на основе паролей без вектора инициализации
Шифры шифрования на основе паролей (PBE), требующие вектора инициализации (IV), могут получить его из ключа, если он правильно сконструирован, или из явно переданного IV. Если вы передадите ключ PBE, не содержащий IV, и не передадите явный IV, шифры PBE на Android в настоящее время предполагают, что IV равен нулю.
При использовании шифров PBE всегда передавайте явный IV, как показано в следующем фрагменте кода:
Котлин
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))
Ява
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));
Криптопровайдер
Начиная с Android 9 (уровень API 28), поставщик Crypto Java Cryptography Architecture (JCA) удалён. Если ваше приложение запрашивает экземпляр поставщика Crypto, например, вызывая следующий метод, возникает исключение NoSuchProviderException
.
Котлин
SecureRandom.getInstance("SHA1PRNG", "Crypto")
Ява
SecureRandom.getInstance("SHA1PRNG", "Crypto");
Библиотека безопасности и криптографии Jetpack
Все API в библиотеке security-crypto
Jetpack были объявлены устаревшими в стабильной версии 1.1.0
. Последующих выпусков этой библиотеки не предвидится.
Аннотации об устаревании видны, если в файле build.gradle
модуля вашего приложения есть какие-либо из следующих зависимостей:
Круто
dependencies { implementation "androidx.security:security-crypto:1.1.0" // or implementation "androidx.security:security-crypto-ktx:1.1.0" }
Котлин
dependencies { implementation("androidx.security:security-crypto:1.1.0") // or implementation("androidx.security:security-crypto-ktx:1.1.0") }
Поддерживаемые алгоритмы
Это идентификаторы алгоритма JCA, которые поддерживаются на 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