KeyStore (Android) — این پیادهسازی ارائهدهنده کریپتوگرافیک Java Cryptography Architecture (JCA) است که در Android برای ذخیره ایمن کلیدها با قابلیت انزوای سختافزاری یکپارچه شده است. از Android 4.3 (API 18) به بعد، KeyStore از کلیدهای سختافزاری از طریق Keymaster HAL پشتیبانی میکند، و از Android 9 (API 28) به بعد — StrongBox Keymaster برای کلیدها در Secure Element جداگانه. بر اساس Android Security Documentation، ارائهدهنده «AndroidKeyStore» جایگزین Bouncy Castle یا OpenSSL KeyStore شده و حفاظت سیستمی در برابر استخراج غیرمجاز کلیدها ارائه میدهد.
نکات کلیدی
KeyStore در Android — این یک برنامه یا فایل جداگانه نیست، بلکه یک ارائهدهنده کریپتوگرافیک است که اینترفیس java.security.KeyStore را پیادهسازی میکند. آن یک API واحد برای ذخیره و استفاده از کلیدهای خصوصی، کلیدهای متماثل و گواهینامههای مراکز اعتماد (CA) فراهم میکند. ارائهدهنده با نام «AndroidKeyStore» ثبت شده و از طریق KeyStore.getInstance() استاندارد قابل دسترسی است.
قبل از Android 4.3 عملیات کریپتوگرافیک به صورت نرمافزاری از طریق Bouncy Castle انجام میشد. از Android 4.3 Keymaster HAL 1.0 ارائه شد که امکان استفاده از TEE در ARM TrustZone را فراهم میکرد. Android 6.0 (API 23) Keymaster 2.0 را با پشتیبانی از احراز هویت سختافزاری با اثر انگشت اضافه کرد. Android 9 (API 28) Keymaster 4.0 و StrongBox Keymaster را برای Secure Element جداگانه معرفی کرد.
هر نسخه Keymaster قابلیتهای جدیدی اضافه میکند و انزوای کلیدها را بهبود میبخشد. دستگاههای مدرن (2022+) برای گواهینامه Google Mobile Services باید از Keymaster 4.0 پشتیبانی کنند که حضور TEE را برای همه برنامههای Android تضمین میکند.
Android KeyStore از سه سطح تشکیل شده است: Java API (KeyStore، KeyPairGenerator)، فرآیند سیستمی keystore (C++، به عنوان system service کار میکند) و Keymaster HAL (کتابخانه در TEE یا Secure Element). برنامه API را فراخوان میکند، خدمات keystore درخواست را به Keymaster هدایت میکند، و عملیات در محیط محافظتشده انجام میشود.
همه کلیدهای خصوصی در TEE ذخیره میشوند و نمیتوانند از فضای کاربری خوانده شوند. حتی خدمات سیستمی keystore به کلیدهای خام دسترسی ندارد — تنها به دستههایی که به کلیدهای داخل Keymaster اشاره میکنند.
Android KeyStore اینترفیس استاندارد ارائهدهنده خدمات JCA را پیادهسازی میکند. وقتی برنامه Cipher.getInstance(«RSA/ECB/PKCS1Padding», «AndroidKeyStore») را فراخوان میکند، Android Security Provider عملیات را از طریق زنجیره به Keymaster ارجاع میدهد: Java → JNI → keystore service → Keymaster HAL.
ارائهدهنده AndroidKeyStore به صورت خودکار در زمان راهاندازی فرآیند ثبت میشود. اولویت آن بیشتر از Bouncy Castle یا Conscrypt است. بنابراین در KeyStore.getInstance() بدون مشخص کردن ارائهدهنده، در اکثر موارد AndroidKeyStore بازگردانده میشود. برای فراخوان صریح از KeyStore.getInstance(«AndroidKeyStore») استفاده کنید.
هر برنامه Android یک کانتینر ایزوله در KeyStore دارد. برنامههایی با UID یکسان (shared userId) میتوانند به کلیدهای مشخصی دسترسی مشترک داشته باشند، اما نصب استاندارد تضمین میکند که برنامه A نمیتواند کلیدهای برنامه B را بخواند.
load(null) — مقداردهی KeyStore. پارامتر همیشه برای AndroidKeyStore null است. setEntry — ذخیره کلید با مشخص کردن KeyProtection (purposes، digest، padding). getEntry — دریافت KeyStore.PrivateKeyEntry، SecretKeyEntry یا TrustedCertificateEntry. containsAlias — بررسی وجود کلید. deleteEntry — حذف کلید (به صورت جاویدان).
import java.security.KeyStore
import java.security.KeyPairGenerator
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
object KeyStoreManager {
private val keyStore by lazy {
KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
}
fun createRsaKey(alias: String) {
val spec = KeyGenParameterSpec.Builder(alias,
KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
).setKeySize(2048)
.setDigests(KeyProperties.DIGEST_SHA256)
.setSignaturePaddings(KeyProperties.SIGN_PADDING_RSA_PKCS1)
.build()
val kpg = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_RSA,
"AndroidKeyStore"
)
kpg.initialize(spec)
kpg.generateKeyPair()
}
}
Android KeyStore از یک مجموعه گسترده از الگوریتمهای کریپتوگرافیک پشتیبانی میکند که بستگی به نسخه Keymaster HAL در دستگاه دارد. توسعهدهنده میتواند لیست الگوریتمهای پشتیبانی شده را از طریق KeyGenParameterSpec.Builder در زمان ایجاد دریافت کند — پارامترهای ناسازگار باعث InvalidAlgorithmParameterException میشوند.
RSA (1024–4096 بیت) — برای امضا (PKCS1، PSS با SHA-1/SHA-256/SHA-384/SHA-512) و تشفیر (OAEP با SHA-1/SHA-256). EC (P-224، P-256، P-384، P-521) — برای امضای ECDSA و توافق کلید ECDH. X25519 و Ed25519 — از Android 12 (API 31) برای پروتکلهای کریپتوگرافیک مدرن.
برای کلیدهای نامتماثل همواره در داخل Keymaster تولید کنید، هرگز کلیدهای خصوصی را وارد نکنید. کلیدهای خصوصی واردشده به صورت سختافزاری حفاظت نمیشوند — آنها در لایه نرمافزاری ذخیره میشوند و در صورت تسخیر AP آسیبپذیر هستند.
AES (128، 256 بیت) — برای تشفیر متماثل در حالتهای CBC، CTR، GCM. HMAC (SHA-1، SHA-256، SHA-512) — برای احراز هویت پیامها. ChaCha20 (Android 12+) — برای تشفیر جریانی با کارایی بالا با احراز هویت Poly1305.
| الگوریتم | Keymaster | مقصود | API |
|---|---|---|---|
| RSA | KM 1.0+ | امضا، تشفیر | 18+ |
| EC | KM 1.0+ | ECDSA، ECDH | 18+ |
| AES | KM 2.0+ | تشفیر متماثل | 23+ |
| HMAC | KM 2.0+ | کد احراز هویت | 23+ |
| ChaCha20 | KM 3.0+ | تشفیر جریانی | 31+ |
| X25519/E25519 | KM 3.0+ | تبادل کلید | 31+ |
KeyStore.PrivateKeyEntry — شامل کلید خصوصی (قابل خروج نیست) و زنجیره گواهینامه است. KeyStore.SecretKeyEntry — برای کلیدهای متماثل. KeyStore.TrustedCertificateEntry — برای گواهینامههای CA معتمد. کلیدهای عمومی برای خروج از طریق keyStore.getCertificate(alias).publicKey در دسترس هستند.
یک سناریوی کامل را بررسی کنیم: تولید کلید AES برای تشفیر دادهها و تولید کلید EC برای امضا با حفاظت بیومتریک. هر دو کلید در داخل Android KeyStore با پشتیبانی سختافزاری ایجاد میشوند.
کلید AES از طریق KeyGenerator با KeyGenParameterSpec ایجاد میشود. پارامترها: PURPOSE_ENCRYPT + PURPOSE_DECRYPT، BLOCK_MODE_GCM (حالت توصیهشده با احراز هویت)، ENCRYPTION_PADDING_NONE (برای GCM padding لازم نیست).
import javax.crypto.KeyGenerator
import javax.crypto.Cipher
import javax.crypto.spec.GCMParameterSpec
fun generateAndEncrypt(alias: String, plainText: ByteArray): ByteArray {
val spec = KeyGenParameterSpec.Builder(alias,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
).setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setKeySize(256)
.build()
val kg = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
kg.initialize(spec)
kg.generateKey()
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
cipher.init(Cipher.ENCRYPT_MODE, getKeyFromStore(alias))
return cipher.doFinal(plainText)
}
کلید EC با userAuthenticationRequired=true قبل از هر عملیات امضا نیازمند احراز هویت کاربر است. برای این منظور از BiometricPrompt با CryptoObject شامل شیء Signature استفاده میشود. پس از بیومتری موفقیتآمیز، Keymaster به عملیات اجازه میدهد.
fun createBiometricSignKey(alias: String) {
val spec = KeyGenParameterSpec.Builder(alias,
KeyProperties.PURPOSE_SIGN
).setAlgorithmParameterSpec(
ECGenParameterSpec("secp256r1")
).setDigests(KeyProperties.DIGEST_SHA256)
.setUserAuthenticationRequired(true)
.setInvalidatedByBiometricEnrollment(true)
.build()
val kpg = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_EC,
"AndroidKeyStore"
)
kpg.initialize(spec)
kpg.generateKeyPair()
}
Android KeyStore تضمینات امنیتی سختافزاری ارائه میدهد که KeyStoreهای نرمافزاری (JKS، BKS) نمیتوانند تامین کنند. کلیدها در سطح SoC محافظت میشوند و حتی کنترل کامل بر فضای کاربری Android نمیتواند کلید خصوصی را استخراج کند.
Key Attestation — مکانیسمی که به برنامه (و سرور) اجازه میدهد بررسی کند که کلید در چه محیطی ایجاد شده است. Android Keystore گواهینامهای را امضا میکند که شامل فهرست ویژگیهای کلید است: الگوریتم، اندازه، purges، hardware-backed (True/False)، origin (GENERATED، IMPORTED). سرور زنجیره گواهینامه را تا گواهینامه ریشه Google بررسی میکند.
این برای برنامههای مالی حیاتی است: سرور میتواند نیازمند باشد که کلید در محیط سختافزاری (Hardware-Backed = True) ایجاد شده باشد و کلیدهای ایجادشده در Keystore نرمافزاری را رد کند. Key Attestation از حملاتی جلوگیری میکند که در آن مہاجم Keystore را با شبیهساز جایگزین میکند.
setInvalidatedByBiometricEnrollment(true) به این معنی است که کلید در زمان تغییر یا حذف الگوهای بیومتریک کاربر توسط Keymaster به طور خودکار حذف میشود. این حفاظتی است در برابر حملاتی که در آن مهاجم اثر انگشت خود را به حساب موجود اضافه میکند. پس از افزودن اثر انگشت جدید، کلیدهای قدیمی غیرقابل دسترس میشوند.
شماره تلاشهای ناموفق احراز هویت بیومتریک نیز توسط Keymaster مدیریت میشود. پس از maxBiometricAttempt (توسط سازنده تنظیم میشود، معمولاً 5) Keymaster همه عملیات با کلیدهای بیومتریک را به مدت 30 ثانیه مسدود میکند. پس از 10 تلاش ناموفق — تا وقت وارد کردن رمز عبور دستگاه (پین مخفی).
پرسشهای متداول
Bouncy Castle (BKS) — یک KeyStore نرمافزاری است که کلیدها را در یک فایل محافظتشده با رمز عبور ذخیره میکند. Android KeyStore از انزوای سختافزاری TEE/StrongBox استفاده میکند. کلیدهای BKS را میتوان با دسترسی root استخراج کرد، اما کلیدهای Android KeyStore را نمیتوان. BKS برای گواهینامههای CA و Android KeyStore برای کلیدهای خصوصی مناسب است.
بله، اگر در تولید PURPOSE_ENCRYPT or PURPOSE_DECRYPT or PURPOSE_SIGN or PURPOSE_VERIFY مشخص شده باشد. اما بهترین روش ایجاد کلیدهای جداگانه برای عملیات مختلف است. این کار خسارت ناشی از تسخیر یکی از کلیدها را محدود میکند و با اصل کمترین دسترسی مطابقت دارد.
از KeyStore.getKeyCharacteristics(alias) موجود از طریق android.security.keystore استفاده کنید. این روش یک مجموعه علمت برمیگرداند: FLAG_HARDWARE — کلید در TEE، FLAG_SECURE_ELEMENT — کلید در StrongBox. اگر علمتی نباشد — کلید نرمافزاری است.
همه کلیدهایی که با setInvalidatedByBiometricEnrollment(true) ایجاد شدهاند توسط Keymaster به طور خودکار ابطال میشوند. در زمان استفاده، برنامه KeyPermanentlyInvalidatedException دریافت خواهد کرد. دادههایی که با این کلیدها تشفیر شدهاند به طور جاویدان از دست میروند.
کلیدهای سختافزاری (در TEE/StrongBox) از پشتیبانی پشتیبانی نمیکنند — آنها به دستگاه خاص متصل هستند. کلیدهای نرمافزاری میتوانند در پشتیبان Google Drive قرار گیرند. برای انتقال دادهها بین دستگاهها، دادهها را در سرور تشفیر کنید و در دستگاه جدید تشفیرگشایی کنید.
نتیجهگیری
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید