Kunci Gabungan Perangkat Keras

Seperti kebanyakan perangkat lunak enkripsi {i>disk<i} dan file, enkripsi penyimpanan Android mengandalkan kunci enkripsi mentah yang ada dalam memori sistem, sehingga enkripsi dapat dilakukan. Bahkan ketika enkripsi dilakukan perangkat keras khusus daripada perangkat lunak, perangkat lunak umumnya masih perlu mengelola kunci enkripsi mentah.

Hal ini secara tradisional tidak dianggap sebagai masalah karena kunci tidak akan ada selama serangan {i>offline<i}, yang merupakan jenis serangan utama yang membuat enkripsi yang dimaksudkan untuk melindunginya. Namun, ada keinginan untuk menyediakan peningkatan perlindungan terhadap jenis serangan lainnya, seperti cold boot serangan online, dan serangan online yang memungkinkan penyerang membocorkan tanpa memengaruhi perangkat secara penuh.

Untuk mengatasi masalah ini, Android 11 memperkenalkan dukungan untuk tombol yang digabungkan dengan hardware, yang menyediakan dukungan hardware. Kunci yang dibungkus {i>hardware<i} adalah kunci penyimpanan yang hanya dikenal dalam bentuk mentah untuk perangkat keras khusus; perangkat lunak hanya melihat dan bekerja dengan kunci-kunci ini yang digabungkan (dienkripsi). Perangkat keras ini harus mampu menghasilkan dan mengimpor kunci penyimpanan, menggabungkan kunci penyimpanan dalam bentuk sementara dan jangka panjang, berasal dari sub kunci, secara langsung memprogram satu subkunci ke dalam mesin kripto {i>inline<i}, dan yang mengembalikan sub-kunci terpisah ke perangkat lunak.

Catatan: Mesin kripto inline (atau inline hardware enkripsi) mengacu pada hardware yang mengenkripsi/mendekripsi data sambil sedang dalam perjalanan ke/dari perangkat penyimpanan. Biasanya ini adalah host UFS atau eMMC yang menerapkan ekstensi kripto{i> <i}yang didefinisikan oleh Spesifikasi JEDEC.

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), tetapi Solusi ini berlaku untuk metadata enkripsi juga.

Salah satu cara untuk menghindari kebutuhan kunci enkripsi dalam memori sistem adalah dengan menyimpannya hanya di slot kunci sebuah mesin kripto {i>inline<i}. Namun, pendekatan tersebut mengalami beberapa masalah:

  • Jumlah kunci enkripsi dapat melebihi jumlah slot kunci.
  • Mesin kripto{i> inline<i} hanya dapat digunakan untuk mengenkripsi/mendekripsi blok penuh data dalam {i>disk<i}. Namun, dalam kasus FBE, perangkat lunak masih harus dapat melakukan pekerjaan kriptografi lainnya seperti enkripsi nama file dan mendapatkan kunci pengenal. Perangkat lunak masih membutuhkan akses ke kunci FBE mentah untuk melakukan pekerjaan lain ini.

Untuk menghindari masalah ini, kunci penyimpanan dibuat menjadi tombol yang digabungkan dengan hardware, yang hanya dapat dibuka dan digunakan oleh perangkat keras khusus. Dengan begitu, jumlah kunci yang didukung tidak terbatas. Di beberapa selain itu, hierarki kunci dimodifikasi dan sebagian dipindahkan ke perangkat keras ini, yang memungkinkan sub-kunci dikembalikan ke perangkat lunak untuk tugas-tugas yang tidak dapat menggunakan mesin kripto inline.

Hierarki kunci

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

Diagram berikut menggambarkan hierarki kunci yang umum untuk FBE ketika kunci yang digabungkan dengan hardware tidak digunakan:

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

Kunci class FBE adalah kunci enkripsi mentah yang diteruskan Android ke Linux {i>kernel<i} untuk membuka kunci kumpulan direktori terenkripsi tertentu, seperti penyimpanan yang dienkripsi dengan kredensial untuk pengguna Android tertentu. (Pada {i>kernel<i}, kunci tersebut disebut kunci master fscrypt.) Dari kunci ini, {i>kernel<i} memperoleh sub-kunci berikut:

  • ID kunci. Ini tidak digunakan untuk enkripsi, namun merupakan nilai digunakan untuk mengidentifikasi kunci yang digunakan untuk file atau direktori tertentu terlindungi.
  • Kunci enkripsi isi file
  • Kunci enkripsi nama file

Sebaliknya, diagram berikut menggambarkan hierarki kunci untuk FBE ketika kunci yang digabungkan secara hardware:

Hierarki kunci FBE (dengan kunci yang digabungkan dengan hardware)
Gambar 2. Hierarki kunci FBE (dengan kunci yang digabungkan dengan hardware)

Dibandingkan dengan kasus sebelumnya, level tambahan telah ditambahkan ke kunci hierarki, dan kunci enkripsi konten file telah dipindahkan. Akar masih mewakili kunci yang akan diteruskan Android ke Linux untuk membuka serangkaian direktori terenkripsi. Namun, sekarang kunci itu ada dalam bentuk yang singkat, dan agar dapat digunakan harus diteruskan ke perangkat keras khusus. Perangkat keras ini harus menerapkan dua antarmuka yang mengambil kunci yang digabungkan secara efemeral:

  • Satu antarmuka untuk mendapatkan inline_encryption_key dan secara langsung memprogramnya ke dalam slot kunci dari mesin kripto {i>inline<i}. Hal ini memungkinkan file untuk dienkripsi/didekripsi tanpa perangkat lunak memiliki akses ke tombol. Dalam {i>kernel<i} umum Android, antarmuka ini berhubungan dengan blk_crypto_ll_ops::keyslot_program, yang harus yang diterapkan oleh {i>driver<i} penyimpanan.
  • Satu antarmuka untuk mendapatkan dan menampilkan sw_secret ("software rahasia" -- juga disebut "rahasia mentah" di beberapa tempat), yang merupakan kunci yang Linux digunakan untuk memperoleh sub-kunci untuk segala hal selain isi file enkripsi. Dalam {i>kernel<i} umum Android, antarmuka ini berhubungan dengan blk_crypto_ll_ops::derive_sw_secret, yang harus yang diterapkan oleh {i>driver<i} penyimpanan.

Untuk mendapatkan inline_encryption_key dan sw_secret dari kunci penyimpanan mentah, perangkat keras harus menggunakan KDF yang kuat secara kriptografi. KDF ini harus mengikuti praktik terbaik kriptografi; kunci itu harus memiliki kekuatan keamanan sebesar minimal 256 bit, artinya cukup untuk algoritma apa pun yang digunakan nanti. Aplikasi juga harus menggunakan label, konteks, dan/atau string informasi spesifik per aplikasi yang berbeda saat mendapatkan setiap jenis sub-kunci untuk menjamin bahwa sub-kunci yang dihasilkan terisolasi secara kriptografis, yaitu pengetahuan tentang salah satunya tidak mengungkapkan lainnya. Pelebaran kunci tidak diperlukan, karena kunci penyimpanan mentah sudah menggunakan kunci acak yang sama.

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

Penggabungan tombol (key wrapping)

Untuk memenuhi sasaran keamanan kunci yang dibungkus hardware, ada dua jenis didefinisikan:

  • Penggabungan ephemeral: hardware mengenkripsi kunci mentah menggunakan kunci yang dihasilkan secara acak pada setiap {i>booting<i} dan tidak secara langsung diekspos di luar perangkat keras.
  • Penggabungan jangka panjang: hardware mengenkripsi kunci mentah menggunakan kunci unik dan persisten yang terdapat ke dalam perangkat keras yang tidak secara langsung terbuka di luar perangkat keras.

Semua kunci yang diteruskan ke {i>kernel<i} Linux untuk membuka penyimpanan ditampilkan secara singkat. Hal ini memastikan bahwa jika penyerang dapat mengekstrak sebuah yang sedang digunakan dari memori sistem, maka kunci itu tidak akan bisa digunakan, hanya dari perangkat, tetapi juga di perangkat setelah memulai ulang komputer.

Pada saat yang sama, Android masih harus bisa menyimpan versi terenkripsi dari kunci pada {i>disk <i}sehingga mereka dapat dibuka kuncinya. Data mentah {i>key<i} akan berfungsi untuk tujuan ini. Namun, sebaiknya jangan pernah menggunakan kunci ada dalam memori sistem sehingga tidak akan bisa diekstrak untuk digunakan di luar perangkat, bahkan jika diekstrak pada saat {i>booting<i}. Karena alasan ini, konsep {i>long-term wrapping <i}ditentukan.

Untuk mendukung pengelolaan kunci yang digabungkan dengan dua cara berbeda ini, hardware harus implementasikan antarmuka berikut:

  • Antarmuka untuk membuat dan mengimpor kunci penyimpanan, yang mengembalikannya ke yang digabungkan dalam jangka panjang. Antarmuka ini diakses secara tidak langsung melalui KeyMint, dan sesuai dengan tag KeyMint TAG_STORAGE_KEY. Fungsi "generate" kemampuan digunakan oleh vold untuk membuat penyimpanan baru kunci untuk digunakan oleh Android, sedangkan "impor" kemampuan digunakan oleh vts_kernel_encryption_test untuk mengimpor kunci pengujian.
  • Antarmuka untuk mengonversi kunci penyimpanan gabungan jangka panjang menjadi kunci penyimpanan yang dibungkus secara efemeral. Hal ini sesuai dengan Metode KeyMint convertStorageKeyToEphemeral. Metode ini digunakan oleh vold dan vts_kernel_encryption_test secara berurutan untuk membuka penyimpanan.

Algoritma {i>key wrapping<i} adalah detail implementasi, tetapi harus menggunakan AEAD yang kuat seperti AES-256-GCM dengan IV acak.

Diperlukan perubahan software

AOSP sudah memiliki framework dasar untuk mendukung kunci yang digabungkan dengan hardware. Ini menyertakan dukungan dalam komponen userspace seperti vold, serta sebagai dukungan kernel Linux pada blk-crypto, fscrypt, dan kunci-default-dm.

Namun, beberapa perubahan khusus penerapan diperlukan.

Perubahan KeyMint

Implementasi KeyMint perangkat harus dimodifikasi untuk mendukung TAG_STORAGE_KEY dan terapkan metode 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 digabungkan dengan hardware.

Untuk android14 dan kernel 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/mengeluarkan kunci yang dibungkus perangkat keras, dan menerapkan blk_crypto_ll_ops::derive_sw_secret.

Untuk kernel android12 dan android13, tetapkan BLK_CRYPTO_FEATURE_WRAPPED_KEYS dalam blk_keyslot_manager::features, buat blk_ksm_ll_ops::keyslot_program dan blk_ksm_ll_ops::keyslot_evict mendukung pemrograman/mengeluarkan kunci yang dibungkus perangkat keras, dan menerapkan blk_ksm_ll_ops::derive_raw_secret.

Untuk kernel android11, tetapkan BLK_CRYPTO_FEATURE_WRAPPED_KEYS di keyslot_manager::features, membuat keyslot_mgmt_ll_ops::keyslot_program dan keyslot_mgmt_ll_ops::keyslot_evict mendukung pemrograman/mengeluarkan kunci yang dibungkus perangkat keras, dan menerapkan keyslot_mgmt_ll_ops::derive_raw_secret.

Pengujian

Meskipun enkripsi dengan kunci yang digabungkan dengan hardware lebih sulit untuk diuji daripada enkripsi dengan kunci standar, masih mungkin untuk menguji dengan mengimpor kunci pengujian dan menerapkan kembali turunan kunci yang dilakukan oleh perangkat keras. Hal ini diterapkan di vts_kernel_encryption_test. Untuk menjalankan pengujian ini, jalankan:

atest -v vts_kernel_encryption_test

Membaca log pengujian dan memverifikasi bahwa kasus pengujian utama yang digabungkan dengan hardware (mis. FBEPolicyTest.TestAesInlineCryptOptimizedHwWrappedKeyPolicy dan DmDefaultKeyTest.TestHwWrappedKey) tidak dilewati karena dukungan untuk kunci yang digabungkan dengan hardware tidak terdeteksi, karena hasil pengujian akan tetap "lulus" dalam kasus tersebut.

Mengaktifkan

Setelah dukungan kunci yang digabungkan perangkat keras pada perangkat bekerja dengan benar, Anda dapat buat perubahan berikut pada file fstab perangkat untuk membuat Android menggunakannya untuk FBE dan enkripsi metadata:

  • FBE: tambahkan flag wrappedkey_v0 ke Parameter fileencryption. Misalnya, gunakan fileencryption=::inlinecrypt_optimized+wrappedkey_v0. Sebagai detail selengkapnya, lihat FBE dokumentasi tambahan.
  • Enkripsi metadata: tambahkan flag wrappedkey_v0 ke Parameter metadata_encryption. Misalnya, gunakan metadata_encryption=:wrappedkey_v0. Untuk mengetahui detail selengkapnya, lihat metadata dokumentasi enkripsi.