این سند روش صحیح استفاده از امکانات رمزنگاری اندروید را تشریح میکند و نمونههایی از استفاده از آنها را شامل میشود. اگر برنامه شما به امنیت کلید بیشتری نیاز دارد، از سیستم Android Keystore استفاده کنید.
ارائه دهنده ای را فقط با سیستم Android Keystore مشخص کنید
اگر از سیستم Android Keystore استفاده می کنید، باید ارائه دهنده ای را مشخص کنید.
با این حال، در شرایط دیگر، اندروید ارائه دهنده خاصی را برای یک الگوریتم مشخص تضمین نمی کند. تعیین ارائهدهنده بدون استفاده از سیستم Android Keystore میتواند در نسخههای بعدی مشکلات سازگاری ایجاد کند.
یک الگوریتم توصیه شده را انتخاب کنید
هنگامی که شما آزادی انتخاب الگوریتم مورد استفاده را دارید (مانند زمانی که به سازگاری با یک سیستم شخص ثالث نیاز ندارید)، توصیه می کنیم از الگوریتم های زیر استفاده کنید:
کلاس | توصیه |
---|---|
رمز | AES در حالت CBC یا GCM با کلیدهای 256 بیتی (مانند AES/GCM/NoPadding ) |
MessageDigest | خانواده SHA-2 (مانند SHA-256 ) |
مک | HMAC خانواده SHA-2 (مانند 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);
پیچیدگی های پیاده سازی
برخی جزئیات از پیاده سازی رمزنگاری اندروید وجود دارد که غیرعادی به نظر می رسد اما به دلیل نگرانی های مربوط به سازگاری وجود دارد. این بخش مواردی را که به احتمال زیاد با آنها روبرو خواهید شد بحث می کند.
خلاصه پیام OAEP MGF1
رمزهای RSA OAEP توسط دو هضم پیام مختلف پارامتری می شوند: خلاصه "اصلی" و هضم MGF1. شناسههای Cipher
وجود دارند که شامل نامهای خلاصه هستند، مانند Cipher.getInstance("RSA/ECB/OAEPwithSHA-256andMGF1Padding")
، که خلاصه اصلی را مشخص میکند و خلاصه MGF1 را نامشخص میگذارد. برای Android Keystore، SHA-1 برای خلاصه MGF1 استفاده می شود، در حالی که برای سایر ارائه دهندگان رمزنگاری اندروید، این دو خلاصه یکسان هستند.
برای کنترل بیشتر بر خلاصههایی که برنامه شما استفاده میکند، مانند Cipher.getInstance("RSA/ECB/OAEPPadding")
با 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 (JCA) حذف شده است. اگر برنامه شما نمونه ای از ارائه دهنده Crypto را درخواست کند، مانند فراخوانی روش زیر، یک NoSuchProviderException
رخ می دهد.
کاتلین
SecureRandom.getInstance("SHA1PRNG", "Crypto")
جاوا
SecureRandom.getInstance("SHA1PRNG", "Crypto");
کتابخانه رمزنگاری امنیتی Jetpack
کتابخانه رمزنگاری امنیتی Jetpack منسوخ شده است. این فقط بر مواردی تأثیر میگذارد که وابستگیهای زیر را در فایل build.gradle
ماژول برنامه خود داشته باشید:
شیار
dependencies { implementation "androidx.security:security-crypto:1.0.0" }
کاتلین
dependencies { implementation("androidx.security:security-crypto:1.0.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