Seperti sebagian besar software enkripsi disk dan file, enkripsi penyimpanan Android secara tradisional mengandalkan kunci enkripsi mentah yang ada di memori sistem sehingga enkripsi dapat dilakukan. Meskipun enkripsi dilakukan oleh hardware khusus, bukan oleh software, software umumnya masih perlu mengelola kunci enkripsi mentah.
Hal ini biasanya tidak dianggap sebagai masalah karena kunci tidak ada selama serangan offline, yang merupakan jenis serangan utama yang ingin dilindungi oleh enkripsi penyimpanan. Namun, ada keinginan untuk memberikan perlindungan yang lebih baik terhadap jenis serangan lainnya, seperti serangan cold boot, dan serangan online yang memungkinkan penyerang membocorkan memori sistem tanpa sepenuhnya membahayakan perangkat.
Untuk mengatasi masalah ini, Android 11 memperkenalkan dukungan untuk kunci yang di-wrap hardware, jika dukungan hardware tersedia. Kunci yang di-wrap hardware adalah kunci penyimpanan yang hanya diketahui dalam bentuk mentah oleh hardware khusus; software hanya melihat dan menggunakan kunci ini dalam bentuk yang di-wrap (dienkripsi). Hardware ini harus dapat membuat dan mengimpor kunci penyimpanan, membungkus kunci penyimpanan dalam bentuk sementara dan jangka panjang, mendapatkan subkunci, memprogram satu subkunci secara langsung ke dalam mesin kripto inline, dan menampilkan subkunci terpisah ke software.
Catatan: Mesin kripto inline (atau hardware enkripsi inline) merujuk pada hardware yang mengenkripsi/mendekripsi data saat data sedang dalam perjalanan ke/dari perangkat penyimpanan. Biasanya ini adalah pengontrol host UFS atau eMMC yang mengimplementasikan ekstensi kripto yang ditentukan oleh spesifikasi JEDEC yang sesuai.
Desain
Bagian ini menyajikan desain fitur kunci yang di-wrap hardware, termasuk dukungan hardware yang diperlukan untuknya. Diskusi ini berfokus pada enkripsi berbasis file (FBE), tetapi solusi ini juga berlaku untuk enkripsi metadata.
Salah satu cara untuk menghindari kebutuhan kunci enkripsi mentah dalam memori sistem adalah dengan menyimpannya hanya di keyslot mesin kripto inline. Namun, pendekatan ini menimbulkan beberapa masalah:
- Jumlah kunci enkripsi mungkin melebihi jumlah slot kunci.
- Mesin kripto inline biasanya kehilangan konten slot kuncinya jika pengontrol host penyimpanan direset. Merestel pengontrol host penyimpanan adalah prosedur pemulihan error standar yang dijalankan jika jenis error penyimpanan tertentu terjadi, dan error tersebut dapat terjadi kapan saja. Oleh karena itu, saat kripto inline digunakan, sistem operasi harus selalu siap untuk memprogram ulang slot kunci tanpa intervensi pengguna.
- Mesin kripto inline hanya dapat digunakan untuk mengenkripsi/mendekripsi blok data lengkap di disk. Namun, dalam kasus FBE, software masih perlu dapat melakukan pekerjaan kriptografi lainnya seperti enkripsi nama file dan mendapatkan ID kunci. Software masih memerlukan akses ke kunci FBE mentah untuk melakukan pekerjaan lain ini.
Untuk menghindari masalah ini, kunci penyimpanan dibuat menjadi kunci yang di-wrap hardware, yang hanya dapat dibuka lapisannya dan digunakan oleh hardware khusus. Hal ini memungkinkan dukungan untuk kunci dalam jumlah tak terbatas. Selain itu, hierarki kunci diubah dan sebagian dipindahkan ke hardware ini, yang memungkinkan subkunci dikembalikan ke software untuk tugas yang tidak dapat menggunakan mesin kripto inline.
Hierarki kunci
Kunci dapat diturunkan dari kunci lain menggunakan fungsi turunan kunci (KDF) seperti HKDF, sehingga menghasilkan hierarki kunci.
Diagram berikut menggambarkan hierarki kunci umum untuk FBE saat kunci yang di-wrap hardware tidak digunakan:
Kunci kelas FBE adalah kunci enkripsi mentah yang diteruskan Android ke kernel Linux untuk membuka kunci serangkaian direktori terenkripsi tertentu, seperti penyimpanan yang dienkripsi dengan kredensial untuk pengguna Android tertentu. (Di kernel, kunci ini disebut kunci master fscrypt.) Dari kunci ini, kernel mendapatkan subkunci berikut:
- ID kunci. ID ini tidak digunakan untuk enkripsi, tetapi merupakan nilai yang digunakan untuk mengidentifikasi kunci yang digunakan untuk melindungi file atau direktori tertentu.
- Kunci enkripsi konten file
- Kunci enkripsi nama file
Sebaliknya, diagram berikut menggambarkan hierarki kunci untuk FBE saat kunci yang di-wrap hardware digunakan:
Dibandingkan dengan kasus sebelumnya, tingkat tambahan telah ditambahkan ke hierarki kunci, dan kunci enkripsi konten file telah dipindahkan. Node root masih merepresentasikan kunci yang diteruskan Android ke Linux untuk membuka kunci serangkaian direktori terenkripsi. Namun, kunci tersebut kini dalam bentuk yang dibungkus secara sementara, dan agar dapat digunakan, kunci tersebut harus diteruskan ke hardware khusus. Hardware ini harus mengimplementasikan dua antarmuka yang menggunakan kunci yang dienkapsulasi secara sementara:
- Satu antarmuka untuk mendapatkan
inline_encryption_key
dan memprogramnya langsung ke dalam slot kunci mesin kripto inline. Hal ini memungkinkan konten file dienkripsi/didekripsi tanpa software memiliki akses ke kunci mentah. Di kernel umum Android, antarmuka ini sesuai dengan operasiblk_crypto_ll_ops::keyslot_program
, yang harus diimplementasikan oleh driver penyimpanan. - Satu antarmuka untuk mendapatkan dan menampilkan
sw_secret
("software secret" -- juga disebut "raw secret" di beberapa tempat), yang merupakan kunci yang digunakan Linux untuk mendapatkan subkunci untuk semua hal selain enkripsi konten file. Di kernel umum Android, antarmuka ini sesuai dengan operasiblk_crypto_ll_ops::derive_sw_secret
, yang harus diimplementasikan oleh driver penyimpanan.
Untuk mendapatkan inline_encryption_key
dan sw_secret
dari
kunci penyimpanan mentah, hardware harus menggunakan KDF yang kuat secara kriptografis. KDF ini
harus mengikuti praktik terbaik kriptografi; KDF harus memiliki kekuatan keamanan minimal 256 bit, yaitu cukup untuk algoritma apa pun yang digunakan nanti. Selain itu, saat mendapatkan setiap jenis subkunci, kunci ini harus menggunakan label dan konteks yang berbeda untuk menjamin bahwa subkunci yang dihasilkan terisolasi secara kriptografi, yaitu, pengetahuan tentang salah satu subkunci tidak akan mengungkapkan subkunci lainnya. Peregangan kunci tidak diperlukan, karena kunci penyimpanan mentah sudah menjadi kunci acak yang seragam.
Secara teknis, KDF apa pun yang memenuhi persyaratan keamanan dapat digunakan.
Namun, untuk tujuan pengujian, vts_kernel_encryption_test
menerapkan KDF yang sama di software untuk mereproduksi ciphertext di disk
dan memverifikasi bahwa ciphertext tersebut sudah benar. Untuk mempermudah pengujian dan memastikan KDF yang aman dan telah ditinjau digunakan, sebaiknya hardware menerapkan KDF default yang diperiksa oleh pengujian. Untuk hardware yang menggunakan KDF yang berbeda, lihat Menguji kunci yang dienkapsulasi untuk mengetahui cara mengonfigurasi pengujian yang sesuai.
Penggabungan kunci
Untuk memenuhi tujuan keamanan kunci yang di-wrap hardware, dua jenis wrapping kunci ditentukan:
- Penggabungan sementara: hardware mengenkripsi kunci mentah menggunakan kunci yang dibuat secara acak setiap kali perangkat di-boot dan tidak diekspos secara langsung di luar hardware.
- Pembungkusan jangka panjang: hardware mengenkripsi kunci mentah menggunakan kunci unik dan persisten yang dibuat ke dalam hardware yang tidak diekspos secara langsung di luar hardware.
Semua kunci yang diteruskan ke kernel Linux untuk membuka kunci penyimpanan dienkripsi secara sementara. Hal ini memastikan bahwa jika penyerang dapat mengekstrak kunci yang sedang digunakan dari memori sistem, maka kunci tersebut tidak dapat digunakan tidak hanya di luar perangkat, tetapi juga di perangkat setelah perangkat dimulai ulang.
Pada saat yang sama, Android tetap harus dapat menyimpan versi terenkripsi kunci di disk agar dapat dibuka kuncinya. Kunci mentah akan berfungsi untuk tujuan ini. Namun, sebaiknya kunci mentah tidak pernah ada di memori sistem sama sekali sehingga tidak pernah dapat diekstrak untuk digunakan di luar perangkat, meskipun diekstrak pada waktu booting. Oleh karena itu, konsep pembungkusan jangka panjang ditentukan.
Untuk mendukung pengelolaan kunci yang di-wrap dengan dua cara berbeda ini, hardware harus menerapkan antarmuka berikut:
- Antarmuka untuk membuat dan mengimpor kunci penyimpanan, yang menampilkannya dalam
bentuk terenkapsulasi jangka panjang. Antarmuka ini diakses secara tidak langsung melalui
KeyMint, dan sesuai dengan tag KeyMint
TAG_STORAGE_KEY
. Kemampuan "generate" digunakan olehvold
untuk membuat kunci penyimpanan baru yang akan digunakan oleh Android, sedangkan kemampuan "import" digunakan olehvts_kernel_encryption_test
untuk mengimpor kunci pengujian. - Antarmuka untuk mengonversi kunci penyimpanan gabungan jangka panjang menjadi
kunci penyimpanan gabungan sementara. Ini sesuai dengan
metode KeyMint
convertStorageKeyToEphemeral
. Metode ini digunakan olehvold
danvts_kernel_encryption_test
untuk membuka kunci penyimpanan.
Algoritma penggabungan kunci adalah detail implementasi, tetapi harus menggunakan AEAD yang kuat seperti AES-256-GCM dengan IV acak.
Perubahan software diperlukan
AOSP sudah memiliki framework dasar untuk mendukung kunci yang di-wrap hardware. Hal ini mencakup dukungan di komponen ruang pengguna seperti vold
, serta dukungan kernel Linux di blk-crypto, fscrypt, dan dm-default-key.
Namun, beberapa perubahan khusus penerapan diperlukan.
Perubahan KeyMint
Implementasi KeyMint perangkat harus diubah untuk mendukung
TAG_STORAGE_KEY
dan mengimplementasikan metode
convertStorageKeyToEphemeral
.
Di Keymaster, exportKey
digunakan, bukan
convertStorageKeyToEphemeral
.
Perubahan kernel Linux
Driver kernel Linux untuk mesin kripto inline perangkat harus diubah untuk mendukung kunci yang di-wrap hardware.
Untuk kernel android14
dan yang lebih tinggi,
tetapkan BLK_CRYPTO_KEY_TYPE_HW_WRAPPED
di blk_crypto_profile::key_types_supported
,
buat blk_crypto_ll_ops::keyslot_program
dan blk_crypto_ll_ops::keyslot_evict
mendukung pemrograman/pengusiran kunci yang di-wrap hardware,
dan terapkan blk_crypto_ll_ops::derive_sw_secret
.
Untuk kernel android12
dan android13
, setel BLK_CRYPTO_FEATURE_WRAPPED_KEYS
di blk_keyslot_manager::features
, buat blk_ksm_ll_ops::keyslot_program
dan blk_ksm_ll_ops::keyslot_evict
mendukung pemrograman/pengusiran kunci yang di-wrap hardware, dan terapkan blk_ksm_ll_ops::derive_raw_secret
.
Untuk kernel android11
,
tetapkan BLK_CRYPTO_FEATURE_WRAPPED_KEYS
di keyslot_manager::features
,
buat keyslot_mgmt_ll_ops::keyslot_program
dan keyslot_mgmt_ll_ops::keyslot_evict
mendukung pemrograman/pengusiran kunci yang di-wrap hardware,
dan terapkan keyslot_mgmt_ll_ops::derive_raw_secret
.
Menguji kunci gabungan
Meskipun enkripsi dengan kunci yang digabungkan hardware lebih sulit diuji daripada enkripsi dengan kunci mentah, pengujian masih dapat dilakukan dengan mengimpor kunci pengujian dan menerapkan ulang turunan kunci yang dilakukan hardware. Hal ini diimplementasikan
di vts_kernel_encryption_test
. Untuk menjalankan pengujian ini,
jalankan:
atest -v vts_kernel_encryption_test
Baca log pengujian dan verifikasi bahwa kasus pengujian kunci yang di-wrap hardware (misalnya, FBEPolicyTest.TestAesInlineCryptOptimizedHwWrappedKeyPolicy
dan DmDefaultKeyTest.TestHwWrappedKey
) tidak dilewati karena dukungan untuk kunci yang di-wrap hardware tidak terdeteksi, karena hasil pengujian masih "lulus" dalam kasus tersebut.
Secara default, vts_kernel_encryption_test
mengasumsikan hardware
menerapkan KDF yang disebut kdf1
. KDF ini termasuk dalam keluarga KDF mode penghitung dari NIST SP 800-108, dan menggunakan AES-256-CMAC sebagai fungsi pseudorandom. Untuk mengetahui informasi selengkapnya tentang CMAC, lihat spesifikasi CMAC. KDF menggunakan konteks dan label tertentu saat mendapatkan setiap subkunci. Hardware harus menerapkan KDF ini, termasuk pilihan yang tepat untuk
konteks, label, dan pemformatan string input tetap saat mendapatkan setiap
subkey.
Namun, vts_kernel_encryption_test
juga menerapkan KDF tambahan
kdf2
melalui kdf4
. Keduanya sama amannya dengan
kdf1
dan hanya berbeda dalam pilihan konteks, label, dan
pemformatan string input tetap. Mereka ada hanya untuk mengakomodasi hardware yang berbeda.
Untuk perangkat yang menggunakan KDF yang berbeda, tetapkan properti sistem
ro.crypto.hw_wrapped_keys.kdf
di
PRODUCT_VENDOR_PROPERTIES
ke nama KDF seperti yang ditentukan dalam
kode sumber pengujian. Hal ini menyebabkan vts_kernel_encryption_test
memeriksa KDF tersebut, bukan kdf1
. Misalnya, untuk memilih
kdf2
, gunakan:
PRODUCT_VENDOR_PROPERTIES += ro.crypto.hw_wrapped_keys.kdf=kdf2
Untuk perangkat yang menggunakan KDF yang tidak didukung oleh pengujian, tambahkan juga penerapan KDF tersebut ke pengujian dan beri nama yang unik.
Mengaktifkan kunci gabungan
Jika dukungan kunci yang di-wrap hardware perangkat berfungsi dengan benar, lakukan perubahan berikut pada file fstab
perangkat agar Android menggunakannya untuk enkripsi FBE dan metadata:
- FBE: tambahkan tanda
wrappedkey_v0
ke parameterfileencryption
. Misalnya, gunakanfileencryption=::inlinecrypt_optimized+wrappedkey_v0
. Untuk detail selengkapnya, lihat dokumentasi FBE. - Enkripsi metadata: tambahkan tanda
wrappedkey_v0
ke parametermetadata_encryption
. Misalnya, gunakanmetadata_encryption=:wrappedkey_v0
. Untuk mengetahui detail selengkapnya, lihat dokumentasi enkripsi metadata.