Wie bei den meisten Festplatten- und Dateiverschlüsselungssoftware wird bei der Speicherverschlüsselung von Android traditionell davon ausgegangen, dass die Rohverschlüsselungsschlüssel im Systemspeicher vorhanden sind, damit die Verschlüsselung durchgeführt werden kann. Auch wenn die Verschlüsselung von dedizierter Hardware und nicht von Software durchgeführt wird, muss die Software in der Regel die Rohverschlüsselungsschlüssel verwalten.
Das wird normalerweise nicht als Problem angesehen, da die Schlüssel bei einem Offlineangriff nicht vorhanden sind. Das ist die Hauptart von Angriff, vor der die Speicherverschlüsselung schützen soll. Es besteht jedoch der Wunsch, den Schutz vor anderen Arten von Angriffen zu erhöhen, z. B. vor Cold-Boot-Angriffen und Onlineangriffen, bei denen ein Angreifer möglicherweise den Systemspeicher auslesen kann, ohne das Gerät vollständig zu kompromittieren.
Um dieses Problem zu beheben, wurde in Android 11 die Unterstützung für hardware-wrapped keys eingeführt, sofern Hardwareunterstützung vorhanden ist. Hardware-Wrapped Keys sind Speicherschlüssel, die nur der dedizierten Hardware im Rohformat bekannt sind. Software sieht und verwendet diese Schlüssel nur in verschlüsselter Form. Diese Hardware muss in der Lage sein, Speicherschlüssel zu generieren und zu importieren, Speicherschlüssel in kurzlebige und langfristige Formen zu verpacken, Unterschlüssel abzuleiten, einen Unterschlüssel direkt in eine Inline-Crypto-Engine zu programmieren und einen separaten Unterschlüssel an die Software zurückzugeben.
Hinweis:Eine Inline-Crypto-Engine (oder Inline-Verschlüsselungshardware) bezieht sich auf Hardware, die Daten verschlüsselt/entschlüsselt, während sie sich auf dem Weg zum/vom Speichergerät befinden. In der Regel handelt es sich dabei um einen UFS- oder eMMC-Hostcontroller, der die in der entsprechenden JEDEC-Spezifikation definierten Krypto-Erweiterungen implementiert.
Design
In diesem Abschnitt wird das Design der Funktion für hardwaregebundene Schlüssel beschrieben, einschließlich der erforderlichen Hardwareunterstützung. In diesem Dokument geht es hauptsächlich um die dateibasierte Verschlüsselung (File-Based Encryption, FBE). Die Lösung gilt aber auch für die Metadatenverschlüsselung.
Eine Möglichkeit, die Rohverschlüsselungsschlüssel nicht im Systemspeicher zu benötigen, besteht darin, sie nur in den Schlüssel-Slots einer Inline-Verschlüsselungs-Engine zu speichern. Dieser Ansatz hat jedoch einige Probleme:
- Die Anzahl der Verschlüsselungsschlüssel kann die Anzahl der Schlüssel-Slots überschreiten.
- Bei Inline-Crypto-Engines gehen die Inhalte der Schlüssel-Slots in der Regel verloren, wenn der Speicher-Hostcontroller zurückgesetzt wird. Das Zurücksetzen des Speicherhostcontrollers ist ein Standardverfahren zur Fehlerbehebung, das ausgeführt wird, wenn bestimmte Arten von Speicherfehlern auftreten. Solche Fehler können jederzeit auftreten. Wenn Inline-Krypto verwendet wird, muss das Betriebssystem daher immer bereit sein, die Schlüssel-Slots ohne Nutzereingriff neu zu programmieren.
- Inline-Krypto-Engines können nur zum Verschlüsseln/Entschlüsseln vollständiger Datenblöcke auf der Festplatte verwendet werden. Bei der dateibasierten Verschlüsselung muss die Software jedoch weiterhin andere kryptografische Aufgaben ausführen können, z. B. die Verschlüsselung von Dateinamen und das Ableiten von Schlüsselkennungen. Die Software benötigt weiterhin Zugriff auf die Rohschlüssel für die dateibasierte Verschlüsselung, um andere Aufgaben auszuführen.
Um diese Probleme zu vermeiden, werden die Speicherschlüssel stattdessen in Hardware-Wrapped Keys umgewandelt, die nur von dedizierter Hardware entpackt und verwendet werden können. So kann eine unbegrenzte Anzahl von Schlüsseln unterstützt werden. Außerdem wird die Schlüsselhierarchie geändert und teilweise auf diese Hardware verschoben. Dadurch kann ein Unterschlüssel an die Software zurückgegeben werden, wenn für Aufgaben keine Inline-Crypto-Engine verwendet werden kann.
Schlüsselhierarchie
Schlüssel können mit einer Schlüsselableitungsfunktion (Key Derivation Function, KDF) wie HKDF aus anderen Schlüsseln abgeleitet werden, was zu einer Schlüsselhierarchie führt.
Das folgende Diagramm zeigt eine typische Schlüsselhierarchie für FBE, wenn keine hardwaregebundenen Schlüssel verwendet werden:
Der FBE-Klassenschlüssel ist der Rohverschlüsselungsschlüssel, den Android an den Linux-Kernel übergibt, um eine bestimmte Gruppe verschlüsselter Verzeichnisse zu entsperren, z. B. den mit Anmeldedaten verschlüsselten Speicher für einen bestimmten Android-Nutzer. Im Kernel wird dieser Schlüssel als fscrypt-Masterschlüssel bezeichnet. Aus diesem Schlüssel leitet der Kernel die folgenden Unterschlüssel ab:
- Die Schlüsselkennung. Dieser Wert wird nicht für die Verschlüsselung verwendet, sondern dient dazu, den Schlüssel zu identifizieren, mit dem eine bestimmte Datei oder ein bestimmtes Verzeichnis geschützt ist.
- Der Verschlüsselungsschlüssel für den Dateiinhalt
- Der Verschlüsselungsschlüssel für Dateinamen
Das folgende Diagramm zeigt die Schlüsselhierarchie für FBE, wenn hardwaregebundene Schlüssel verwendet werden:
Im Vergleich zum vorherigen Fall wurde der Schlüsselhierarchie eine zusätzliche Ebene hinzugefügt und der Verschlüsselungsschlüssel für Dateiinhalte wurde verschoben. Der Stammknoten stellt weiterhin den Schlüssel dar, den Android an Linux übergibt, um eine Reihe verschlüsselter Verzeichnisse zu entsperren. Dieser Schlüssel ist jetzt jedoch in ephemerally-wrapped-Form und muss an spezielle Hardware übergeben werden, um verwendet werden zu können. Diese Hardware muss zwei Schnittstellen implementieren, die einen kurzlebig verpackten Schlüssel akzeptieren:
- Eine Schnittstelle zum Ableiten von
inline_encryption_key
und zum direkten Programmieren in einen Schlüssel-Slot der Inline-Krypto-Engine. So können Dateiinhalte verschlüsselt/entschlüsselt werden, ohne dass Software Zugriff auf den Rohschlüssel hat. In den gemeinsamen Android-Kerneln entspricht diese Schnittstelle dem Vorgangblk_crypto_ll_ops::keyslot_program
, der vom Speichertreiber implementiert werden muss. - Eine Schnittstelle zum Ableiten und Zurückgeben von
sw_secret
(„Software-Secret“, an einigen Stellen auch „Roh-Secret“ genannt). Dies ist der Schlüssel, mit dem Linux die Unterschlüssel für alles außer der Verschlüsselung von Dateiinhalten ableitet. In den gemeinsamen Android-Kerneln entspricht diese Schnittstelle dem Vorgangblk_crypto_ll_ops::derive_sw_secret
, der vom Speichertreiber implementiert werden muss.
Um inline_encryption_key
und sw_secret
aus dem Rohspeicherschlüssel abzuleiten, muss die Hardware eine kryptografisch starke KDF verwenden. Diese KDF muss den Best Practices für die Kryptografie entsprechen und eine Sicherheitsstärke von mindestens 256 Bit haben, d. h. genug für jeden später verwendeten Algorithmus. Außerdem muss für die Ableitung jedes Subkey-Typs ein eindeutiges Label und ein eindeutiger Kontext verwendet werden, damit die resultierenden Subkeys kryptografisch isoliert sind. Das bedeutet, dass die Kenntnis eines Subkeys keine Informationen über einen anderen Subkey preisgibt. Key Stretching ist nicht erforderlich, da der Rohschlüssel für den Speicher bereits ein gleichmäßig zufälliger Schlüssel ist.
Theoretisch kann jeder KDF verwendet werden, der die Sicherheitsanforderungen erfüllt.
Zu Testzwecken implementiert vts_kernel_encryption_test
jedoch dieselbe KDF in Software, um den verschlüsselten Text auf der Festplatte zu reproduzieren und zu prüfen, ob er korrekt ist. Um das Testen zu vereinfachen und sicherzustellen, dass eine sichere und bereits überprüfte KDF verwendet wird, empfehlen wir, dass die Hardware die Standard-KDF implementiert, die im Test geprüft wird. Informationen zum Konfigurieren des Tests für Hardware, die einen anderen KDF verwendet, finden Sie unter Umschlossene Schlüssel testen.
Key-Wrapping
Um die Sicherheitsziele von Hardware-verpackten Schlüsseln zu erreichen, sind zwei Arten der Schlüsselverpackung definiert:
- Kurzlebiger Wrapper: Die Hardware verschlüsselt den Rohschlüssel mit einem Schlüssel, der bei jedem Start zufällig generiert wird und nicht direkt außerhalb der Hardware verfügbar ist.
- Langfristiges Verpacken: Die Hardware verschlüsselt den Rohschlüssel mit einem eindeutigen, persistenten Schlüssel, der in die Hardware integriert ist und nicht direkt außerhalb der Hardware verfügbar ist.
Alle Schlüssel, die an den Linux-Kernel übergeben werden, um den Speicher zu entsperren, werden ephemer verschlüsselt. So wird sichergestellt, dass ein Angreifer, der einen verwendeten Schlüssel aus dem Systemspeicher extrahieren kann, diesen Schlüssel nicht nur auf einem anderen Gerät, sondern auch auf dem Gerät nach einem Neustart nicht verwenden kann.
Gleichzeitig muss Android eine verschlüsselte Version der Schlüssel auf der Festplatte speichern können, damit sie überhaupt entsperrt werden können. Die Rohschlüssel sind für diesen Zweck geeignet. Es ist jedoch wünschenswert, dass die Rohschlüssel niemals im Systemspeicher vorhanden sind, damit sie nicht extrahiert und auf einem anderen Gerät verwendet werden können, auch wenn sie beim Start extrahiert werden. Aus diesem Grund wurde das Konzept des langfristigen Wrappings definiert.
Damit Schlüssel, die auf diese beiden unterschiedlichen Arten umschlossen sind, verwaltet werden können, muss die Hardware die folgenden Schnittstellen implementieren:
- Schnittstellen zum Generieren und Importieren von Speicherschlüsseln, die in langfristig verpackter Form zurückgegeben werden. Auf diese Schnittstellen wird indirekt über KeyMint zugegriffen. Sie entsprechen dem KeyMint-Tag
TAG_STORAGE_KEY
. Die Funktion „generate“ wird vonvold
verwendet, um neue Speicherschlüssel für Android zu generieren, während die Funktion „import“ vonvts_kernel_encryption_test
verwendet wird, um Testschlüssel zu importieren. - Eine Schnittstelle zum Konvertieren eines langfristig verpackten Speicherschlüssels in einen ephemer verpackten Speicherschlüssel. Dies entspricht der KeyMint-Methode
convertStorageKeyToEphemeral
. Diese Methode wird sowohl vonvold
als auch vonvts_kernel_encryption_test
verwendet, um den Speicher zu entsperren.
Der Algorithmus zum Umschließen von Schlüsseln ist ein Implementierungsdetail, sollte aber ein starkes AEAD wie AES-256-GCM mit zufälligen IVs verwenden.
Softwareänderungen erforderlich
AOSP bietet bereits ein grundlegendes Framework zur Unterstützung von Hardware-Wrapped-Schlüsseln. Dazu gehört die Unterstützung in Userspace-Komponenten wie vold
sowie die Unterstützung des Linux-Kernels in blk-crypto, fscrypt und dm-default-key.
Es sind jedoch einige implementierungsspezifische Änderungen erforderlich.
KeyMint-Änderungen
Die KeyMint-Implementierung des Geräts muss geändert werden, um TAG_STORAGE_KEY
zu unterstützen und die Methode convertStorageKeyToEphemeral
zu implementieren.
In Keymaster wurde exportKey
anstelle von convertStorageKeyToEphemeral
verwendet.
Änderungen am Linux-Kernel
Der Linux-Kernel-Treiber für die Inline-Crypto-Engine des Geräts muss geändert werden, um Hardware-Wrapped Keys zu unterstützen.
Für android14
- und höhere Kernel:
Setzen Sie BLK_CRYPTO_KEY_TYPE_HW_WRAPPED
in blk_crypto_profile::key_types_supported
,
erstellen Sie blk_crypto_ll_ops::keyslot_program
und blk_crypto_ll_ops::keyslot_evict
,
unterstützen Sie das Programmieren/Entfernen von hardwaregebundenen Schlüsseln und
implementieren Sie blk_crypto_ll_ops::derive_sw_secret
.
Setzen Sie für android12
- und android13
-Kernel BLK_CRYPTO_FEATURE_WRAPPED_KEYS
in blk_keyslot_manager::features
, unterstützen Sie die Programmierung/Entfernung von hardwaregebundenen Schlüsseln in blk_ksm_ll_ops::keyslot_program
und blk_ksm_ll_ops::keyslot_evict
und implementieren Sie blk_ksm_ll_ops::derive_raw_secret
.
Für android11
-Kernel: Setzen Sie BLK_CRYPTO_FEATURE_WRAPPED_KEYS
in keyslot_manager::features
, sorgen Sie dafür, dass keyslot_mgmt_ll_ops::keyslot_program
und keyslot_mgmt_ll_ops::keyslot_evict
das Programmieren/Entfernen von Hardware-verschlüsselten Schlüsseln unterstützen, und implementieren Sie keyslot_mgmt_ll_ops::derive_raw_secret
.
Verpackte Schlüssel testen
Die Verschlüsselung mit in Hardware verpackten Schlüsseln ist schwieriger zu testen als die Verschlüsselung mit Rohschlüsseln. Sie können sie jedoch testen, indem Sie einen Testschlüssel importieren und die Schlüsselableitung, die die Hardware ausführt, neu implementieren. Dies wird in vts_kernel_encryption_test
implementiert. Führen Sie Folgendes aus, um diesen Test auszuführen:
atest -v vts_kernel_encryption_test
Lesen Sie das Testprotokoll und prüfen Sie, ob die Testläufe für Hardware-Wrapped-Schlüssel (z. B. FBEPolicyTest.TestAesInlineCryptOptimizedHwWrappedKeyPolicy
und DmDefaultKeyTest.TestHwWrappedKey
) übersprungen wurden, weil keine Unterstützung für Hardware-Wrapped-Schlüssel erkannt wurde. In diesem Fall werden die Testergebnisse weiterhin als „Bestanden“ angezeigt.
Standardmäßig geht vts_kernel_encryption_test
davon aus, dass die Hardware eine KDF implementiert, die kdf1
aufruft. Diese KDF gehört zur Familie der KDFs im Zählermodus aus NIST SP 800-108 und verwendet AES-256-CMAC als Pseudozufallsfunktion. Weitere Informationen zu CMAC finden Sie in der CMAC-Spezifikation. Das KDF verwendet spezifische Kontexte und Labels, wenn jeder untergeordnete Schlüssel abgeleitet wird. Die Hardware sollte diese KDF implementieren, einschließlich der genauen Auswahl von Kontext, Label und Formatierung des festen Eingabestrings beim Ableiten jedes Unterschlüssels.
vts_kernel_encryption_test
implementiert jedoch auch zusätzliche KDFs
kdf2
über kdf4
. Sie sind genauso sicher wie kdf1
und unterscheiden sich nur in der Auswahl von Kontexten, Labels und der Formatierung des festen Eingabestrings. Sie sind nur für unterschiedliche Hardware vorgesehen.
Für Geräte, die eine andere KDF verwenden, legen Sie die Systemeigenschaft ro.crypto.hw_wrapped_keys.kdf
in PRODUCT_VENDOR_PROPERTIES
auf den Namen der KDF fest, wie er im Testquellcode definiert ist. Dadurch prüft vts_kernel_encryption_test
auf diesen KDF anstelle von kdf1
. Wenn Sie beispielsweise kdf2
auswählen möchten, verwenden Sie:
PRODUCT_VENDOR_PROPERTIES += ro.crypto.hw_wrapped_keys.kdf=kdf2
Fügen Sie für Geräte, die eine KDF verwenden, die vom Test nicht unterstützt wird, dem Test auch eine Implementierung dieser KDF hinzu und geben Sie ihr einen eindeutigen Namen.
Verpackte Schlüssel aktivieren
Wenn die Unterstützung für den hardware-wrapped-Schlüssel des Geräts ordnungsgemäß funktioniert, nehmen Sie die folgenden Änderungen an der fstab
-Datei des Geräts vor, damit Android sie für die FBE- und Metadatenverschlüsselung verwendet:
- FBE: Fügen Sie dem Parameter
fileencryption
das Flagwrappedkey_v0
hinzu. Verwenden Sie zum Beispielfileencryption=::inlinecrypt_optimized+wrappedkey_v0
. Weitere Informationen finden Sie in der FBE-Dokumentation. - Metadatenverschlüsselung: Fügen Sie dem Parameter
metadata_encryption
das Flagwrappedkey_v0
hinzu. Verwenden Sie zum Beispielmetadata_encryption=:wrappedkey_v0
. Weitere Informationen finden Sie in der Dokumentation zur Verschlüsselung von Metadaten.