Kunci Terbungkus Perangkat Keras

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

Ini secara tradisional tidak dilihat sebagai masalah karena kunci tidak akan ada selama serangan offline, yang merupakan jenis serangan utama yang dimaksudkan untuk dilindungi oleh enkripsi penyimpanan. Namun, ada keinginan untuk memberikan peningkatan perlindungan terhadap jenis serangan lain, seperti serangan boot dingin , dan serangan online di mana penyerang mungkin dapat membocorkan memori sistem tanpa sepenuhnya membahayakan perangkat.

Untuk mengatasi masalah ini, Android 11 memperkenalkan dukungan untuk kunci yang dibungkus perangkat keras , di mana ada dukungan perangkat keras. Kunci yang dibungkus perangkat keras adalah kunci penyimpanan yang hanya dikenal dalam bentuk mentah untuk 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, menurunkan subkunci, secara langsung memprogram satu subkunci ke dalam mesin kripto sebaris, dan mengembalikan subkunci terpisah ke perangkat lunak.

Catatan : Mesin kripto sebaris (atau perangkat keras enkripsi sebaris ) 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.

Rancangan

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 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 sebaris. Namun, pendekatan ini mengalami beberapa masalah:

  • Jumlah kunci enkripsi dapat melebihi jumlah slot kunci.
  • Mesin kripto sebaris hanya dapat digunakan untuk mengenkripsi/mendekripsi blok penuh data pada disk. Namun, dalam kasus FBE, perangkat lunak masih harus dapat melakukan pekerjaan kriptografi lainnya seperti enkripsi nama file dan penurunan 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. Ini memungkinkan jumlah kunci yang tidak terbatas untuk didukung. Selain itu, hierarki kunci dimodifikasi dan sebagian dipindahkan ke perangkat keras ini, yang memungkinkan subkunci dikembalikan ke perangkat lunak untuk tugas yang tidak dapat menggunakan mesin kripto sebaris.

Hirarki kunci

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

Diagram berikut menggambarkan hierarki kunci tipikal untuk FBE saat kunci yang dibungkus perangkat keras tidak digunakan:

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

Kunci kelas FBE adalah kunci enkripsi mentah yang diteruskan Android ke kernel Linux untuk membuka kunci kumpulan 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, tetapi lebih merupakan nilai yang digunakan untuk mengidentifikasi kunci yang dengannya file atau direktori tertentu dilindungi.
  • Kunci enkripsi isi file
  • Kunci enkripsi nama file

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

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

Dibandingkan dengan kasus sebelumnya, level 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 itu dalam bentuk terbungkus sementara, dan agar dapat digunakan, kunci itu harus diteruskan ke perangkat keras khusus. Perangkat keras ini harus mengimplementasikan dua antarmuka yang menggunakan kunci yang dibungkus secara singkat:

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

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

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

Pembungkus kunci

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

  • Pembungkus ephemeral : perangkat keras mengenkripsi kunci mentah menggunakan kunci yang dibuat 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 dibangun ke dalam perangkat keras yang tidak secara langsung terpapar di luar perangkat keras.

Semua kunci yang diteruskan ke kernel Linux untuk membuka kunci penyimpanan dibungkus secara singkat. Ini memastikan bahwa jika penyerang dapat mengekstrak kunci yang sedang digunakan dari memori sistem, maka kunci itu tidak akan dapat digunakan tidak hanya di luar perangkat, tetapi juga di dalam perangkat setelah reboot.

Pada saat yang sama, Android masih harus dapat menyimpan versi kunci yang dienkripsi pada disk agar dapat dibuka kuncinya terlebih dahulu. Kunci mentah akan berfungsi untuk tujuan ini. Namun, sangat diharapkan untuk tidak pernah memiliki kunci mentah dalam memori sistem sama sekali sehingga kunci tersebut tidak pernah dapat diekstraksi untuk digunakan di luar perangkat, bahkan jika diekstraksi pada saat boot. Untuk alasan ini, konsep pembungkusan jangka panjang didefinisikan.

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

  • Antarmuka untuk membuat 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 "mengimpor" digunakan oleh vts_kernel_encryption_test untuk mengimpor kunci pengujian.
  • Antarmuka untuk mengubah kunci penyimpanan yang dibungkus jangka panjang menjadi kunci penyimpanan yang dibungkus secara singkat. Ini sesuai dengan metode convertStorageKeyToEphemeral KeyMint. Metode ini digunakan oleh vold dan vts_kernel_encryption_test untuk membuka kunci penyimpanan.

Algoritme pembungkusan kunci adalah detail implementasi, tetapi harus menggunakan AEAD yang kuat seperti AES-256-GCM dengan infus acak.

Perubahan perangkat lunak diperlukan

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

Namun, beberapa perubahan khusus implementasi diperlukan.

Perubahan KeyMint

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

Di Keymaster, exportKey digunakan sebagai ganti convertStorageKeyToEphemeral .

Perubahan kernel Linux

Driver kernel Linux untuk mesin kripto sebaris perangkat harus dimodifikasi untuk menyetel BLK_CRYPTO_FEATURE_WRAPPED_KEYS , membuat operasi keyslot_program() dan keyslot_evict() mendukung pemrograman/mengusir kunci yang dibungkus perangkat keras, dan mengimplementasikan operasi derive_raw_secret() .

Pengujian

Meskipun enkripsi dengan kunci yang dibungkus perangkat keras lebih sulit untuk diuji daripada enkripsi dengan kunci standar, masih mungkin untuk menguji dengan mengimpor kunci uji dan mengimplementasikan kembali derivasi kunci yang dilakukan perangkat keras. Ini diimplementasikan 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 "dilewati" di kasus itu.

Mengaktifkan

Setelah dukungan kunci terbungkus perangkat keras berfungsi dengan benar, Anda dapat membuat 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 . 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 .