انبارکلید آندروید: این چیست، معماری و اصول کار

نویسنده: IT Sectr منتشر شده: 2026-03-14 زمان مطالعه: 10 دقیقه

انبارکلید آندروید — یک مکانیسم سیستمی آندروید برای ذخیره امن کلیدهای کریپتوگرافی در انزوای سخت‌افزاری است. این سیستم از Trusted Execution Environment (TEE) در دستگاه‌های دارای ARM TrustZone یا Secure Element جداگانه برای حفاظت از کلیدها در سطح تراشه استفاده می‌کند. به پیروی Android Open Source Project، Keystore از الگوریتم‌های RSA، EC، AES و HMAC با تولید کلید مستقیماً در محیط امن پشتیبانی می‌کند.

نکات کلیدی

  • انبارکلید آندروید — ارائه‌دهنده KeyStore که کلیدهای کریپتوگرافی را از فضای کاربری آندروید جدا می‌کند
  • کلیدها داخل TEE یا Secure Element تولید می‌شوند و هرگز محیط امن را به صورت باز ترک نمی‌کنند
  • Android 9+ KeyGenParameterSpec.Builder را با پارامترهای purpose، digest، padding، userAuthenticationRequired اضافه می‌کند
  • حفاظت بیومتریک کلیدها قبل از هر عملیات تأیید کاربر از طریق BiometricPrompt را طلب می‌کند
  • Keymaster HAL — لایه انتزاعی سخت‌افزاری که عملیات کریپتوگرافی را در TEE یا Secure Element انجام می‌دهد

انبارکلید آندروید چیست؟

انبارکلید آندروید — یک ارائه‌دهنده کریپتوگرافی (provider) است که از API 1 (Android 1.0) در آندروید پیاده‌سازی شده، اما پشتیبانی سخت‌افزاری کامل از Android 4.3 (API 18) فراهم شد. Keystore مسئله ذخیره امن کلیدهای خصوصی را چنان حل می‌کند که حتی در صورت تساهل سیستم‌عامل، مهاجم نتواند کلیدها را به صورت باز استخراج کند.

معماری KeyStore در آندروید

معماری انبارکلید آندروید از سه لایه تشکیل شده: API کاربردی (java.security.KeyStore)، خدمات سیستم (keystore daemon) و لایه سخت‌افزاری (Keymaster HAL). برنامه از طریق API ستاندارد Java Cryptography Architecture (JCA) دسترسی پیدا می‌کند، و خدمات سیستم درخواست‌ها را به Keymaster که در TEE عمل می‌کند هدایت می‌کند.

تمامی عملیات‌های کریپتوگرافیک با کلیدها (امضا، رمزگشایی) داخل TEE یا Secure Element انجام می‌شود. کلیدها هرگز محیط امن را ترک نمی‌کنند — برنامه فقط یک اشاره‌گر (alias) برای ارجاع به کلید دریافت می‌کند. این تفاوت بنیادین با KeyStoreهای نرم‌افزاری است که در آن‌ها کلیدها به طور پتانسیل در حافظه فرآیند در دسترس هستند.

تفاوت با Java KeyStore

JKS (Java KeyStore) یا BKS (Bouncy Castle) ستاندارد کلیدها را در پرونده‌هایی که با رمز عبور محافظت می‌شوند ذخیره می‌کنند. Android Keystore کلیدها را در انزوای سخت‌افزاری ذخیره می‌کند که حتی از کاربر root نیز محافظت می‌شوند. JKS در برابر دسترسی مستقیم به فایل سیستم آسیب‌پذیر است، Android Keystore — نیست.

تفاوت دیگر ایناست که در Android Keystore کلیدها پارامترهای استفاده سختگیرانه‌ای (purpose — فقط sign/verify/encrypt/decrypt) دارند که در زمان تولید تعیین می‌شوند. این پارامترها پس از آن قابل تغییر نیستند که از سوءاستفاده از کلید جلوگیری می‌کند.

انبارکلید آندروید چگونه کار می‌کند؟

در زمان ایجاد یک کلید جدید، برنامه KeyPairGenerator یا KeyGenerator را با KeyGenParameterSpec که شامل تمامی پارامترهای کلید آینده است فراخوان می‌کند. سیستم درخواست را به Keymaster HAL ارسال می‌کند که کلید را داخل TEE تولید و یک اشاره‌گر برمی‌گرداند.

فرآیند تولید کلید

روش KeyGenParameterSpec.Builder پارامترهای اجباری را می‌پذیرد: نام کلید در Keystore، کاربرد (PURPOSE_SIGN، PURPOSE_ENCRYPT)، الگوریتم (RSA، EC، AES). به علاوه: digest (SHA-256)، padding (PKCS7)، userAuthenticationRequired (بیومتری)، keyValidityStart/End (محدودیت‌های زمانی).

پس از تعیین پارامترها، KeyPairGenerator.generateKeyPair() یک KeyPair برمی‌گرداند که PrivateKey یک شیئ است که عملیات را به Keymaster ارجاع می‌دهد. کلید عمومی قابل استخراج است، کلید خصوصی — خیر. آن فقط داخل TEE وجود دارد.

kotlin
import java.security.KeyPairGenerator
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties

fun generateKey(alias: String) {
    val spec = KeyGenParameterSpec.Builder(alias,
        KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
    ).setDigests(KeyProperties.DIGEST_SHA256)
     .setSignaturePaddings(KeyProperties.SIGN_PADDING_RSA_PKCS1)
     .setUserAuthenticationRequired(true)
     .build()

    val kpGen = KeyPairGenerator.getInstance(
        KeyProperties.KEY_ALGORITHM_RSA,
        "AndroidKeyStore"
    )
    kpGen.initialize(spec)
    kpGen.generateKeyPair()
}

امضا و تأیید

Signature برای ECDSA یا RSA-PSS از طریق API ستاندارد ایجاد می‌شود: Signature.getInstance(algorithm).initSign(privateKey). عملیات امضا در TEE انجام می‌شود: برنامه داده‌ها را ارسال می‌کند، Keymaster آنها را به صورت سخت‌افزاری امضا می‌کند و امضا را برمی‌گرداند. کلید و داده‌ها در حافظه مشترک مخلوط نمی‌شوند.

برای حفاظت بیومتریک، قبل از امضا باید کاربر از طریق BiometricPrompt احراز هویت شود. بدون احراز هویت موفقیت‌آمیز، Keymaster عملیات را انجام نمی‌دهد و CryptoAuthenticationException برمی‌گرداند.

kotlin
import java.security.KeyStore
import java.security.Signature
import androidx.biometric.BiometricPrompt

fun signWithBiometric(alias: String) {
    val ks = KeyStore.getInstance("AndroidKeyStore")
    ks.load(null)
    val entry = ks.getEntry(alias, null) as KeyStore.PrivateKeyEntry
    val signature = Signature.getInstance("SHA256withRSA")
    signature.initSign(entry.privateKey)
    // BiometricPrompt با CryptoObject(signature) FaceID/PIN را درخواست می‌کند
}

انواع ذخیره‌سازی‌های KeyStore

آندروید از دو حالت ذخیره کلید پشتیبانی می‌کند: نرم‌افزاری (در دستگاه‌های بدون TEE) و سخت‌افزاری (در دستگاه‌های دارای TEE یا Secure Element). حالت به قابلیت‌های SoC و نسخه آندروید بستگی دارد.

KeyStore نرم‌افزاری (فقط نرم‌افزار)

در دستگاه‌های بدون Trusted Execution Environment (قبل از Android 4.3 یا SoCهای ارزان) کلیدها با استفاده از یک کلید اصلی که از رمز صفحه قفل به‌دست آمده در شکل رمزگذاری‌شده ذخیره می‌شوند. این حالت امنیت کمتری دارد — کلیدها در زمان انجام عملیات کریپتوگرافی در حافظه فرآیند در دسترس هستند.

سطح حفاظت بر اساس رمزگذاری فایل KeyStore با AES-256-GCM است. کلید رمزگذاری بر اساس رمز عبور یا PIN کاربر از طریق Scrypt (PBKDF2 با تعداد ایتراسیون بالا) تولید می‌شود.

KeyMaster سخت‌افزاری (TEE/Secure Element)

در دستگاه‌های مدرن Keymaster 4.x در TEE (ARM TrustZone) استفاده می‌شود. کلیدها فقط داخل TrustZone تولید، ذخیره و استفاده می‌شوند. حتی هسته لینوکس به کلیدهای خصوصی دسترسی ندارد — فقط Keymaster HAL می‌تواند عملیات را انجام دهد.

Secure Element (مانند eSE در Samsung Knox یا StrongBox در Google Pixel 3+) — یک تراشه جداگانه با پردازنده و حافظه خود است. آن گواهی Common Criteria EAL 4+ را دارد و بالاترین سطح حفاظت را از جمله محافظت در برابر بازکردن فیزیکی فراهم می‌کند.

نوعمکان ذخیرهسطح حفاظتاز API
Softwareفایل /data/misc/keystoreمتوسط (AES-256)API 1+
Keymaster 3TEE (TrustZone)بالاAPI 23+
Keymaster 4TEE + Secure I/Oخیلی بالاAPI 28+
StrongBoxSecure Element سخت‌افزاریحداکثرAPI 28+، اختیاری

کار با KeyStore API

Android Keystore با Java Cryptography Architecture (JCA) ادغام شده است. برای دسترسی به ارائه‌دهنده، KeyStore.getInstance("AndroidKeyStore") استاندارد استفاده می‌شود. API از API 18 موجود است.

ایجاد و بارگذاری KeyStore

روش KeyStore.load(null) کانتینر KeyStore برنامه جاری را بارگذاری می‌کند. رمز عبور مورد نیاز نیست — Android از کنتکست برنامه و UID آن برای جداسازی دسترسی استفاده می‌کند. هر برنامه فقط ورودی‌های خود را می‌بیند، مگر اینکه از UID مشترک استفاده شود.

روش‌های setEntry و getEntry با KeyStore.PrivateKeyEntry، SecretKeyEntry یا TrustedCertificateEntry کار می‌کنند. پارامتر ProtectionParameter همیشه برای Android Keystore null است (حفاظت در سطح سیستم پیاده شده است).

kotlin
import java.security.KeyStore
import java.security.cert.Certificate
import android.security.keystore.KeyProtection

fun storeSecretKey(alias: String, key: SecretKey) {
    val ks = KeyStore.getInstance("AndroidKeyStore")
    ks.load(null)
    val prot = KeyProtection.Builder(
        KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
    ).setBlockModes(KeyProperties.BLOCK_MODE_GCM)
     .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
     .setUserAuthenticationRequired(true)
     .build()
    ks.setEntry(alias, KeyStore.SecretKeyEntry(key), prot)
}

بررسی نوع ذخیره‌سازی

با استفاده از KeyCharacteristics می‌توان تعیین کرد که کلید در چه محیطی ذخیره شده: KeyStore نرم‌افزاری، TEE یا StrongBox. روش getKeyCharacteristics() یک مجموعه علمت برمی‌گرداند: FLAG_HARDWARE (keymaster)، FLAG_SECURE_ELEMENT (StrongBox)، FLAG_TRUSTED_USER_PRESENCE_REQUIRED (بیومتری).

الگوریتم‌ها و امنیت

Android Keystore از یک مجموعه گسترده از الگوریتم‌های کریپتوگرافیک پشتیبانی می‌کند که به سه دسته تقسیم می‌شود: نامتماثل، متماثل و MAC. پشتیبانی از الگوریتم‌های مشخص به نسخه Keymaster HAL بستگی دارد.

الگوریتم‌های پشتیبانی‌شده

RSA (1024–4096 بیت) — برای امضا (PKCS1، PSS) و رمزگذاری (OAEP، PKCS1). EC (P-224، P-256، P-384، P-521) — برای امضای ECDSA و توافق ECDH. AES (128، 256 بیت) — برای رمزگذاری متماثل در حالت‌های CBC، CTR، GCM. HMAC (SHA1، SHA256، SHA512) — برای احراز هویت پیام.

برای هر کلید، setPurposes تعیین شده است که عملیات ممکن را محدود می‌کند. یک کلید RSA با PURPOSE_SIGN نمی‌تواند برای رمزگذاری استفاده شود، حتی اگر مهاجم به API دسترسی داشته باشد. این اجبار استفاده از کلید در سطح سخت‌افزار است.

محافظت در برابر تساهل

Keymaster شمارنده تلاش‌های ناموفق احراز هویت بیومتریک را دارد. پس از تعداد مشخصی تلاش ناموفق (از طریق setInvalidatedByBiometricEnrollment قابل تنظیم) کلید غیرقابل دسترس شده و نیازمند حذف/تولید مجدد است. پس از حذف تمامی الگوهای بیومتریک، تمامی کلیدهای با userAuthenticationRequired=true به طور خودکار بی‌اعتبار می‌شوند.

همچنین Key Attestation (Android 8.1+) پشتیبانی می‌شود: به درخواست برنامه، Keymaster یک گواهینامه با اطلاعاتی درباره ویژگی‌های کلید (سخت‌افزاری/نرم‌افزاری، الگوریتم، purges) امضا می‌کند. سرور می‌تواند این گواهینامه را برای تأیید اینکه کلید در محیط امن ایجاد شده است بررسی کند.

سوالات متداول

تفاوت بین Android Keystore و KeyStore در جاوا چیست؟

Java KeyStore کلیدها را در یک فایل محافظت‌شده با رمز عبور (JKS، BKS) ذخیره می‌کند. Android Keystore از انزوای سخت‌افزاری TEE یا Secure Element استفاده می‌کند. Java KeyStore در برابر دسترسی root آسیب‌پذیر است، Android Keystore — نیست، زیرا کلیدهای خصوصی هرگز محیط امن را ترک نمی‌کنند.

آیا می‌توان یک کلید موجود را به Android Keystore وارد کرد؟

بله، از طریق KeyStore.setEntry با KeyProtection. اما کلید وارد‌شده حفاظت سخت‌افزاری ندارد — در KeyStore نرم‌افزاری که با کلید اصلی رمزگذاری شده ذخیره می‌شود. برای حداکثر امنیت، همیشه کلیدها را داخل Keystore تولید کنید.

چگونه بررسی کنیم که دستگاه KeyStore سخت‌افزاری را پشتیبانی می‌کند؟

از KeyChain.isBoundKeyAlgorithm استفاده کنید یا KeyCharacteristics را پس از تولید کلید بررسی کنید. وجود FLAG_HARDWARE در ویژگی‌ها به معنای این است که کلید در TEE ایجاد شده است. همچنین می‌توانید android.security.keystore.isHardwareBacked() را بررسی کنید.

با حذف برنامه چه بلـر کلیدها می‌آید؟

پس از حذف برنامه، Android تمامی کلیدهای آن را از Keystore حذف می‌کند. داده‌ها به طور جبران‌ناپذیر از دست می‌روند. در نصب مجدد، برنامه باید کلیدهای جدیدی تولید کند. پیشتیان از کلیدها از طریق TEE به دلایل معماری ممکن نیست.

KeyStore چگونه در برابر حملات از طریق رفع ایراد محافظت می‌کند؟

در دستگاه قفل‌شده، Keymaster هیچ عملیاتی انجام نمی‌دهد. کلیدهای با userAuthenticationRequired=true هر بار نیازمند تأیید بیومتریک هستند. حتی با دسترسی root، مهاجم نمی‌تواند مستقیماً با Keymaster تماس بگیرد — فقط از طریق خدمات Android Keystore.

نتیجه

  • Android Keystore — ارائه‌دهنده کریپتوگرافی JCA با انزوای سخت‌افزاری کلیدها از طریق TEE یا Secure Element
  • کلیدها داخل TrustZone تولید می‌شوند و هرگز محیط امن را به صورت باز ترک نمی‌کنند
  • KeyGenParameterSpec پارامترهای کلید را تعیین می‌کند: purpose، digest، padding، userAuthenticationRequired، keyValidity
  • Keymaster HAL سه سطح را پیاده‌سازی می‌کند: نرم‌افزاری (software)، TEE (Keymaster 3/4) و StrongBox (سخت‌افزاری Secure Element)
  • حفاظت بیومتریک کلیدها توسط setUserAuthenticationRequired و BiometricPrompt با CryptoObject تأمین می‌شود
  • Key Attestation (API 28+) امكان بررسی روی سرور را فراهم می‌کند که کلید در محیط سخت‌افزاری ایجاد شده است
  • از Android Keystore برای ذخیره کلیدهای خصوصی امضا، رمزگذاری و احراز هویت در برنامه‌های Android استفاده کنید

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید