Sistem Android Keystore memungkinkan Anda menyimpan kunci kriptografis dalam penampung agar lebih sulit untuk diekstrak dari perangkat. Setelah kunci berada di keystore, Anda dapat menggunakannya untuk operasi kriptografi, dan materi kunci tersebut tetap tidak dapat diekspor. Selain itu, sistem keystore memungkinkan Anda membatasi waktu dan cara penggunaan kunci, misalnya mewajibkan autentikasi pengguna untuk menggunakan kunci, atau membatasi kunci agar hanya digunakan dalam mode kriptografi tertentu. Lihat bagian Fitur Keamanan untuk mengetahui informasi selengkapnya.
Sistem keystore digunakan oleh
KeyChain
API, diperkenalkan di Android 4.0 (level API 14), serta fitur penyedia Android
Keystore, diperkenalkan di Android 4.3 (level API 18). Dokumen ini menjelaskan
waktu dan cara Anda menggunakan sistem Android Keystore.
Fitur keamanan
Sistem Android Keystore melindungi materi kunci dari penggunaan tanpa izin dengan dua cara. Pertama, mengurangi risiko penggunaan materi kunci tanpa izin dari luar perangkat Android dengan mencegah ekstraksi materi kunci dari proses aplikasi dan dari perangkat Android secara keseluruhan. Kedua, sistem keystore mengurangi risiko penggunaan materi kunci tanpa izin dalam perangkat Android dengan membuat aplikasi menentukan penggunaan kuncinya dengan izin, lalu menerapkan batasan tersebut di luar proses aplikasi.
Pencegahan ekstraksi
Materi kunci dari kunci Android Keystore dilindungi dari ekstraksi menggunakan dua langkah pengamanan:
- Materi kunci tidak memasuki proses aplikasi. Saat sebuah aplikasi menjalankan operasi kriptografi menggunakan kunci Android Keystore, di balik layar, teks biasa, ciphertext, dan pesan yang perlu ditandatangani atau diverifikasi diteruskan ke proses sistem yang menjalankan operasi kriptografi tersebut. Jika proses aplikasi disusupi, penyerang mungkin dapat menggunakan kunci aplikasi, tetapi tidak dapat mengekstrak materi kuncinya (misalnya, untuk digunakan di luar perangkat Android).
- Materi kunci dapat terikat dengan hardware aman perangkat Android, seperti Trusted Execution Environment (TEE) atau
Elemen Pengaman (SE). Jika fitur ini diaktifkan untuk sebuah kunci, materi kuncinya
tidak akan diekspos di luar hardware yang aman. Jika Android OS disusupi atau
penyerang dapat membaca penyimpanan internal perangkat, penyerang mungkin dapat menggunakan kunci Keystore
Android aplikasi di perangkat Android, tetapi tidak dapat mengekstraknya dari perangkat. Fitur ini hanya akan aktif
jika hardware aman perangkat mendukung kombinasi tertentu algoritma kunci, mode
pemblokiran, skema padding, dan digest yang diizinkan untuk digunakan dengan kunci.
Untuk memeriksa apakah fitur ini diaktifkan untuk sebuah kunci, dapatkan
KeyInfo
untuk kunci tersebut. Langkah berikutnya bergantung pada versi SDK target aplikasi Anda:- Jika aplikasi Anda menargetkan Android 10 (level API 29) atau yang lebih tinggi, periksa nilai
return
getSecurityLevel()
. Nilai return yang cocok denganKeyProperties.SecurityLevelEnum.TRUSTED_ENVIRONMENT
atauKeyProperties.SecurityLevelEnum.STRONGBOX
menunjukkan bahwa kunci tersebut berada dalam hardware yang aman. - Jika aplikasi Anda menargetkan Android 9 (level API 28) atau yang lebih rendah, periksa nilai return
boolean
KeyInfo.isInsideSecurityHardware()
.
- Jika aplikasi Anda menargetkan Android 10 (level API 29) atau yang lebih tinggi, periksa nilai
return
Modul keamanan hardware
Perangkat yang didukung dan menjalankan Android 9 (level API 28) atau yang lebih tinggi dapat memiliki StrongBox Keymaster, implementasi Keymaster atau Keymint HAL yang berada di elemen pengaman yang mirip dengan modul keamanan hardware. Meskipun modul keamanan hardware dapat merujuk ke berbagai implementasi penyimpanan kunci yang tidak dapat terungkap oleh penyusupan kernel Linux, seperti TEE, StrongBox secara eksplisit merujuk pada perangkat seperti Elemen Pengaman tersemat (eSE) atau unit pemrosesan yang aman (iSE) di SoC.
Modul ini berisi hal-hal berikut:
- CPU-nya sendiri
- Penyimpanan aman
- Generator angka-acak yang sesungguhnya.
- Mekanisme tambahan untuk mencegah modifikasi paket dan sideload aplikasi tanpa izin
- Timer yang aman
- Pin notifikasi reboot (atau yang setara), seperti input/output tujuan umum (GPIO)
Untuk mendukung implementasi StrongBox rendah daya, subset algoritma dan ukuran kunci berikut didukung:
- RSA 2048
- AES 128 dan 256
- ECDSA, ECDH P-256
- HMAC-SHA256 (mendukung ukuran kunci antara 8 dan 64 byte, inklusif)
- Triple DES
- APDU yang Diperpanjang
- Pengesahan Kunci
- Dukungan Amendemen H untuk upgrade
Saat membuat atau mengimpor kunci menggunakan class KeyStore
,
indikasikan preferensi untuk menyimpan kunci di StrongBox Keymaster
dengan meneruskan true
ke metode setIsStrongBoxBacked()
.
Meskipun StrongBox sedikit lebih lambat dan memiliki keterbatasan resource (artinya mendukung lebih sedikit operasi serentak) dibandingkan TEE, StrongBox memberikan jaminan keamanan yang lebih baik terhadap serangan fisik dan side-channel. Jika Anda ingin memprioritaskan jaminan keamanan yang lebih tinggi daripada efisiensi resource aplikasi, sebaiknya gunakan StrongBox di perangkat tempatnya tersedia. Di mana pun StrongBox tidak tersedia, aplikasi Anda selalu dapat kembali ke TEE untuk menyimpan materi kunci.
Otorisasi penggunaan kunci
Untuk menghindari penggunaan kunci tanpa izin di perangkat Android, Android Keystore mengizinkan aplikasi untuk menentukan penggunaan kuncinya dengan izin saat membuat atau mengimpor kunci. Setelah kunci dibuat atau diimpor, otorisasinya tidak dapat diubah. Selanjutnya, otorisasi diberlakukan oleh Android Keystore setiap kali kunci digunakan. Otorisasi ini merupakan fitur keamanan lanjutan yang umumnya hanya berguna jika Anda menetapkan bahwa peretasan proses aplikasi setelah kunci dibuat/diimpor (tetapi tidak sebelum atau selama dibuat/diimpor) tidak akan mengakibatkan penggunaan kunci tersebut tanpa izin.
Otorisasi penggunaan kunci yang didukung termasuk ke dalam kategori berikut:
- Kriptografi: kunci hanya dapat digunakan dengan algoritma, operasi, atau tujuan kunci yang diotorisasi (mengenkripsi, mendekripsi, menandatangani, memverifikasi), skema padding, mode pemblokiran, atau digest.
- Interval validitas sementara: kunci diotorisasi hanya untuk digunakan selama interval waktu yang ditentukan.
- Autentikasi pengguna: kunci hanya dapat digunakan jika pengguna telah diautentikasi baru-baru ini. Lihat Mewajibkan autentikasi pengguna untuk penggunaan kunci.
Sebagai langkah keamanan tambahan untuk kunci yang materi kuncinya berada dalam hardware aman (lihat
KeyInfo.isInsideSecurityHardware()
atau, untuk aplikasi yang menargetkan Android 10 (level API 29) atau yang lebih tinggi,
KeyInfo.getSecurityLevel()
),
beberapa otorisasi penggunaan kunci mungkin diberlakukan oleh hardware aman,
bergantung pada perangkat Android.
Hardware aman biasanya menerapkan otorisasi kriptografi dan autentikasi
pengguna. Namun, hardware aman biasanya tidak menerapkan otorisasi
interval validitas sementara, karena hardware ini biasanya tidak memiliki
jam real-time yang independen dan aman.
Anda dapat meminta kueri apakah otorisasi autentikasi pengguna kunci diberlakukan oleh
hardware yang aman menggunakan
KeyInfo.isUserAuthenticationRequirementEnforcedBySecureHardware()
.
Memilih antara keychain dan penyedia Android Keystore
Gunakan KeyChain
API jika Anda menginginkan
kredensial berskala sistem. Ketika suatu aplikasi meminta penggunaan kredensial apa pun
melalui KeyChain
API, pengguna dapat
memilih kredensial terinstal mana yang dapat diakses oleh suatu aplikasi,
melalui UI yang disediakan oleh sistem. Dengan cara ini, beberapa aplikasi dapat menggunakan
kumpulan kredensial yang sama dengan izin pengguna.
Gunakan penyedia Android Keystore untuk mengizinkan setiap aplikasi menyimpan kredensialnya
sendiri, yang hanya dapat diakses oleh aplikasi tersebut.
Cara ini memungkinkan aplikasi mengelola kredensial yang hanya dapat digunakan oleh aplikasi itu sendiri,
sekaligus memberikan manfaat keamanan yang sama seperti
yang diberikan KeyChain
API untuk kredensial seluruh sistem.
Metode ini tidak mengharuskan pengguna memilih kredensial.
Menggunakan penyedia Android Keystore
Untuk menggunakan fitur ini, gunakan class standar KeyStore
dan KeyPairGenerator
atau
KeyGenerator
bersama dengan penyedia AndroidKeyStore
yang diperkenalkan di Android 4.3 (level API 18).
AndroidKeyStore
didaftarkan sebagai jenis KeyStore
untuk digunakan dengan metode KeyStore.getInstance(type)
,
dan sebagai penyedia untuk digunakan dengan metode KeyPairGenerator.getInstance(algorithm, provider)
dan KeyGenerator.getInstance(algorithm, provider)
.
Membuat kunci pribadi atau kunci rahasia baru
Untuk membuat KeyPair
baru yang berisi
PrivateKey
,
Anda harus menentukan atribut X.509 awal sertifikat. Anda dapat menggunakan
KeyStore.setKeyEntry()
untuk mengganti sertifikat di kemudian hari dengan sertifikat yang ditandatangani
oleh certificate authority (CA).
Untuk membuat pasangan kunci, gunakan KeyPairGenerator
dengan KeyGenParameterSpec
.
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();
Mengimpor kunci terenkripsi ke hardware yang aman
Android 9 (level API 28) dan yang lebih tinggi memungkinkan Anda mengimpor kunci terenkripsi dengan aman ke keystore menggunakan format kunci yang dienkode dengan ASN.1. Keymaster kemudian akan mendekripsi kunci dalam keystore, sehingga isi kunci tidak pernah muncul sebagai teks biasa dalam memori host perangkat. Proses ini memberikan keamanan dekripsi kunci tambahan.
Untuk mendukung pengimporan kunci terenkripsi secara aman ke keystore, lakukan langkah-langkah berikut:
Buat pasangan kunci yang menggunakan fungsi
PURPOSE_WRAP_KEY
. Sebaiknya Anda juga menambahkan pengesahan ke pasangan kunci ini.Pada server atau komputer yang Anda percayai, buat pesan ASN.1 untuk
SecureKeyWrapper
.Wrapper akan berisi skema berikut:
KeyDescription ::= SEQUENCE { keyFormat INTEGER, authorizationList AuthorizationList } SecureKeyWrapper ::= SEQUENCE { wrapperFormatVersion INTEGER, encryptedTransportKey OCTET_STRING, initializationVector OCTET_STRING, keyDescription KeyDescription, secureKey OCTET_STRING, tag OCTET_STRING }
Buat objek
WrappedKeyEntry
, lalu teruskan pesan ASN.1 sebagai array byte.Teruskan objek
WrappedKeyEntry
ini ke overloadsetEntry()
yang menerima objekKeystore.Entry
.
Menggunakan entri keystore
Anda dapat mengakses penyedia AndroidKeyStore
melalui
semua KeyStore
API standar.
Mencantumkan entri
Cantumkan entri di keystore dengan memanggil metode aliases()
:
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();
Menandatangani dan memverifikasi data
Tanda tangani data dengan mengambil KeyStore.Entry
dari keystore dan menggunakan
Signature
API, seperti sign()
:
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();
Demikian pula, verifikasikan data dengan metode verify(byte[])
:
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);
Mewajibkan autentikasi pengguna untuk penggunaan kunci
Saat membuat atau mengimpor kunci ke AndroidKeyStore
, Anda dapat menetapkan agar kunci
hanya boleh digunakan jika pengguna telah diautentikasi. Pengguna diautentikasi menggunakan
salah satu kredensial layar kunci aman mereka (pola/PIN/sandi, kredensial biometrik).
Autentikasi ini merupakan fitur keamanan lanjutan yang umumnya hanya berguna jika Anda menetapkan bahwa peretasan proses aplikasi setelah kunci dibuat/diimpor (tetapi tidak sebelum atau selama dibuat/diimpor) tidak dapat mengabaikan keharusan pengguna untuk diautentikasi agar dapat menggunakan kunci.
Ketika kunci hanya diizinkan untuk digunakan jika pengguna telah diautentikasi, Anda dapat memanggil
setUserAuthenticationParameters()
untuk mengonfigurasinya agar beroperasi dalam salah satu mode berikut:
- Memberi otorisasi selama durasi waktu tertentu
- Semua kunci diizinkan untuk digunakan segera setelah pengguna melakukan autentikasi menggunakan salah satu kredensial yang ditentukan.
- Memberi otorisasi selama durasi operasi kriptografi tertentu
Setiap operasi yang melibatkan kunci tertentu harus diizinkan satu per satu oleh pengguna.
Aplikasi Anda memulai proses ini dengan memanggil
authenticate()
di instanceBiometricPrompt
.
Untuk setiap kunci yang dibuat, Anda dapat memilih untuk mendukung
kredensial
biometrik yang kuat,
kredensial
layar kunci, atau kedua jenis kredensial. Untuk menentukan apakah pengguna telah menyiapkan kredensial
yang diandalkan oleh kunci aplikasi Anda, panggil
canAuthenticate()
.
Jika kunci hanya mendukung kredensial biometrik, kunci tersebut akan dibatalkan secara default setiap kali
pendaftaran biometrik baru ditambahkan. Anda dapat mengonfigurasi kunci agar tetap valid saat pendaftaran
biometrik baru ditambahkan. Untuk melakukannya, teruskan false
ke
setInvalidatedByBiometricEnrollment()
.
Pelajari lebih lanjut cara menambahkan kemampuan autentikasi biometrik ke aplikasi Anda, termasuk cara menampilkan dialog autentikasi biometrik.
Algoritma yang didukung
Cipher
KeyGenerator
KeyFactory
KeyStore
(mendukung jenis kunci yang sama sepertiKeyGenerator
danKeyPairGenerator
)KeyPairGenerator
Mac
Signature
SecretKeyFactory
Artikel blog
Lihat entri blog Unifying Key Store Access in ICS.