Kunci yang Dibungkus Perangkat Keras

Seperti kebanyakan perangkat lunak enkripsi disk dan file, enkripsi penyimpanan Android biasanya bergantung pada kunci enkripsi mentah yang ada di memori sistem sehingga enkripsi dapat dilakukan. Meskipun enkripsi dilakukan oleh perangkat keras khusus dan bukan perangkat lunak, perangkat lunak umumnya masih perlu mengelola kunci enkripsi mentah.

Biasanya hal ini tidak dianggap sebagai masalah karena kunci tidak akan muncul selama serangan offline, yang merupakan jenis serangan utama yang ingin dilindungi oleh enkripsi penyimpanan. Namun, ada keinginan untuk memberikan peningkatan perlindungan terhadap jenis serangan lain, seperti serangan cold boot , dan serangan online di mana penyerang mungkin dapat membocorkan memori sistem tanpa membahayakan perangkat sepenuhnya.

Untuk mengatasi masalah ini, Android 11 memperkenalkan dukungan untuk kunci yang dibungkus perangkat keras , di mana dukungan perangkat keras hadir. Kunci yang dibungkus perangkat keras adalah kunci penyimpanan yang hanya diketahui dalam bentuk mentah ke perangkat keras khusus; perangkat lunak hanya melihat dan bekerja dengan kunci-kunci ini dalam bentuk terbungkus (terenkripsi). Perangkat keras ini harus mampu menghasilkan dan mengimpor kunci penyimpanan, membungkus kunci penyimpanan dalam bentuk sementara dan jangka panjang, memperoleh subkunci, memprogram satu subkunci secara langsung ke dalam mesin kripto inline, dan mengembalikan subkunci terpisah ke perangkat lunak.

Catatan : Mesin kripto inline (atau perangkat keras enkripsi inline ) mengacu pada perangkat keras yang mengenkripsi/mendekripsi data saat 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 dibungkus perangkat keras, termasuk dukungan perangkat keras apa yang diperlukan untuk itu. Diskusi ini berfokus pada enkripsi berbasis file (FBE), namun solusinya juga berlaku untuk enkripsi metadata .

Salah satu cara untuk menghindari kebutuhan kunci enkripsi mentah dalam memori sistem adalah dengan menyimpannya hanya di slot kunci mesin kripto inline. Namun, pendekatan ini menghadapi beberapa masalah:

  • Jumlah kunci enkripsi mungkin melebihi jumlah slot kunci.
  • Mesin kripto inline hanya dapat digunakan untuk mengenkripsi/mendekripsi seluruh blok data pada disk. Namun, dalam kasus FBE, perangkat lunak masih harus mampu melakukan pekerjaan kriptografi lainnya seperti enkripsi nama file dan mendapatkan pengidentifikasi kunci. Perangkat lunak masih memerlukan akses ke kunci FBE mentah untuk melakukan pekerjaan lain ini.

Untuk menghindari masalah ini, kunci penyimpanan dibuat menjadi kunci yang dibungkus perangkat keras , yang hanya dapat dibuka dan digunakan oleh perangkat keras khusus. Hal ini memungkinkan jumlah kunci yang tidak terbatas untuk didukung. Selain itu, hierarki kunci diubah dan sebagian dipindahkan ke perangkat keras ini, yang memungkinkan subkunci dikembalikan ke perangkat lunak untuk tugas-tugas yang tidak dapat menggunakan mesin kripto inline.

Hierarki kunci

Kunci dapat diturunkan dari kunci lain menggunakan KDF (fungsi derivasi kunci) seperti HKDF , sehingga menghasilkan hierarki kunci .

Diagram berikut menggambarkan hierarki kunci khas untuk FBE ketika kunci yang terbungkus perangkat keras tidak digunakan:

Hierarki kunci FBE (standar)
Gambar 1. Hierarki kunci FBE (standar)

Kunci kelas FBE adalah kunci enkripsi mentah yang diteruskan Android ke kernel Linux untuk membuka kunci sekumpulan direktori terenkripsi tertentu, seperti penyimpanan terenkripsi kredensial untuk pengguna Android tertentu. (Dalam kernel, kunci ini disebut kunci master fscrypt .) Dari kunci ini, kernel memperoleh subkunci berikut:

  • Pengidentifikasi kunci. Ini tidak digunakan untuk enkripsi, melainkan nilai yang digunakan untuk mengidentifikasi kunci yang melindungi file atau direktori tertentu.
  • Kunci enkripsi isi file
  • Kunci enkripsi nama file

Sebaliknya, diagram berikut menggambarkan hierarki kunci untuk FBE ketika kunci yang terbungkus perangkat keras digunakan:

Hierarki kunci FBE (dengan kunci yang dibungkus perangkat keras)
Gambar 2. Hierarki kunci FBE (dengan kunci yang dibungkus perangkat keras)

Dibandingkan dengan kasus sebelumnya, tingkat tambahan telah ditambahkan ke hierarki kunci, dan kunci enkripsi konten file telah dipindahkan. Node root masih mewakili kunci yang diteruskan Android ke Linux untuk membuka kunci sekumpulan direktori terenkripsi. Namun, sekarang kunci tersebut berada dalam bentuk yang terbungkus secara sementara, dan agar dapat digunakan, kunci tersebut harus diteruskan ke perangkat keras khusus. Perangkat keras ini harus mengimplementasikan dua antarmuka yang menggunakan kunci yang dibungkus secara sementara:

  • Satu antarmuka untuk mendapatkan inline_encryption_key dan langsung memprogramnya ke dalam slot kunci mesin kripto inline. Hal ini memungkinkan konten file dienkripsi/didekripsi tanpa perangkat lunak memiliki akses ke kunci mentah. Di kernel umum Android, antarmuka ini sesuai dengan operasi blk_crypto_ll_ops::keyslot_program , yang harus diimplementasikan oleh driver penyimpanan.
  • Satu antarmuka untuk mendapatkan dan mengembalikan sw_secret ("rahasia perangkat lunak" -- juga disebut "rahasia mentah" di beberapa tempat), yang merupakan kunci yang digunakan Linux untuk mendapatkan subkunci untuk segala hal selain enkripsi konten file. Di kernel umum Android, antarmuka ini sesuai dengan operasi blk_crypto_ll_ops::derive_sw_secret , yang harus diimplementasikan oleh driver penyimpanan.

Untuk mendapatkan inline_encryption_key dan sw_secret dari kunci penyimpanan mentah, perangkat keras harus menggunakan KDF yang kuat secara kriptografis. KDF ini harus mengikuti praktik terbaik kriptografi; ia harus memiliki kekuatan keamanan minimal 256 bit, yaitu cukup untuk algoritma apa pun yang digunakan nanti. Ia juga harus menggunakan label, konteks, dan/atau string informasi khusus aplikasi yang berbeda ketika memperoleh setiap jenis subkunci untuk menjamin bahwa subkunci yang dihasilkan diisolasi secara kriptografis, yaitu pengetahuan tentang salah satu dari subkunci tersebut tidak mengungkapkan subkunci lainnya. Peregangan kunci tidak diperlukan, karena kunci penyimpanan mentah sudah merupakan kunci acak yang seragam.

Secara teknis, KDF apa pun yang memenuhi persyaratan keamanan dapat digunakan. Namun, untuk tujuan pengujian, KDF yang sama perlu diimplementasikan kembali dalam kode pengujian. Saat ini, satu KDF telah ditinjau dan diterapkan; itu dapat ditemukan di kode sumber untuk vts_kernel_encryption_test . Disarankan untuk hardware menggunakan KDF ini, yang menggunakan NIST SP 800-108 "KDF in Counter Mode" dengan AES-256-CMAC sebagai PRFnya. Perhatikan bahwa agar kompatibel, semua bagian algoritma harus identik, termasuk pilihan konteks dan label KDF untuk setiap subkunci.

Pembungkus kunci

Untuk memenuhi tujuan keamanan kunci yang dibungkus perangkat keras, dua jenis pembungkus kunci didefinisikan:

  • Pembungkusan sementara : perangkat keras mengenkripsi kunci mentah menggunakan kunci yang dihasilkan secara acak pada setiap boot dan tidak secara langsung diekspos di luar perangkat keras.
  • Pembungkusan jangka panjang : perangkat keras mengenkripsi kunci mentah menggunakan kunci unik dan persisten yang terpasang di perangkat keras yang tidak terekspos secara langsung di luar perangkat keras.

Semua kunci yang diteruskan ke kernel Linux untuk membuka kunci penyimpanan dibungkus secara sementara. Hal ini memastikan bahwa jika penyerang dapat mengekstrak kunci yang sedang digunakan dari memori sistem, maka kunci tersebut tidak hanya tidak dapat digunakan di luar perangkat, tetapi juga di perangkat setelah reboot.

Pada saat yang sama, Android masih harus dapat menyimpan versi kunci yang terenkripsi pada 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 kunci tersebut tidak dapat diekstraksi untuk digunakan di luar perangkat, bahkan jika diekstraksi saat boot. Oleh karena itu, konsep pembungkusan jangka panjang didefinisikan.

Untuk mendukung pengelolaan kunci yang digabungkan dengan dua cara berbeda ini, perangkat keras harus mengimplementasikan antarmuka berikut:

  • Antarmuka untuk menghasilkan dan mengimpor kunci penyimpanan, mengembalikannya dalam bentuk terbungkus jangka panjang. Antarmuka ini diakses secara tidak langsung melalui KeyMint, dan sesuai dengan tag TAG_STORAGE_KEY KeyMint. Kemampuan "menghasilkan" digunakan oleh vold untuk menghasilkan kunci penyimpanan baru untuk digunakan oleh Android, sedangkan kemampuan "impor" digunakan oleh vts_kernel_encryption_test untuk mengimpor kunci pengujian.
  • Antarmuka untuk mengonversi kunci penyimpanan terbungkus jangka panjang menjadi kunci penyimpanan terbungkus sementara. Ini sesuai dengan metode convertStorageKeyToEphemeral KeyMint. Metode ini digunakan oleh vold dan vts_kernel_encryption_test untuk membuka kunci penyimpanan.

Algoritme pembungkusan kunci merupakan detail implementasi, namun harus menggunakan AEAD yang kuat seperti AES-256-GCM dengan IV acak.

Diperlukan perubahan perangkat lunak

AOSP sudah memiliki kerangka dasar untuk mendukung kunci yang dibungkus perangkat keras. Ini termasuk dukungan pada komponen userspace seperti vold , serta dukungan kernel Linux pada blk-crypto , fscrypt dan dm-default-key .

Namun, diperlukan beberapa perubahan spesifik implementasi.

Perubahan KeyMint

Implementasi KeyMint perangkat harus dimodifikasi untuk mendukung TAG_STORAGE_KEY dan mengimplementasikan metode convertStorageKeyToEphemeral .

Di Keymaster, exportKey digunakan sebagai pengganti convertStorageKeyToEphemeral .

Perubahan kernel Linux

Driver kernel Linux untuk mesin kripto inline perangkat harus dimodifikasi untuk mendukung kunci yang terbungkus perangkat keras.

Untuk kernel android14 dan yang lebih tinggi, setel 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/mengusir kunci yang dibungkus perangkat keras, dan mengimplementasikan 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/mengusir kunci yang dibungkus perangkat keras, dan mengimplementasikan blk_ksm_ll_ops::derive_raw_secret .

Untuk kernel android11 , setel 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 terbungkus perangkat keras, dan implementasikan keyslot_mgmt_ll_ops::derive_raw_secret .

Pengujian

Meskipun enkripsi dengan kunci yang dibungkus perangkat keras lebih sulit untuk diuji daripada enkripsi dengan kunci standar, pengujian masih dapat dilakukan dengan mengimpor kunci pengujian dan menerapkan kembali turunan kunci yang dilakukan perangkat keras. Ini diterapkan di vts_kernel_encryption_test . Untuk menjalankan tes ini, jalankan:

atest -v vts_kernel_encryption_test

Baca log pengujian dan verifikasi bahwa kasus pengujian kunci yang dibungkus perangkat keras (misalnya FBEPolicyTest.TestAesInlineCryptOptimizedHwWrappedKeyPolicy dan DmDefaultKeyTest.TestHwWrappedKey ) tidak dilewati karena dukungan untuk kunci yang dibungkus perangkat keras tidak terdeteksi, karena hasil pengujian akan tetap "lulus" di kasus itu.

Mengaktifkan

Setelah dukungan kunci terbungkus perangkat keras perangkat berfungsi dengan benar, Anda dapat membuat perubahan berikut pada file fstab perangkat agar Android menggunakannya untuk enkripsi FBE dan metadata:

  • FBE: tambahkan flag wrappedkey_v0 ke parameter fileencryption . Misalnya, gunakan fileencryption=::inlinecrypt_optimized+wrappedkey_v0 . Untuk lebih jelasnya, lihat dokumentasi FBE .
  • Enkripsi metadata: tambahkan tanda wrappedkey_v0 ke parameter metadata_encryption . Misalnya, gunakan metadata_encryption=:wrappedkey_v0 . Untuk detail selengkapnya, lihat dokumentasi enkripsi metadata .