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. Anahtar deposu sistemi, anahtarların ne zaman ve nasıl kullanılabileceğini kısıtlamanıza da 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. Öncelikle, anahtar materyalinin uygulama işlemlerinden ve Android cihazın tamamından çıkarılmasını engelleyerek anahtar materyalinin Android cihazın dışarısından yetkisiz kullanımı riskini azaltır. İkinci olarak, anahtar mağazası sistemi, uygulamaların anahtarlarının yetkili kullanımlarını belirtmesini sağlayıp bu kısıtlamaları uygulamaların işlemlerinin dışında uygulayarak Android cihazda anahtar materyalinin yetkisiz kullanımı riskini azaltır.

Ayıklamanın önlenmesi

Android Keystore anahtarlarının anahtar materyali, iki güvenlik önlemi kullanılarak ayıklamaya karşı korunur:

  • Anahtar materyali hiçbir zaman başvuru sürecine dahil edilmez. 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 kullanılmak üzere).
  • 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ı, anahtarın kullanılmasına izin verilen anahtar algoritması, blok modları, dolgu şemaları ve özet kombinasyonunu destekliyorsa 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() değerinin 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'u (API düzeyi 28) veya daha eski sürümleri hedefliyorsa KeyInfo.isInsideSecurityHardware() işlevinin döndürdüğü boole 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ğinin güvenliğinin ihlal edildiği durumlarda anahtar depolama alanının birçok farklı uygulamasını ifade edebilir. StrongBox ise yerleşik güvenli öğeler (eSE) veya SoC üzerinde güvenli işlem birimleri (iSE) gibi cihazları ifade eder.

Modül aşağıdakileri 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 ile 64 bayt (dahil) arasında 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) ve sonraki sürümleri hedefleyen uygulamalar için KeyInfo.getSecurityLevel() bölümüne bakın), bazı anahtar kullanımı yetkilendirmeleri 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 genellikle bağımsız, güvenli bir gerçek zamanlı saate sahip olmadığından zaman geçerlilik aralığı yetkilendirmelerini zorunlu tutmaz.

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 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, çeşitli uygulamaların kullanıcı izniyle aynı kimlik bilgisi grubunu kullanmasına olanak tanır.

Bir uygulamanın kendi kimlik bilgilerini depolamasına ve yalnızca bu uygulamanın bu bilgilere erişmesine izin vermek için Android Keystore 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öntemde kullanıcının kimlik bilgilerini seçmesi gerekmez.

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

Bu özelliği kullanmak için Android 4.3'te (API düzeyi 18) kullanıma sunulan AndroidKeyStore sağlayıcısıyla birlikte standart KeyStore ve KeyPairGenerator ya da KeyGenerator sınıfları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ı olabileceğinden, uygulamaların kullanıcı arayüzünün duyarlı kalmasını sağlamak için ana iş parçacığında AndroidKeyStore kullanmaktan kaçınması gerekir. (StrictMode, bunun geçerli olmadığı 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 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ı bir bayt dizisi olarak ileterek 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 üzerinden 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

AndroidKeyStore içine bir anahtar oluştururken veya içe aktarırken anahtarın yalnızca kullanıcının kimliği doğrulanmışsa kullanılabileceğini belirtebilirsiniz. Kullanıcının kimliği, güvenli kilit ekranı kimlik bilgilerinin (desen/PIN/şifre, biyometrik kimlik bilgileri) bir 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 yetkilendirilir.
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, BiometricPrompt örneğinde authenticate() işlevini çağırarak bu süreci 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, uygulamanızın anahtarının kullandığı kimlik bilgilerini ayarlayıp ayarlamadığını belirlemek için canAuthenticate() işlevini çağırı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 öğesini setInvalidatedByBiometricEnrollment() öğesine 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.