Android anahtar deposu sistemi

Android Anahtar Deposu sistemi, kriptografik anahtarların cihazdan çıkarılmasını zorlaştırmak için bunları bir kapsayıcıda saklamanıza olanak tanır. Anahtarlar anahtar deposuna eklendikten sonra bunları kriptografik işlemler için kullanabilirsiniz. Anahtar materyali ise dışa aktarılamaz durumda kalır. Ayrıca anahtar deposu sistemi, anahtarların ne zaman ve nasıl kullanılabileceğini kısıtlamanıza olanak tanır (ör. anahtar kullanımı için kullanıcı kimlik doğrulaması zorunlu kılma veya anahtarları yalnızca belirli kriptografik modlarda kullanılacak şekilde kısıtlama). Daha fazla bilgi için Güvenlik Özellikleri bölümüne bakın.

Anahtar deposu sistemi, Android 4.0'ta (API düzeyi 14) kullanıma sunulan KeyChain API'nin yanı sıra Android 4.3'te (API düzeyi 18) kullanıma sunulan Android Keystore sağlayıcı özelliği tarafından kullanılır. Bu belgede, Android Anahtar Deposu sisteminin ne zaman ve nasıl kullanılacağı ele alınmaktadır.

Güvenlik özellikleri

Android Keystore sistemi, anahtar materyalini yetkisiz kullanıma karşı iki şekilde korur. İlk olarak, anahtar materyalin uygulama işlemlerinden ve bir bütün olarak Android cihazdan çıkartılmasını önleyerek Android cihazın dışından anahtar materyalinin yetkisiz kullanım riskini azaltır. İkinci olarak anahtar deposu sistemi, uygulamaların anahtarların yetkilendirilmiş kullanımlarını belirtmesini sağlayıp bu kısıtlamaları uygulamaların işlemleri dışında da uygulayarak Android cihaz içinde anahtar materyalinin yetkisiz kullanımı riskini azaltır.

Ayıklamanın önlenmesi

Android Anahtar Deposu anahtarlarının anahtar materyali, iki güvenlik önlemi kullanılarak çıkarılmaya karşı korunur:

  • Anahtar materyali hiçbir zaman başvuru sürecine girmez. Bir uygulama, Android Anahtar Deposu anahtarı kullanarak kriptografik işlemler gerçekleştirdiğinde, arka planda açık metin, şifrelenmiş metin ve imzalanacak veya doğrulanacak mesajlar, kriptografik işlemleri gerçekleştiren bir sistem işlemine beslenir. Uygulamanın işleminin güvenliği ihlal edilirse saldırgan uygulamanın anahtarlarını kullanabilir ancak anahtar materyalini ayıklayamaz (ör. Android cihazın dışında kullanmak için).
  • Anahtar materyali, Android cihazın güvenli donanımına (ör. Güvenilir Yürütme Ortamı (TEE) veya Güvenli Öğe (SE)) bağlanabilir. Bir anahtar için bu özellik etkinleştirildiğinde anahtar materyali hiçbir zaman güvenli donanımın dışında gösterilmez. Android OS'nin güvenliği ihlal edilirse veya saldırgan cihazın dahili depolama alanını okuyabilirse Android cihazdaki herhangi bir uygulamanın Android Keystore anahtarlarını kullanabilir ancak bunları cihazdan çıkaramaz. Bu özellik yalnızca cihazın güvenli donanımının belirli anahtar algoritması, blok modları, dolgu şemaları ve anahtarla birlikte kullanılma yetkisi verilen özet kombinasyonlarını desteklemesi durumunda etkinleştirilir.

    Özelliğin bir anahtar için etkin olup olmadığını kontrol etmek amacıyla KeyInfo anahtarını edinin. Sonraki adım, uygulamanızın hedef SDK sürümüne bağlıdır:

    • Uygulamanız Android 10 (API düzeyi 29) veya sonraki sürümleri hedefliyorsa getSecurityLevel() işlevinin döndürülen değerini inceleyin. KeyProperties.SecurityLevelEnum.TRUSTED_ENVIRONMENT veya KeyProperties.SecurityLevelEnum.STRONGBOX ile eşleşen döndürülen değerler, anahtarın güvenli donanımda olduğunu gösterir.
    • Uygulamanız Android 9 (API düzeyi 28) veya önceki sürümleri hedefliyorsa KeyInfo.isInsideSecurityHardware() boole döndürme değerini inceleyin.

Donanım güvenlik modülü

Android 9 (API düzeyi 28) veya sonraki sürümleri çalıştıran desteklenen cihazlarda, donanım güvenlik modülüne benzer bir güvenli öğede bulunan Keymaster veya Keymint HAL'in bir uygulaması olan StrongBox Keymaster bulunabilir. Donanım güvenlik modülleri, TEE gibi Linux çekirdeği güvenlik ihlallerinin fark edemediği anahtar depolama uygulamalarının birçok farklı uygulamasını

Modül şunları içerir:

  • Kendi CPU'su
  • Güvenli depolama alanı
  • Gerçek bir rastgele sayı üreteci
  • Paketin değiştirilmesine ve uygulamaların yetkisiz olarak harici yüklenmesine karşı koyan ek mekanizmalar
  • Güvenli bir zamanlayıcı
  • Genel amaçlı giriş/çıkış (GPIO) gibi bir yeniden başlatma bildirimi pini (veya eşdeğeri)

Düşük güçlü StrongBox uygulamalarını desteklemek için algoritma ve anahtar boyutlarının bir alt kümesi desteklenir:

  • RSA 2048
  • AES 128 ve 256
  • ECDSA, ECDH P-256
  • HMAC-SHA256 (8 ila 64 bayt dahil olmak üzere anahtar boyutlarını destekler)
  • Üçlü DES
  • Genişletilmiş Uzunluk APDU'ları
  • Anahtar Onayı
  • Yükseltme için H Değişikliği desteği

KeyStore sınıfını kullanarak anahtar oluştururken veya içe aktarırken true değerini setIsStrongBoxBacked() yöntemine ileterek anahtarı StrongBox Keymaster'da depolama tercihinizi belirtirsiniz.

StrongBox, TEE'ye kıyasla biraz daha yavaş ve kaynak açısından kısıtlıdır (yani daha az eşzamanlı işlem destekler). Ancak fiziksel ve yan kanal saldırılarına karşı daha iyi güvenlik garantileri sunar. Uygulama kaynak verimliliğine kıyasla daha yüksek güvenlik garantilerine öncelik vermek istiyorsanız StrongBox'u kullanılabildiği cihazlarda kullanmanızı öneririz. StrongBox'un kullanılamadığı durumlarda uygulamanız, anahtar materyallerini depolamak için her zaman TEE'ye geçebilir.

Anahtar kullanımı yetkilendirmeleri

Android Keystore, Android cihazda anahtarların yetkisiz kullanımını önlemek için uygulamaların anahtarları oluştururken veya içe aktarırken anahtarlarının yetkili kullanımlarını belirtmesine olanak tanır. Oluşturulan veya içe aktarılan anahtarların yetkilendirmeleri değiştirilemez. Yetkilendirmeler, anahtar her kullanıldığında Android Keystore tarafından zorunlu kılınır. Bu, genellikle yalnızca anahtar oluşturma/içe aktarma işleminden sonra (ancak öncesinde veya sırasında değil) uygulama sürecinizin güvenliğinin ihlal edilmesi durumunda anahtarın yetkisiz kullanımlarına yol açılmaması şartıyla yararlı olan gelişmiş bir güvenlik özelliğidir.

Desteklenen anahtar kullanım yetkileri aşağıdaki kategorilere ayrılır:

  • Şifreleme: Anahtar yalnızca yetkili anahtar algoritmaları, işlemleri veya amaçları (şifreleme, şifre çözme, imzalama, doğrulama), dolgu şemaları, blok modları veya karma oluşturma işlemleriyle kullanılabilir.
  • Zamansal geçerlilik aralığı: Anahtar yalnızca tanımlanmış bir zaman aralığında kullanılmak üzere yetkilendirilir.
  • Kullanıcı kimlik doğrulaması: Anahtar yalnızca kullanıcının kimliği yakın zamanda doğrulanmışsa kullanılabilir. Anahtar kullanımı için kullanıcı kimlik doğrulaması zorunluluğu bölümüne bakın.

Anahtar materyali güvenli donanımın içinde olan anahtarlar için ek bir güvenlik önlemi olarak (KeyInfo.isInsideSecurityHardware() veya Android 10 (API düzeyi 29) veya sonraki sürümleri hedefleyen uygulamalar için KeyInfo.getSecurityLevel() bölümüne bakın), bazı anahtar kullanımı yetkileri Android cihaza bağlı olarak güvenli donanım tarafından zorunlu kılınabilir. Güvenli donanım genellikle kriptografik ve kullanıcı kimlik doğrulama yetkilendirmelerini zorunlu kılar. Ancak güvenli donanım, normalde bağımsız ve güvenli bir gerçek zamanlı saate sahip olmadığından genellikle zamansal geçerlilik aralığı yetkilendirmelerini zorunlu kılmaz.

KeyInfo.isUserAuthenticationRequirementEnforcedBySecureHardware() kullanarak bir anahtarın kullanıcı kimlik doğrulama yetkilendirmesinin güvenli donanım tarafından zorunlu kılınıp kılınmadığını sorgulayabilirsiniz.

Anahtar zinciri ile Android Anahtar Deposu sağlayıcısı arasında seçim yapma

Sistem genelinde kimlik bilgileri almak istediğinizde KeyChain API'yi kullanın. Bir uygulama, KeyChain API üzerinden herhangi bir kimlik bilgisinin kullanılmasını istediğinde kullanıcılar, sistemin sağladığı kullanıcı arayüzü üzerinden uygulamanın hangi yüklü kimlik bilgilerine erişebileceğini seçebilir. Bu sayede çeşitli uygulamalar, kullanıcı izniyle aynı kimlik bilgisi grubunu kullanabilir.

Tek bir uygulamanın, yalnızca bu uygulamanın erişebileceği kendi kimlik bilgilerini depolamasına izin vermek için Android Anahtar Deposu sağlayıcısını kullanın. Bu sayede uygulamalar, yalnızca kendilerinin kullanabileceği kimlik bilgilerini yönetebilir ve KeyChain API'nin sistem genelindeki kimlik bilgileri için sağladığı güvenlik avantajlarından yararlanabilir. Bu yöntem, kullanıcının kimlik bilgilerini seçmesini gerektirmez.

Android Keystore sağlayıcısını kullanma

Bu özelliği kullanmak için standart KeyStore ve KeyPairGenerator veya KeyGenerator sınıflarını ve Android 4.3'te (API düzeyi 18) kullanıma sunulan AndroidKeyStore sağlayıcısını kullanırsınız.

AndroidKeyStore, KeyStore.getInstance(type) yöntemiyle kullanılmak üzere KeyStore türü olarak ve KeyPairGenerator.getInstance(algorithm, provider) ile KeyGenerator.getInstance(algorithm, provider) yöntemleriyle kullanılmak üzere sağlayıcı olarak kaydedilir.

Şifreleme işlemleri zaman alıcı olabildiğinden uygulamalar, kullanıcı arayüzünün yanıt vermeye devam etmesini sağlamak için ana iş parçacıklarında AndroidKeyStore kullanmaktan kaçınmalıdır. (StrictMode, bu durumun yaşanmadığı yerleri bulmanıza yardımcı olabilir.)

Yeni bir özel veya gizli anahtar oluşturma

PrivateKey içeren yeni bir KeyPair oluşturmak için sertifikanın ilk X.509 özelliklerini belirtmeniz gerekir. Sertifikayı daha sonra bir sertifika yetkilisi (CA) tarafından imzalanmış bir sertifikayla değiştirmek için KeyStore.setKeyEntry() simgesini kullanabilirsiniz.

Anahtar çiftini oluşturmak için KeyGenParameterSpec ile birlikte bir KeyPairGenerator kullanın:

Kotlin

/*
 * Generate a new EC key pair entry in the Android Keystore by
 * using the KeyPairGenerator API. The private key can only be
 * used for signing or verification and only with SHA-256 or
 * SHA-512 as the message digest.
 */
val kpg: KeyPairGenerator = KeyPairGenerator.getInstance(
        KeyProperties.KEY_ALGORITHM_EC,
        "AndroidKeyStore"
)
val parameterSpec: KeyGenParameterSpec = KeyGenParameterSpec.Builder(
        alias,
        KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
).run {
    setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
    build()
}

kpg.initialize(parameterSpec)

val kp = kpg.generateKeyPair()

Java

/*
 * Generate a new EC key pair entry in the Android Keystore by
 * using the KeyPairGenerator API. The private key can only be
 * used for signing or verification and only with SHA-256 or
 * SHA-512 as the message digest.
 */
KeyPairGenerator kpg = KeyPairGenerator.getInstance(
        KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
kpg.initialize(new KeyGenParameterSpec.Builder(
        alias,
        KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
        .setDigests(KeyProperties.DIGEST_SHA256,
            KeyProperties.DIGEST_SHA512)
        .build());

KeyPair kp = kpg.generateKeyPair();

Şifrelenmiş anahtarları güvenli donanıma aktarma

Android 9 (API düzeyi 28) ve sonraki sürümler, ASN.1 kodlamalı bir anahtar biçimi kullanarak şifrelenmiş anahtarları anahtar deposuna güvenli bir şekilde içe aktarmanıza olanak tanır. Ardından anahtar yöneticisi, anahtar mağazasındaki anahtarların şifresini çözer. Böylece anahtarların içeriği hiçbir zaman cihazın ana belleğinde açık metin olarak görünmez. Bu işlem, ek anahtar şifre çözme güvenliği sağlar.

Şifrelenmiş anahtarların anahtar deposuna güvenli bir şekilde içe aktarılmasını desteklemek için aşağıdaki adımları tamamlayın:

  1. PURPOSE_WRAP_KEY amacını kullanan bir anahtar çifti oluşturun. Bu anahtar çiftine de doğrulama eklemenizi öneririz.

  2. Güvendiğiniz bir sunucuda veya makinede SecureKeyWrapper için ASN.1 mesajını oluşturun.

    Sarmalayıcı aşağıdaki şemayı içerir:

       KeyDescription ::= SEQUENCE {
           keyFormat INTEGER,
           authorizationList AuthorizationList
       }
    
       SecureKeyWrapper ::= SEQUENCE {
           wrapperFormatVersion INTEGER,
           encryptedTransportKey OCTET_STRING,
           initializationVector OCTET_STRING,
           keyDescription KeyDescription,
           secureKey OCTET_STRING,
           tag OCTET_STRING
       }
    
  3. ASN.1 mesajını bayt dizisi olarak ileten bir WrappedKeyEntry nesnesi oluşturun.

  4. Bu WrappedKeyEntry nesnesini, Keystore.Entry nesnesini kabul eden setEntry() aşırı yüklemesine iletin.

Anahtar deposu girişleriyle çalışma

AndroidKeyStore sağlayıcısına tüm standart KeyStore API'leri aracılığıyla erişebilirsiniz.

Girişleri listeleme

aliases() yöntemini çağırarak anahtar deposundaki girişleri listeleyin:

Kotlin

/*
 * Load the Android KeyStore instance using the
 * AndroidKeyStore provider to list the currently stored entries.
 */
val ks: KeyStore = KeyStore.getInstance("AndroidKeyStore").apply {
   load(null)
}
val aliases: Enumeration<String> = ks.aliases()

Java

/*
 * Load the Android KeyStore instance using the
 * AndroidKeyStore provider to list the currently stored entries.
 */
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
Enumeration<String> aliases = ks.aliases();

Verileri imzalama ve doğrulama

Anahtar deposundan KeyStore.Entry'ü alarak ve sign() gibi Signature API'lerini kullanarak verileri imzalayın:

Kotlin

/*
 * Use a PrivateKey in the KeyStore to create a signature over
 * some data.
 */
val ks: KeyStore = KeyStore.getInstance("AndroidKeyStore").apply {
    load(null)
}
val entry: KeyStore.Entry = ks.getEntry(alias, null)
if (entry !is KeyStore.PrivateKeyEntry) {
    Log.w(TAG, "Not an instance of a PrivateKeyEntry")
    return null
}
val signature: ByteArray = Signature.getInstance("SHA256withECDSA").run {
    initSign(entry.privateKey)
    update(data)
    sign()
}

Java

/*
 * Use a PrivateKey in the KeyStore to create a signature over
 * some data.
 */
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
KeyStore.Entry entry = ks.getEntry(alias, null);
if (!(entry instanceof PrivateKeyEntry)) {
    Log.w(TAG, "Not an instance of a PrivateKeyEntry");
    return null;
}
Signature s = Signature.getInstance("SHA256withECDSA");
s.initSign(((PrivateKeyEntry) entry).getPrivateKey());
s.update(data);
byte[] signature = s.sign();

Benzer şekilde, verileri verify(byte[]) yöntemiyle doğrulayın:

Kotlin

/*
 * Verify a signature previously made by a private key in the
 * KeyStore. This uses the X.509 certificate attached to the
 * private key in the KeyStore to validate a previously
 * generated signature.
 */
val ks = KeyStore.getInstance("AndroidKeyStore").apply {
    load(null)
}
val entry = ks.getEntry(alias, null) as? KeyStore.PrivateKeyEntry
if (entry == null) {
    Log.w(TAG, "Not an instance of a PrivateKeyEntry")
    return false
}
val valid: Boolean = Signature.getInstance("SHA256withECDSA").run {
    initVerify(entry.certificate)
    update(data)
    verify(signature)
}

Java

/*
 * Verify a signature previously made by a private key in the
 * KeyStore. This uses the X.509 certificate attached to the
 * private key in the KeyStore to validate a previously
 * generated signature.
 */
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
KeyStore.Entry entry = ks.getEntry(alias, null);
if (!(entry instanceof PrivateKeyEntry)) {
    Log.w(TAG, "Not an instance of a PrivateKeyEntry");
    return false;
}
Signature s = Signature.getInstance("SHA256withECDSA");
s.initVerify(((PrivateKeyEntry) entry).getCertificate());
s.update(data);
boolean valid = s.verify(signature);

Anahtar kullanımı için kullanıcı kimlik doğrulaması zorunlu kılın

Bir anahtar oluştururken veya AndroidKeyStore içine bir anahtar aktarırken anahtarın yalnızca kullanıcının kimliği doğrulanmışsa kullanılmaya yetkili olduğunu belirtebilirsiniz. Kullanıcının kimliği, güvenli kilit ekranı kimlik bilgilerinin (desen/PIN/şifre, biyometrik kimlik bilgileri) alt kümesi kullanılarak doğrulanır.

Bu, yalnızca anahtar oluşturma/içe aktarma işleminden sonra (ancak öncesinde veya sırasında değil) uygulama sürecinizin güvenliğinin ihlal edilmesi durumunda kullanıcının anahtarı kullanabilmek için kimlik doğrulamasını tamamlaması şartının atlanamaması gibi durumlarda yararlı olan gelişmiş bir güvenlik özelliğidir.

Bir anahtarın yalnızca kullanıcının kimliği doğrulanmışsa kullanılmasına izin verildiğinde, anahtarı aşağıdaki modlardan birinde çalışacak şekilde yapılandırmak için setUserAuthenticationParameters() işlevini çağırabilirsiniz:

Belirli bir süre için yetkilendirme
Kullanıcı belirtilen kimlik bilgilerinden birini kullanarak kimliğini doğruladığı anda tüm anahtarlar kullanıma yetkili olur.
Belirli bir şifreleme işleminin süresi boyunca yetkilendirme

Belirli bir anahtarı içeren her işlem, kullanıcı tarafından ayrı ayrı yetkilendirilmelidir.

Uygulamanız bu işlemi, bir BiometricPrompt örneğinde authenticate() çağrısı yaparak başlatır.

Oluşturduğunuz her anahtar için güçlü bir biyometri kimlik bilgisi, kilit ekranı kimlik bilgisi veya her iki kimlik bilgisi türünü de desteklemeyi seçebilirsiniz. Kullanıcının, uygulama anahtarınızın temel aldığı kimlik bilgilerini ayarlayıp ayarlamadığını belirlemek için canAuthenticate() çağrısı yapın.

Bir anahtar yalnızca biyometrik kimlik bilgilerini destekliyorsa yeni biyometrik kayıtlar eklendiğinde anahtar varsayılan olarak geçersiz kılınır. Anahtarı, yeni biyometri kayıtları eklendiğinde geçerli kalacak şekilde yapılandırabilirsiniz. Bunun için false değerini setInvalidatedByBiometricEnrollment() değerine iletin.

Biyometrik kimlik doğrulama iletişim kutusunu gösterme de dahil olmak üzere uygulamanıza biyometrik kimlik doğrulama özellikleri ekleme hakkında daha fazla bilgi edinin.

Desteklenen algoritmalar

Blog makaleleri

ICS'de Anahtar Deposu Erişimini Birleştirme başlıklı blog girişine bakın.