Sistem Keystore Android memungkinkan Anda menyimpan kunci kriptografis dalam container agar lebih sulit untuk diekstrak dari perangkat. Setelah berada di keystore, kunci tersebut dapat digunakan untuk operasi kriptografi tanpa mengimpor materi kunci lainnya. Selain itu, keystore menawarkan fasilitas untuk membatasi kapan dan bagaimana kunci dapat digunakan, seperti mengharuskan autentikasi pengguna untuk penggunaan kunci atau membatasi kunci agar hanya digunakan dalam mode kriptografi tertentu. Lihat bagian Fitur Keamanan untuk mengetahui informasi selengkapnya.
Sistem Keystore digunakan oleh API KeyChain
, diperkenalkan di Android 4.0 (API level 14); fitur penyedia Keystore Android, diperkenalkan di Android 4.3 (API level 18); dan Library keamanan, tersedia sebagai bagian dari Jetpack. Dokumen ini menjelaskan kapan dan bagaimana Anda dapat menggunakan penyedia Keystore Android.
Fitur keamanan
Sistem Android Keystore melindungi materi kunci dari penggunaan yang tidak sah. Pertama, Android Keystore mengurangi penggunaan materi kunci di luar perangkat Android secara tidak sah dengan mencegah ekstraksi materi kunci dari proses aplikasi dan dari perangkat Android secara keseluruhan. Kedua, Android KeyStore mengurangi penggunaan materi kunci pada perangkat Android secara tidak sah dengan mengharuskan aplikasi menetapkan penggunaan kunci yang diizinkan dan kemudian memberlakukan pembatasan tersebut di luar proses aplikasi.
Pencegahan ekstraksi
Materi kunci dari kunci Android Keystore dilindungi dari ekstraksi melalui dua langkah pengamanan:
- Materi kunci tidak memasuki proses aplikasi. Saat sebuah aplikasi menjalankan operasi kriptografi menggunakan kunci Android Keystore, di belakang layar teks biasa, ciphertext, dan pesan yang perlu ditandatangani atau diverifikasi diteruskan ke proses sistem yang menjalankan operasi kriptografi tersebut. Jika proses aplikasi ini diretas, penyerang mungkin dapat menggunakan kunci aplikasi, tetapi tidak dapat mengekstrak materi kuncinya (misalnya, untuk digunakan di luar perangkat Android).
- Materi kunci mungkin terikat dengan hardware aman (misalnya Trusted Execution Environment (TEE), Secure Element (SE)) perangkat Android. Jika fitur ini diaktifkan untuk sebuah kunci, materi kuncinya tidak akan terekspos di luar hardware aman. Jika Android OS diretas atau penyerang dapat membaca penyimpanan internal perangkat, penyerang mungkin dapat menggunakan setiap kunci Android Keystore aplikasi pada perangkat Android, tetapi tidak dapat mengekstraknya dari perangkat. Fitur ini hanya akan aktif jika hardware aman perangkat mendukung kombinasi algoritme kunci tertentu, mode pemblokiran, skema padding, dan digest yang mengizinkan kunci untuk digunakan. Untuk memeriksa apakah fitur ini diaktifkan bagi suatu kunci, dapatkan
KeyInfo
untuk kunci tersebut dan periksa nilai hasilKeyInfo.isInsideSecurityHardware()
.
Modul keamanan hardware
Perangkat yang didukung yang menjalankan Android 9 (API level 28) atau lebih tinggi dapat memiliki StrongBox Keymaster, suatu implementasi Keymaster HAL yang berada dalam modul keamanan hardware. Modul ini berisi hal-hal berikut:
- CPU-nya sendiri.
- Penyimpanan aman.
- Generator angka-acak sebenarnya.
- Mekanisme tambahan untuk menahan modifikasi paket dan sideloading aplikasi tanpa izin.
Saat memeriksa kunci yang disimpan dalam StrongBox Keymaster, sistem akan menguatkan integritas kunci dengan Trusted Execution Environment (TEE).
Untuk mendukung implementasi StrongBox rendah daya, beberapa algoritme dan ukuran kunci didukung:
- RSA 2048
- AES 128 dan 256
- ECDSA P-256
- HMAC-SHA256 (mendukung ukuran kunci antara 8 dan 64 byte, inklusif)
- Triple DES 168
Saat membuat atau mengimpor kunci menggunakan class KeyStore
, indikasikan preferensi untuk menyimpan kunci di StrongBox Keymaster dengan meneruskan true
ke metode setIsStrongBoxBacked()
.
Otorisasi penggunaan kunci
Untuk meminimalkan penggunaan kunci pada perangkat Android secara tidak sah, Android Keystore mengizinkan aplikasi menentukan apa saja penggunaan yang sah atas kunci tersebut selama proses pembuatan atau impor kunci. Setelah kunci dibuat atau diimpor, otorisasinya tidak dapat diubah. Selanjutnya, otorisasi diberlakukan oleh Android Keystore setiap kali kunci digunakan. 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 secara tidak sah.
Otorisasi penggunaan kunci yang didukung dikelompokkan ke dalam kategori berikut:
- kriptografi: algoritme kunci sah, operasi, atau fungsi (enkripsi, dekripsi, tanda tangan, verifikasi), skema padding, mode pemblokiran, dan ringkasan yang diizinkan untuk digunakan dengan kunci;
- interval validitas sementara: interval waktu saat kunci sah untuk digunakan;
- autentikasi pengguna: kunci hanya dapat digunakan jika pengguna telah diautentikasi baru-baru ini. Baca Mewajibkan Autentikasi Pengguna untuk Penggunaan Kunci.
Sebagai langkah keamanan tambahan, untuk kunci yang materi kuncinya berada dalam hardware aman (lihat KeyInfo.isInsideSecurityHardware()
), beberapa otorisasi penggunaan kunci dapat diberlakukan oleh hardware aman, bergantung pada perangkat Android yang digunakan.
Otorisasi kriptografis dan autentikasi pengguna kemungkinan akan diberlakukan oleh hardware aman.
Otorisasi interval validitas sementara sepertinya tidak akan diberlakukan oleh hardware aman karena biasanya tidak memiliki jam real-time yang aman dan independen.
Untuk mencari tahu apakah otorisasi autentikasi pengguna kunci diberlakukan oleh hardware aman, buat kueri menggunakan KeyInfo.isUserAuthenticationRequirementEnforcedBySecureHardware()
.
Memilih antara keychain atau penyedia Keystore Android
Gunakan API KeyChain
jika Anda menginginkan kredensial berskala sistem. Ketika suatu aplikasi meminta penggunaan kredensial apa pun melalui API KeyChain
, pengguna dapat memilih kredensial terinstal mana yang dapat diakses oleh suatu aplikasi, melalui UI yang disediakan oleh sistem. Hal ini memungkinkan beberapa aplikasi menggunakan kumpulan kredensial yang sama atas izin pengguna.
Gunakan penyedia Keystore Android untuk mengizinkan setiap aplikasi menyimpan kredensialnya sendiri yang hanya dapat diakses oleh aplikasi tersebut.
Cara ini memungkinkan aplikasi mengelola kredensial yang hanya dapat digunakan olehnya sendiri, sekaligus memberikan manfaat keamanan yang sama seperti yang diberikan oleh API KeyChain
untuk kredensial berskala sistem. Metode ini tidak memerlukan interaksi pengguna untuk memilih kredensial.
Menggunakan penyedia keystore Android
Untuk menggunakan fitur ini, gunakan class standar KeyStore
dan KeyPairGenerator
atau KeyGenerator
bersama dengan penyedia AndroidKeyStore
yang diperkenalkan pada Android 4.3 (API level 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 baru
Membuat PrivateKey
baru juga mengharuskan Anda menentukan atribut X.509 awal yang akan dimiliki oleh sertifikat yang ditandatangani sendiri.
Library keamanan menyediakan implementasi default untuk menghasilkan kunci simetris yang valid, seperti yang ditunjukkan dalam cuplikan berikut:
Kotlin
// Although you can define your own key generation parameter specification, it's // recommended that you use the value specified here. val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)
Java
// Although you can define your own key generation parameter specification, it's // recommended that you use the value specified here. KeyGenParameterSpec keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC; String masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec);
Atau, Anda dapat menggunakan KeyStore.setKeyEntry
untuk mengganti sertifikat di lain waktu dengan sertifikat yang ditandatangani oleh Certificate Authority (CA).
Untuk membuat kunci, gunakan KeyPairGenerator
dengan KeyPairGeneratorSpec
.
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();
Membuat kunci rahasia baru
Untuk membuat kunci ini, ikuti proses yang sama seperti saat membuat kunci pribadi baru. Gunakan library Keamanan dalam setiap kasus.
Mengimpor kunci terenkripsi secara lebih aman
Android 9 (API level 28) dan yang lebih tinggi memungkinkan Anda untuk mengimpor kunci terenkripsi dengan aman ke dalam Keystore menggunakan format kunci yang berencode 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 yang 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 perangkat yang Anda percaya, buat pesan ASN.1 yang harus dimuat oleh
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
Penggunaan penyedia AndroidKeyStore
berlangsung di seluruh API KeyStore
standar.
Mencantumkan entri
Cantumkan entri di keystore dengan memanggil metode aliases()
:
Kotlin
/* * Load the Android KeyStore instance using the * "AndroidKeyStore" provider to list out what entries are * currently stored. */ 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 out what entries are * currently stored. */ 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 API Signature
, 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 PrivateKey in our * KeyStore. This uses the X.509 certificate attached to our * 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 PrivateKey in our * KeyStore. This uses the X.509 certificate attached to our * 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 subset kredensial layar kunci aman mereka (pola/PIN/sandi, sidik jari).
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.
Apabila kunci hanya sah untuk digunakan jika pengguna telah diautentikasi, maka kunci akan dikonfigurasi melalui salah satu dari dua mode berikut agar dapat difungsikan:
- Autentikasi pengguna mengizinkan penggunaan kunci selama durasi waktu tertentu. Semua kunci dalam mode ini diizinkan untuk digunakan begitu pengguna membuka layar kunci aman atau mengonfirmasi kredensial layar kunci aman mereka menggunakan alur
KeyguardManager.createConfirmDeviceCredentialIntent
. Masa berlaku otorisasi tersebut bervariasi untuk setiap kunci, seperti yang ditetapkan menggunakansetUserAuthenticationValidityDurationSeconds
saat membuat atau mengimpor kunci. Kunci tersebut hanya dapat dibuat atau diimpor jika layar kunci aman diaktifkan (lihatKeyguardManager.isDeviceSecure()
). Kunci ini akan menjadi tidak valid secara permanen jika layar kunci aman dinonaktifkan (dikonfigurasi ulang ke Tidak Ada, Geser, atau mode lain yang tidak mengautentikasi pengguna) atau direset paksa (misalnya oleh Administrator Perangkat). - Autentikasi pengguna mengizinkan operasi kriptografis tertentu yang terkait dengan sebuah kunci. Dalam mode ini, setiap operasi yang melibatkan kunci tersebut harus diizinkan satu per satu oleh pengguna.
Saat ini, satu-satunya alat otorisasi tersebut adalah autentikasi sidik jari:
FingerprintManager.authenticate
. Kunci tersebut hanya dapat dibuat atau diimpor jika setidaknya satu sidik jari sudah didaftarkan (lihatFingerprintManager.hasEnrolledFingerprints
). Kunci ini akan menjadi tidak valid secara permanen jika sidik jari baru didaftarkan atau semua sidik jari dibatalkan pendaftarannya.
Algoritme yang didukung
Cipher
Algoritme | Didukung (API Level) | Catatan |
---|---|---|
AES/CBC/NoPadding | 23+ | |
AES/CBC/PKCS7Padding | 23+ | |
AES/CTR/NoPadding | 23+ | |
AES/ECB/NoPadding | 23+ | |
AES/ECB/PKCS7Padding | 23+ | |
AES/GCM/NoPadding | 23+ | Hanya IV dengan panjang 12 byte yang didukung. |
RSA/ECB/NoPadding | 18+ | |
RSA/ECB/PKCS1Padding | 18+ | |
RSA/ECB/OAEPWithSHA-1AndMGF1Padding | 23+ | |
RSA/ECB/OAEPWithSHA-224AndMGF1Padding | 23+ | |
RSA/ECB/OAEPWithSHA-256AndMGF1Padding | 23+ | |
RSA/ECB/OAEPWithSHA-384AndMGF1Padding | 23+ | |
RSA/ECB/OAEPWithSHA-512AndMGF1Padding | 23+ | |
RSA/ECB/OAEPPadding | 23+ |
KeyGenerator
Algoritme | Didukung (API Level) | Catatan |
---|---|---|
AES | 23+ | Ukuran yang didukung: 128, 192, 256 |
HmacSHA1 | 23+ |
|
HmacSHA224 | 23+ |
|
HmacSHA256 | 23+ |
|
HmacSHA384 | 23+ |
|
HmacSHA512 | 23+ |
|
KeyFactory
Algoritme | Didukung (API Level) | Catatan |
---|---|---|
EC | 23+ | Spesifikasi kunci yang didukung: KeyInfo (hanya kunci privat), ECPublicKeySpec (hanya kunci publik), X509EncodedKeySpec (hanya kunci publik) |
RSA | 23+ | Spesifikasi kunci yang didukung: KeyInfo (hanya kunci privat), RSAPublicKeySpec (hanya kunci publik), X509EncodedKeySpec (hanya kunci publik) |
KeyStore
KeyStore mendukung jenis kunci yang sama sepertiKeyPairGenerator
dan KeyGenerator
.KeyPairGenerator
Algoritme | Didukung (API Level) | Catatan |
---|---|---|
DSA | 19–22 | |
EC | 23+ |
Sebelum API Level 23, kunci EC dapat dibuat menggunakan KeyPairGenerator |
RSA | 18+ |
|
Mac
Algoritme | Didukung (API Level) | Catatan |
---|---|---|
HmacSHA1 | 23+ | |
HmacSHA224 | 23+ | |
HmacSHA256 | 23+ | |
HmacSHA384 | 23+ | |
HmacSHA512 | 23+ |
Tanda Tangan
Algoritme | Didukung (API Level) | Catatan |
---|---|---|
MD5withRSA | 18+ | |
NONEwithECDSA | 23+ | |
NONEwithRSA | 18+ | |
SHA1withDSA | 19–22 | |
SHA1withECDSA | 19+ | |
SHA1withRSA | 18+ | |
SHA1withRSA/PSS | 23+ | |
SHA224withDSA | 20–22 | |
SHA224withECDSA | 20+ | |
SHA224withRSA | 20+ | |
SHA224withRSA/PSS | 23+ | |
SHA256withDSA | 19–22 | |
SHA256withECDSA | 19+ | |
SHA256withRSA | 18+ | |
SHA256withRSA/PSS | 23+ | |
SHA384withDSA | 19–22 | |
SHA384withECDSA | 19+ | |
SHA384withRSA | 18+ | |
SHA384withRSA/PSS | 23+ | |
SHA512withDSA | 19–22 | |
SHA512withECDSA | 19+ | |
SHA512withRSA | 18+ | |
SHA512withRSA/PSS | 23+ |
SecretKeyFactory
Algoritme | Didukung (API Level) | Catatan |
---|---|---|
AES | 23+ | Spesifikasi kunci yang didukung: KeyInfo |
HmacSHA1 | 23+ | Spesifikasi kunci yang didukung: KeyInfo |
HmacSHA224 | 23+ | Spesifikasi kunci yang didukung: KeyInfo |
HmacSHA256 | 23+ | Spesifikasi kunci yang didukung: KeyInfo |
HmacSHA384 | 23+ | Spesifikasi kunci yang didukung: KeyInfo |
HmacSHA512 | 23+ | Spesifikasi kunci yang didukung: KeyInfo |
Artikel blog
Lihat entri blog Unifying Key Store Access in ICS.