Mit Hardware umwickelte Schlüssel

Wie die meisten Festplatten- und Dateiverschlüsselungsprogramme basiert die Speicherverschlüsselung von Android traditionell darauf, dass die rohen Verschlüsselungsschlüssel im Systemspeicher vorhanden sind, damit die Verschlüsselung durchgeführt werden kann. Selbst wenn die Verschlüsselung durch dedizierte Hardware und nicht durch Software durchgeführt wird, muss die Software im Allgemeinen immer noch die rohen Verschlüsselungsschlüssel verwalten.

Dies wird traditionell nicht als Problem angesehen, da die Schlüssel bei einem Offline-Angriff nicht vorhanden sind. Dies ist die Hauptangriffsart, vor der die Speicherverschlüsselung schützen soll. Es besteht jedoch der Wunsch, einen besseren Schutz gegen andere Arten von Angriffen zu bieten, wie z. B. Kaltstartangriffe und Online-Angriffe, bei denen ein Angreifer möglicherweise Systemspeicher verlieren kann, ohne das Gerät vollständig zu gefährden.

Um dieses Problem zu lösen, führte Android 11 die Unterstützung für Hardware-umhüllte Schlüssel ein, bei denen Hardware-Unterstützung vorhanden ist. Hardware-verpackte Schlüssel sind Speicherschlüssel, die nur dedizierter Hardware in Rohform bekannt sind. Die Software erkennt und verarbeitet diese Schlüssel nur in verpackter (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-Krypto-Engine zu programmieren und einen separaten Unterschlüssel an die Software zurückzugeben.

Hinweis : Eine Inline-Krypto-Engine (oder Inline-Verschlüsselungshardware ) bezieht sich auf Hardware, die Daten auf dem Weg zum/vom Speichergerät verschlüsselt/entschlüsselt. Normalerweise handelt es sich dabei um einen UFS- oder eMMC-Hostcontroller, der die in der entsprechenden JEDEC-Spezifikation definierten Kryptoerweiterungen implementiert.

Design

In diesem Abschnitt wird das Design der Funktion „Hardware-umhüllte Schlüssel“ vorgestellt, einschließlich der dafür erforderlichen Hardwareunterstützung. Diese Diskussion konzentriert sich auf die dateibasierte Verschlüsselung (FBE), aber die Lösung gilt auch für die Metadatenverschlüsselung .

Eine Möglichkeit zu vermeiden, dass die rohen Verschlüsselungsschlüssel im Systemspeicher benötigt werden, besteht darin, sie nur in den Schlüsselslots einer Inline-Krypto-Engine aufzubewahren. Allerdings stößt dieser Ansatz auf einige Probleme:

  • Die Anzahl der Verschlüsselungsschlüssel kann die Anzahl der Schlüsselslots überschreiten.
  • Inline-Krypto-Engines können nur zum Verschlüsseln/Entschlüsseln vollständiger Datenblöcke auf der Festplatte verwendet werden. Im Fall von FBE muss die Software jedoch weiterhin in der Lage sein, andere kryptografische Aufgaben wie die Verschlüsselung von Dateinamen und die Ableitung von Schlüsselkennungen auszuführen. Um diese anderen Arbeiten ausführen zu können, benötigt die Software weiterhin Zugriff auf die rohen FBE-Schlüssel.

Um diese Probleme zu vermeiden, werden die Speicherschlüssel stattdessen in Hardware-verpackte Schlüssel umgewandelt, die nur von dedizierter Hardware entpackt und verwendet werden können. Dadurch kann eine unbegrenzte Anzahl von Schlüsseln unterstützt werden. Darüber hinaus wird die Schlüsselhierarchie geändert und teilweise auf diese Hardware verschoben, was die Rückgabe eines Unterschlüssels an die Software für Aufgaben ermöglicht, die keine Inline-Krypto-Engine verwenden können.

Schlüsselhierarchie

Schlüssel können mithilfe einer KDF (Schlüsselableitungsfunktion) wie HKDF von 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 in Hardware verpackten Schlüssel verwendet werden:

FBE-Schlüsselhierarchie (Standard)
Abbildung 1. FBE-Schlüsselhierarchie (Standard)

Der FBE-Klassenschlüssel ist der rohe Verschlüsselungsschlüssel, den Android an den Linux-Kernel übergibt, um einen bestimmten Satz verschlüsselter Verzeichnisse freizuschalten, beispielsweise den mit Anmeldeinformationen verschlüsselten Speicher für einen bestimmten Android-Benutzer. (Im Kernel wird dieser Schlüssel als fscrypt-Hauptschlüssel bezeichnet.) Von diesem Schlüssel leitet der Kernel die folgenden Unterschlüssel ab:

  • Der Schlüsselbezeichner. Dies wird nicht zur Verschlüsselung verwendet, sondern ist vielmehr ein Wert zur Identifizierung des Schlüssels, 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

Im Gegensatz dazu zeigt das folgende Diagramm die Schlüsselhierarchie für FBE, wenn mit Hardware umschlossene Schlüssel verwendet werden:

FBE-Schlüsselhierarchie (mit in Hardware verpacktem Schlüssel)
Abbildung 2. FBE-Schlüsselhierarchie (mit in Hardware verpacktem Schlüssel)

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 Root-Knoten stellt immer noch den Schlüssel dar, den Android an Linux übergibt, um eine Reihe verschlüsselter Verzeichnisse freizuschalten. Allerdings liegt dieser Schlüssel nun in kurzlebiger Form vor und muss, um verwendet zu werden, an dedizierte Hardware übergeben werden. Diese Hardware muss zwei Schnittstellen implementieren, die einen kurzlebigen Schlüssel akzeptieren:

  • Eine Schnittstelle zum Ableiten inline_encryption_key und zum direkten Programmieren in einen Keyslot der Inline-Krypto-Engine. Dadurch können Dateiinhalte verschlüsselt/entschlüsselt werden, ohne dass Software Zugriff auf den Rohschlüssel hat. In den gängigen Android-Kerneln entspricht diese Schnittstelle der Operation blk_crypto_ll_ops::keyslot_program , die vom Speichertreiber implementiert werden muss.
  • Eine Schnittstelle zum Ableiten und Zurückgeben sw_secret („Software-Geheimnis“ – an manchen Stellen auch „Rohgeheimnis“ genannt), dem Schlüssel, den Linux verwendet, um die Unterschlüssel für alles andere als die Dateiinhaltsverschlüsselung abzuleiten. In den gängigen Android-Kerneln entspricht diese Schnittstelle der Operation blk_crypto_ll_ops::derive_sw_secret , die vom Speichertreiber implementiert werden muss.

Um inline_encryption_key und sw_secret aus dem Rohspeicherschlüssel abzuleiten, muss die Hardware ein kryptografisch starkes KDF verwenden. Dieses KDF muss den Best Practices der Kryptographie folgen. Es muss eine Sicherheitsstärke von mindestens 256 Bit haben, also ausreichend für jeden später verwendeten Algorithmus. Außerdem muss bei der Ableitung jedes Unterschlüsseltyps eine eindeutige Bezeichnung, ein eindeutiger Kontext und/oder eine anwendungsspezifische Informationszeichenfolge verwendet werden, um sicherzustellen, dass die resultierenden Unterschlüssel kryptografisch isoliert sind, d. h. die Kenntnis eines davon verrät keine anderen. Eine Schlüsseldehnung ist nicht erforderlich, da der Rohspeicherschlüssel bereits ein einheitlich zufälliger Schlüssel ist.

Technisch gesehen könnte jedes KDF verwendet werden, das die Sicherheitsanforderungen erfüllt. Zu Testzwecken ist es jedoch erforderlich, dasselbe KDF erneut im Testcode zu implementieren. Derzeit wurde ein KDF überprüft und implementiert; Es ist im Quellcode für vts_kernel_encryption_test zu finden. Es wird empfohlen, dass die Hardware dieses KDF verwendet, das NIST SP 800-108 „KDF im Zählermodus“ mit AES-256-CMAC als PRF verwendet. Beachten Sie, dass alle Teile des Algorithmus identisch sein müssen, um kompatibel zu sein, einschließlich der Auswahl der KDF-Kontexte und Beschriftungen für jeden Unterschlüssel.

Schlüsselverpackung

Um die Sicherheitsziele von mit Hardware umhüllten Schlüsseln zu erreichen, werden zwei Arten der Schlüsselumhüllung definiert:

  • Ephemeres Wrapping : 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 offengelegt wird.
  • Langfristige Verpackung : Die Hardware verschlüsselt den Rohschlüssel mit einem einzigartigen, dauerhaften Schlüssel, der in die Hardware integriert ist und nicht direkt außerhalb der Hardware offengelegt wird.

Alle Schlüssel, die zum Entsperren des Speichers an den Linux-Kernel übergeben werden, werden kurzlebig verpackt. Dadurch wird sichergestellt, dass, wenn ein Angreifer in der Lage ist, einen verwendeten Schlüssel aus dem Systemspeicher zu extrahieren, dieser Schlüssel nicht nur außerhalb des Geräts, sondern nach einem Neustart auch auf dem Gerät unbrauchbar ist.

Gleichzeitig muss Android weiterhin in der Lage sein, eine verschlüsselte Version der Schlüssel auf der Festplatte zu speichern, damit sie überhaupt entsperrt werden können. Die Rohschlüssel würden für diesen Zweck funktionieren. Es ist jedoch wünschenswert, dass die Rohschlüssel niemals im Systemspeicher vorhanden sind, damit sie niemals für die Verwendung außerhalb des Geräts extrahiert werden können, selbst wenn sie beim Booten extrahiert werden. Aus diesem Grund wird der Begriff der Langzeitverpackung definiert.

Um die Verwaltung von Schlüsseln zu unterstützen, die auf diese beiden unterschiedlichen Arten verpackt sind, muss die Hardware die folgenden Schnittstellen implementieren:

  • Schnittstellen zum Generieren und Importieren von Speicherschlüsseln und deren Rückgabe in langfristig verpackter Form. Der Zugriff auf diese Schnittstellen erfolgt indirekt über KeyMint und sie entsprechen dem KeyMint-Tag TAG_STORAGE_KEY . Die Funktion „Generieren“ wird von vold verwendet, um neue Speicherschlüssel für die Verwendung durch Android zu generieren, während die Funktion „Importieren“ von vts_kernel_encryption_test zum Importieren von Testschlüsseln verwendet wird.
  • Eine Schnittstelle zum Konvertieren eines langfristig verpackten Speicherschlüssels in einen kurzlebig verpackten Speicherschlüssel. Dies entspricht der keyMint-Methode convertStorageKeyToEphemeral . Diese Methode wird sowohl von vold als auch vts_kernel_encryption_test verwendet, um den Speicher zu entsperren.

Der Key-Wrapping-Algorithmus ist ein Implementierungsdetail, er sollte jedoch ein starkes AEAD wie AES-256-GCM mit zufälligen IVs verwenden.

Softwareänderungen erforderlich

AOSP verfügt bereits über ein grundlegendes Framework zur Unterstützung von Hardware-umhüllten Schlüsseln. Dazu gehört die Unterstützung in Userspace-Komponenten wie vold sowie die Linux-Kernel-Unterstützung in blk-crypto , fscrypt und dm-default-key .

Es sind jedoch einige umsetzungsspezifische Ä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-Krypto-Engine des Geräts muss geändert werden, um in Hardware verpackte Schlüssel zu unterstützen.

Für android14 und höhere Kernel legen Sie BLK_CRYPTO_KEY_TYPE_HW_WRAPPED in blk_crypto_profile::key_types_supported fest, stellen Sie sicher, dass blk_crypto_ll_ops::keyslot_program und blk_crypto_ll_ops::keyslot_evict das Programmieren/Entfernen von Hardware-umschlossenen Schlüsseln unterstützen, und implementieren Sie blk_crypto_ll_ops::derive_sw_secret .

Legen Sie für android12 und android13 Kernel BLK_CRYPTO_FEATURE_WRAPPED_KEYS in blk_keyslot_manager::features fest, stellen Sie sicher, dass blk_ksm_ll_ops::keyslot_program und blk_ksm_ll_ops::keyslot_evict das Programmieren/Entfernen von Hardware-umschlossenen Schlüsseln unterstützen, und implementieren Sie blk_ksm_ll_ops::derive_raw_secret .

Legen Sie für android11 Kernel BLK_CRYPTO_FEATURE_WRAPPED_KEYS in keyslot_manager::features fest, stellen Sie sicher, dass keyslot_mgmt_ll_ops::keyslot_program und keyslot_mgmt_ll_ops::keyslot_evict das Programmieren/Entfernen von Hardware-umschlossenen Schlüsseln unterstützen, und implementieren Sie keyslot_mgmt_ll_ops::derive_raw_secret “.

Testen

Obwohl die Verschlüsselung mit Hardware-umhüllten Schlüsseln schwieriger zu testen ist als die Verschlüsselung mit Standardschlüsseln, ist es dennoch möglich, sie zu testen, indem man einen Testschlüssel importiert und die Schlüsselableitung, die die Hardware durchführt, erneut implementiert. Dies ist in vts_kernel_encryption_test implementiert. Um diesen Test auszuführen, führen Sie Folgendes aus:

atest -v vts_kernel_encryption_test

Lesen Sie das Testprotokoll und stellen Sie sicher, dass die Testfälle für mit Hardware umschlossene Schlüssel (z. B. FBEPolicyTest.TestAesInlineCryptOptimizedHwWrappedKeyPolicy und DmDefaultKeyTest.TestHwWrappedKey ) nicht übersprungen wurden, da keine Unterstützung für mit Hardware umschlossene Schlüssel erkannt wird, da die Testergebnisse weiterhin „übergeben“ werden dieser Fall.

Aktivieren

Sobald die Hardware-umhüllte Schlüsselunterstützung des Geräts ordnungsgemäß funktioniert, können Sie die folgenden Änderungen an der fstab Datei des Geräts vornehmen, damit Android sie für FBE und Metadatenverschlüsselung verwendet:

  • FBE: Fügen Sie das Flag wrappedkey_v0 zum fileencryption hinzu. Verwenden Sie beispielsweise fileencryption=::inlinecrypt_optimized+wrappedkey_v0 . Weitere Einzelheiten finden Sie in der FBE-Dokumentation .
  • Metadatenverschlüsselung: Fügen Sie das Flag wrappedkey_v0 “ zum Parameter metadata_encryption hinzu. Verwenden Sie beispielsweise metadata_encryption=:wrappedkey_v0 . Weitere Einzelheiten finden Sie in der Dokumentation zur Metadatenverschlüsselung .