So verschlüsseln Sie Bytes mit dem TPM (Trusted Platform Module)

110

Wie kann ich Bytes mit dem TPM-Modul eines Computers verschlüsseln?

CryptProtectData

Windows bietet eine (relativ) einfache API zum Verschlüsseln eines Blobs mit dem CryptProtectData API, mit der wir eine benutzerfreundliche Funktion umschließen können:

public Byte[] ProtectBytes(Byte[] plaintext)
{
   //...
}

Die Details von ProtectBytessind weniger wichtig als die Idee, dass Sie es ganz einfach verwenden können:

  • Hier sind die Bytes, die mit einem geheimen Schlüssel verschlüsselt werden sollen System
  • Gib mir den verschlüsselten Blob zurück

Der zurückgegebene Blob ist nicht dokumentiert Dokumentationsstruktur , die alles enthält, was zum Entschlüsseln und Zurückgeben der Originaldaten erforderlich ist (Hash-Algorithmus, Verschlüsselungsalgorithmus, Salt, HMAC-Signatur usw.).

Der Vollständigkeit halber ist hier die Beispiel-Pseudocode-Implementierung ProtectBytes, die Crypt APIzum Schutz von Bytes verwendet:

public Byte[] ProtectBytes(Byte[] plaintext)
{
   //Setup our n-byte plaintext blob
   DATA_BLOB dataIn;
   dataIn.cbData = plaintext.Length;
   dataIn.pbData = Addr(plaintext[0]);

   DATA_BLOB dataOut;

   //dataOut = EncryptedFormOf(dataIn)
   BOOL bRes = CryptProtectData(
         dataIn,
         null,     //data description (optional PWideChar)
         null,     //optional entropy (PDATA_BLOB)
         null,     //reserved
         null,     //prompt struct
         CRYPTPROTECT_UI_FORBIDDEN || CRYPTPROTECT_LOCAL_MACHINE,
         ref dataOut);
   if (!bRes) then
   {
      DWORD le = GetLastError();
      throw new Win32Error(le, "Error calling CryptProtectData");
   }

   //Copy ciphertext from dataOut blob into an actual array
   bytes[] result;
   SetLength(result, dataOut.cbData);
   CopyMemory(dataOut.pbData, Addr(result[0]), dataOut.cbData);

   //When you have finished using the DATA_BLOB structure, free its pbData member by calling the LocalFree function
   LocalFree(HANDLE(dataOut.pbData)); //LocalFree takes a handle, not a pointer. But that's what the SDK says.
}

Wie mache ich dasselbe mit dem TPM?

Der obige Code ist nur zum Verschlüsseln von Daten für den lokalen Computer nützlich. Die Daten werden mit dem SystemKonto als Schlüsselgenerator verschlüsselt ( Details sind zwar interessant, aber unwichtig ). Das Endergebnis ist, dass ich Daten (z. B. einen Festplattenverschlüsselungs-Hauptschlüssel) verschlüsseln kann, die nur vom lokalen Computer entschlüsselt werden können.

Jetzt ist es Zeit, noch einen Schritt weiter zu gehen. Ich möchte einige Daten verschlüsseln (z. B. einen Hauptschlüssel für die Festplattenverschlüsselung), die nur vom lokalen TPM entschlüsselt werden können. Mit anderen Worten, ich möchte die TEE (Qualcomm Trusted Execution Environment ) im folgenden Blockdiagramm für Android durch das TPM in Windows ersetzen :

Geben Sie hier die Bildbeschreibung ein

Hinweis : Mir ist klar, dass das TPM keine Datensignatur ausführt (oder wenn dies der Fall ist, garantiert es nicht, dass das Signieren derselben Daten jedes Mal dieselbe Binärausgabe liefert). Aus diesem Grund wäre ich bereit, "RSA-Signatur" durch "Verschlüsselung eines 256-Bit-Blobs mit einem hardwaregebundenen Schlüssel" zu ersetzen. .

Wo ist der Code?

Das Problem ist, dass die TPM-Programmierung auf MSDN vollständig undokumentiert ist . Es ist keine API verfügbar, um Vorgänge auszuführen. Stattdessen müssen Sie sich eine Kopie des Software Stack (auch bekannt als TSS) der Trusted Computing Group suchen , herausfinden, welche Befehle mit Nutzdaten in welcher Reihenfolge an das TPM gesendet werden sollen, und die Tbsip_Submit_Command- Funktion von Window aufrufen , um Befehle direkt zu senden:

TBS_RESULT Tbsip_Submit_Command(
  _In_     TBS_HCONTEXT hContext,
  _In_     TBS_COMMAND_LOCALITY Locality,
  _In_     TBS_COMMAND_PRIORITY Priority,
  _In_     const PCBYTE *pabCommand,
  _In_     UINT32 cbCommand,
  _Out_    PBYTE *pabResult,
  _Inout_  UINT32 *pcbOutput
);

Windows verfügt über keine übergeordnete API zum Ausführen von Aktionen.

Dies ist das moralische Äquivalent zum Versuch, eine Textdatei zu erstellen, indem SATA-E / A-Befehle an Ihre Festplatte ausgegeben werden .

Warum nicht einfach Hosen benutzen?

Die Trusted Computing Group (TCG) hat eine eigene API definiert: TCB Software Stack (TSS) . Eine Implementierung dieser API wurde von einigen Personen erstellt und heißt TrouSerS . Ein Mann hat das Projekt dann auf Windows portiert .

Das Problem mit diesem Code ist, dass er nicht in die Windows-Welt portierbar ist. Sie können es beispielsweise nicht in Delphi oder in C # verwenden. Es benötigt:

  • OpenSSL
  • pThread

Ich möchte nur, dass der Code etwas mit meinem TPM verschlüsselt.

Das Obige CryptProtectDataerfordert nichts anderes als das, was sich im Funktionskörper befindet.

Was ist der entsprechende Code zum Verschlüsseln von Daten mit dem TPM? Wie andere angemerkt haben, müssen Sie wahrscheinlich die drei TPM-Handbücher konsultieren und die Blobs selbst erstellen . Es handelt sich wahrscheinlich um den TPM_sealBefehl. Obwohl ich denke , dass ich Daten nicht versiegeln möchte , denke ich, dass ich sie binden möchte :

Bindung - verschlüsselt Daten mit dem TPM-Bindeschlüssel, einem eindeutigen RSA-Schlüssel, der von einem Speicherschlüssel abstammt. Versiegeln - verschlüsselt Daten auf ähnliche Weise wie das Binden, gibt jedoch zusätzlich einen Zustand an, in dem sich TPM befinden muss, damit die Daten entschlüsselt (entsiegelt) werden können.

Ich versuche, die drei erforderlichen Bände zu lesen, um die 20 benötigten Codezeilen zu finden:

Aber ich habe keine Ahnung, was ich lese. Wenn es irgendeine Art von Tutorial oder Beispielen gäbe, könnte ich eine Chance haben. Aber ich bin völlig verloren.

Also fragen wir Stackoverflow

Auf die gleiche Weise konnte ich Folgendes bereitstellen:

Byte[] ProtectBytes_Crypt(Byte[] plaintext)
{
   //...
   CryptProtectData(...); 
   //...
}

kann jemand das entsprechende Äquivalent liefern:

Byte[] ProtectBytes_TPM(Byte[] plaintext)
{
   //...
   Tbsip_Submit_Command(...);
   Tbsip_Submit_Command(...);
   Tbsip_Submit_Command(...);
   //...snip...
   Tbsip_Submit_Command(...);
   //...
}

das macht das gleiche, außer dass ein in SystemLSA gesperrter Schlüssel im TPM gesperrt ist?

Beginn der Forschung

Ich weiß nicht genau, was Binden bedeutet. Wenn man sich jedoch TPM Main - Teil 3 Befehle - Spezifikation Version 1.2 ansieht, wird bind erwähnt :

10.3 TPM_UnBind

TPM_UnBind nimmt den Daten-Blob, der das Ergebnis eines Tspi_Data_Bind-Befehls ist, und entschlüsselt ihn für den Export an den Benutzer. Der Anrufer muss die Verwendung des Schlüssels autorisieren, der den eingehenden Blob entschlüsselt. TPM_UnBind arbeitet blockweise und hat keine Ahnung von einer Beziehung zwischen einem Block und einem anderen.

Was verwirrend ist, ist, dass es keinen Tspi_Data_BindBefehl gibt.

Forschungsaufwand

Es ist schrecklich, wie niemand sich jemals die Mühe gemacht hat, das TPM oder seinen Betrieb zu dokumentieren. Es ist, als hätten sie ihre ganze Zeit damit verbracht, sich dieses coole Ding auszudenken , mit dem sie spielen wollten, wollten sich aber nicht mit dem schmerzhaften Schritt befassen, es für etwas nutzbar zu machen.

Beginnend mit dem (jetzt) ​​kostenlosen Buch Ein praktischer Leitfaden für TPM 2.0: Verwenden des Trusted Platform-Moduls im neuen Zeitalter der Sicherheit :

Kapitel 3 - Kurzanleitung zu TPM 2.0

Das TPM hat Zugriff auf einen selbst generierten privaten Schlüssel, sodass es Schlüssel mit einem öffentlichen Schlüssel verschlüsseln und den resultierenden Blob dann auf der Festplatte speichern kann. Auf diese Weise kann das TPM eine praktisch unbegrenzte Anzahl von Schlüsseln zur Verwendung bereithalten, ohne jedoch wertvollen internen Speicher zu verschwenden. Auf der Festplatte gespeicherte Schlüssel können gelöscht, aber auch gesichert werden, was den Designern als akzeptabler Kompromiss erschien.

Wie kann ich einen Schlüssel mit dem öffentlichen Schlüssel des TPM verschlüsseln?

Kapitel 4 - Bestehende Anwendungen, die TPMs verwenden

Anwendungen, die das TPM verwenden sollten, dies aber nicht tun

In den letzten Jahren hat die Anzahl der webbasierten Anwendungen zugenommen. Dazu gehören webbasierte Sicherung und Speicherung. Eine große Anzahl von Unternehmen bietet inzwischen solche Dienste an. Soweit uns bekannt ist, lässt jedoch keiner der Clients für diese Dienste den Benutzer den Schlüssel für den Sicherungsdienst für ein TPM sperren. In diesem Fall wäre es sicherlich schön, wenn der TPM-Schlüssel selbst durch Duplizieren auf mehreren Computern gesichert würde. Dies scheint eine Chance für Entwickler zu sein.

Wie sperrt ein Entwickler einen Schlüssel für das TPM?

Kapitel 9 - Erben

GEBRAUCHSFALL: SPEICHERPASSWÖRTER SPEICHERN

In einer typischen Kennwortdatei werden gesalzene Kennwort-Hashes gespeichert. Die Überprüfung besteht darin, ein angegebenes Kennwort zu salzen, zu hashen und mit dem gespeicherten Wert zu vergleichen. Da die Berechnung kein Geheimnis enthält, wird die Kennwortdatei offline angegriffen.

In diesem Anwendungsfall wird ein TPM-generierter HMAC-Schlüssel verwendet. In der Kennwortdatei wird ein HMAC des gesalzenen Kennworts gespeichert. Die Überprüfung besteht darin, das angegebene Passwort zu salzen und zu HMACen und es mit dem gespeicherten Wert zu vergleichen. Da ein Offline-Angreifer nicht über den HMAC-Schlüssel verfügt, kann der Angreifer durch Ausführen der Berechnung keinen Angriff starten.

Das könnte funktionieren. Wenn das TPM einen geheimen HMAC-Schlüssel hat und nur mein TPM den HMAC-Schlüssel kennt, könnte ich "Sign (auch bekannt als TPM-Verschlüsselung mit privatem Schlüssel)" durch "HMAC" ersetzen. Aber dann kehrt er sich in der nächsten Zeile komplett um:

TPM2_Create, Angabe eines HMAC-Schlüssels

Es ist kein TPM-Geheimnis, wenn ich den HMAC-Schlüssel angeben muss. Die Tatsache, dass der HMAC-Schlüssel nicht geheim ist, ist sinnvoll, wenn Sie feststellen, dass dies das Kapitel über kryptografische Dienstprogramme ist, das das TPM bereitstellt. Anstatt SHA2, AES, HMAC oder RSA selbst schreiben zu müssen, können Sie das, was das TPM bereits herumliegen hat, wiederverwenden.

Kapitel 10 - Tasten

Als Sicherheitsgerät ist die Fähigkeit einer Anwendung, Schlüssel zu verwenden und sie gleichzeitig in einem Hardwaregerät zu schützen, die größte Stärke des TPM. Das TPM kann extern generierte Schlüssel sowohl generieren als auch importieren. Es unterstützt sowohl asymmetrische als auch symmetrische Tasten.

Ausgezeichnet! Wie machst du das!?

Schlüsselgenerator

Die wohl größte Stärke des TPM ist seine Fähigkeit, einen kryptografischen Schlüssel zu generieren und sein Geheimnis innerhalb einer Hardwaregrenze zu schützen. Der Schlüsselgenerator basiert auf dem TPM-eigenen Zufallszahlengenerator und ist nicht auf externe Zufallsquellen angewiesen. Dadurch werden Schwachstellen aufgrund schwacher Software mit unzureichender Entropiequelle beseitigt.

Kann das TPM kryptografische Schlüssel generieren und seine Geheimnisse innerhalb einer Hardwaregrenze schützen? Ist so, wie?

Kapitel 12 - Plattformkonfigurationsregister

PCRs zur Autorisierung

GEBRAUCHSFALL: VERSIEGELN EINES SCHLÜSSELSCHEIBENSCHLÜSSELS FÜR DEN PLATTFORMZUSTAND

Verschlüsselungsanwendungen auf der gesamten Festplatte sind weitaus sicherer, wenn ein TPM den Verschlüsselungsschlüssel schützt, als wenn er auf derselben Festplatte gespeichert ist und nur durch ein Kennwort geschützt ist. Erstens verfügt die TPM-Hardware über einen Anti-Hammering-Schutz (eine detaillierte Beschreibung des TPM-Wörterbuch-Angriffsschutzes finden Sie in Kapitel 8), wodurch ein Brute-Force-Angriff auf das Kennwort unpraktisch wird. Ein Schlüssel, der nur durch Software geschützt ist, ist weitaus anfälliger für ein schwaches Passwort. Zweitens ist ein auf der Festplatte gespeicherter Softwareschlüssel viel einfacher zu stehlen. Nehmen Sie die Festplatte (oder ein Backup der Festplatte) und Sie erhalten den Schlüssel. Wenn ein TPM den Schlüssel enthält, muss die gesamte Plattform oder zumindest die Festplatte und das Motherboard gestohlen werden.

Durch das Versiegeln kann der Schlüssel nicht nur durch ein Passwort, sondern auch durch eine Richtlinie geschützt werden. Eine typische Richtlinie sperrt den Schlüssel für PCR-Werte (den Softwarestatus), die zum Zeitpunkt des Versiegelns aktuell sind. Dies setzt voraus, dass der Status beim ersten Start nicht beeinträchtigt wird. Jegliche vorinstallierte Malware, die beim ersten Start vorhanden ist, wird in den PCRs gemessen, und somit wird der Schlüssel für einen gefährdeten Softwarestatus versiegelt. Ein weniger vertrauenswürdiges Unternehmen verfügt möglicherweise über ein Standard-Disk-Image und ein Siegel für PCRs, die dieses Image darstellen. Diese PCR-Werte würden auf einer vermutlich vertrauenswürdigeren Plattform vorberechnet. Ein noch anspruchsvolleres Unternehmen würde TPM2_PolicyAuthorize verwenden und mehrere Tickets bereitstellen, die eine Reihe vertrauenswürdiger PCR-Werte autorisieren. In Kapitel 14 finden Sie eine detaillierte Beschreibung der Richtlinienautorisierung und ihrer Anwendung zur Lösung des PCR-Sprödigkeitsproblems.

Obwohl ein Passwort auch den Schlüssel schützen könnte, gibt es auch ohne ein TPM-Schlüsselpasswort einen Sicherheitsgewinn. Ein Angreifer konnte die Plattform ohne Angabe eines TPMkey-Kennworts starten, sich jedoch nicht ohne den Benutzernamen und das Kennwort des Betriebssystems anmelden. Die OSsecurity schützt die Daten. Der Angreifer kann ein alternatives Betriebssystem starten, z. B. von einer Live-DVD oder einem USB-Stick anstatt von der Festplatte, um die Anmeldesicherheit des Betriebssystems zu umgehen. Diese unterschiedliche Startkonfiguration und Software würde jedoch die PCR-Werte ändern. Da diese neuen PCRs nicht mit den versiegelten Werten übereinstimmen würden, würde das TPM den Entschlüsselungsschlüssel nicht freigeben und die Festplatte könnte nicht entschlüsselt werden.

Ausgezeichnet! Dies ist genau der Anwendungsfall, den ich zufällig möchte. Dies ist auch der Anwendungsfall, für den Microsoft das TPM verwendet. Wie mache ich es!?

Also habe ich das ganze Buch gelesen und es hat nichts Nützliches geliefert. Das ist ziemlich beeindruckend, weil es 375 Seiten umfasst. Sie fragen sich, was das Buch enthielt - und wenn ich zurückblicke, habe ich keine Ahnung.

Deshalb geben wir die endgültige Anleitung zur Programmierung des TPM auf und wenden uns stattdessen einer Dokumentation von Microsoft zu:

Aus dem Microsoft TPM Platform Crypto-Provider Toolkit . Es wird genau erwähnt, was ich tun möchte:

Der Endorsement Key oder EK

Der EK wurde entwickelt, um eine zuverlässige kryptografische Kennung für die Plattform bereitzustellen. Ein Unternehmen verwaltet möglicherweise eine Datenbank der Endorsement Keys, die zu den TPMs aller PCs in seinem Unternehmen gehören, oder ein Rechenzentrums-Fabric-Controller verfügt möglicherweise über eine Datenbank der TPMs in allen Blades. Unter Windows können Sie den im Abschnitt „Platform Crypto Provider in Windows 8“ beschriebenen NCrypt-Anbieter verwenden, um den öffentlichen Teil des EK zu lesen.

Irgendwo im TPM befindet sich ein privater RSA-Schlüssel. Dieser Schlüssel ist dort eingesperrt - von der Außenwelt nie zu sehen. Ich möchte, dass das TPM etwas mit seinem privaten Schlüssel signiert (dh es mit seinem privaten Schlüssel verschlüsselt).

Ich möchte also die grundlegendste Operation, die es möglicherweise geben kann:

Geben Sie hier die Bildbeschreibung ein

Verschlüsseln Sie etwas mit Ihrem privaten Schlüssel. Ich frage (noch) nicht einmal nach den komplizierteren Sachen:

  • "Versiegeln" basierend auf dem PCR-Zustand
  • Erstellen eines Schlüssels und Speichern in einem flüchtigen oder nichtflüchtigen Speicher
  • Erstellen eines symmetrischen Schlüssels und Versuch, ihn in das TPM zu laden

Ich frage nach der grundlegendsten Operation, die ein TPM ausführen kann. Warum ist es unmöglich, Informationen darüber zu erhalten?

Ich kann zufällige Daten bekommen

Ich schätze, ich war glitschig, als ich sagte, dass die RSA-Signierung das grundlegendste ist, was das TPM tun kann. Die meisten grundlegende Sache , die TPM gefragt werden kann , tun , ist mir zufälliges Bytes geben. Dass ich herausgefunden habe, wie es geht:

public Byte[] GetRandomBytesTPM(int desiredBytes)
{
   //The maximum random number size is limited to 4,096 bytes per call
   Byte[] result = new Byte[desiredBytes];

   BCRYPT_ALG_HANDLE hAlgorithm;

   BCryptOpenAlgorithmProvider(
         out hAlgorithm,
         BCRYPT_RNG_ALGORITHM, //AlgorithmID: "RNG"
         MS_PLATFORM_CRYPTO_PROVIDER, //Implementation: "Microsoft Platform Crypto Provider" i.e. the TPM
         0 //Flags
   );
   try
   {                
      BCryptGenRandom(hAlgorithm, @result[0], desiredBytes, 0);
   }
   finally
   {
      BCryptCloseAlgorithmProvider(hAlgorithm);
   }

   return result;
}

Die schicke Sache

Mir ist klar, dass die Anzahl der Personen, die das TPM verwenden, sehr gering ist. Deshalb hat niemand auf Stackoverflow eine Antwort. Ich kann also nicht zu gierig werden, um eine Lösung für mein gemeinsames Problem zu finden. Aber das, was ich wirklich tun möchte, ist, einige Daten zu "versiegeln" :

Geben Sie hier die Bildbeschreibung ein

  • Präsentieren Sie dem TPM einige Daten (z. B. 32 Byte Schlüsselmaterial).
  • Lassen Sie das TPM die Daten verschlüsseln und geben Sie eine undurchsichtige Blob-Struktur zurück
  • Bitten Sie später das TPM, den Blob zu entschlüsseln
  • Die Entschlüsselung funktioniert nur, wenn die PCR-Register des TPM dieselben sind wie während der Verschlüsselung.

Mit anderen Worten:

Byte[] ProtectBytes_TPM(Byte[] plaintext, Boolean sealToPcr)
{
   //...
}

Byte[] UnprotectBytes_TPM(Byte[] protectedBlob)
{
   //...
}

Kryptographie Next Gen (Cng, auch bekannt als BCrypt) unterstützt TPM

Die ursprüngliche Kryptographie-API in Windows wurde als Krypto-API bezeichnet.

Ab Windows Vista wurde die Crypto-API durch die Cryptography-API: Next Generation (intern als BestCrypt , abgekürzt als BCrypt , nicht zu verwechseln mit dem Kennwort-Hashing-Algorithmus ) ersetzt.

Windows wird mit zwei BCrypt- Anbietern ausgeliefert :

Der Platform Crypto- Anbieter ist nicht auf MSDN dokumentiert, verfügt jedoch über Dokumentation von einer Microsoft Research-Website 2012:

TPM Platform Crypto-Provider Toolkit

Der TPM Platform Crypto Provider und das Toolkit enthalten Beispielcode, Dienstprogramme und Dokumentation für die Verwendung von TPM-bezogenen Funktionen in Windows 8. Zu den beschriebenen Subsystemen gehören der TPM-gestützte Crypto-Next-Gen (CNG) -Plattform-Crypto-Provider und die Anbieter von Attestierungsdiensten kann die neuen Windows-Funktionen verwenden. Es werden sowohl TPM1.2- als auch TPM2.0-basierte Systeme unterstützt.

Es scheint, dass Microsoft beabsichtigt, die TPM-Kryptofunktionalität mit dem Microsoft Platform Crypto Provider der Cryptography NG API zu erweitern.

Verschlüsselung mit öffentlichem Schlüssel mit Microsoft BCrypt

Vorausgesetzt, dass:

Ein Weg in die Zukunft könnte darin bestehen, herauszufinden, wie das digitale Signieren mithilfe der Microsoft Cryptography Next Gen-API durchgeführt wird .

Mein nächster Schritt wird darin bestehen, den Code für die Verschlüsselung in BCrypt mit einem öffentlichen RSA-Schlüssel unter Verwendung des Standardanbieters ( MS_PRIMITIVE_PROVIDER) zu erstellen . Z.B:

  • modulus: 0xDC 67 FA F4 9E F2 72 1D 45 2C B4 80 79 06 A0 94 27 50 8209 DD 67 CE 57 B8 6C 4A 4F 40 9F D2 D1 69 FB 995D 85 0C 07 A1 F9 47 1B 56 16 6E F6 7F B9 CF 2A 58 36 37 99 29 AA 4F A8 12 E8 4F C7 82 2B 9D 72 2A 9C DE 6F C2 EE 12 6D CF F0 F2 B8 C4 DD 7C 5C 1A C8 17 51 A9 AC DF 08 22 04 9D 2B D7 F9 4B 09 DE 9A EB 5C 51 1A D8 F8 F9 56 9E F8 FB 37 9B 3F D3 74 65 24 0D FF 34 75 57 A4 F5 BF 55
  • publicExponent: 65537

Wenn dieser Code funktioniert, kann ich möglicherweise zur Verwendung des TPM-Anbieters ( MS_PLATFORM_CRYPTO_PROVIDER) wechseln .

22.02.2016: Und da Apple gezwungen ist, beim Entschlüsseln von Benutzerdaten zu helfen, besteht erneut Interesse daran, wie das TPM die einfachste Aufgabe ausführen kann, für die es erfunden wurde - etwas zu verschlüsseln.

Es ist ungefähr gleichbedeutend mit jedem, der ein Auto besitzt, aber niemand weiß, wie man eines startet. Es kann wirklich nützliche und coole Dinge tun, wenn wir nur Schritt 1 überwinden könnten .

Bonuslesung

Ian Boyd
quelle
Für die Bindung (Verschlüsselung) steht keine explizite Funktion zur Verfügung und wird auch nicht benötigt. Sie erstellen einfach einen Bindungsschlüssel im TPM und verwenden seinen öffentlichen Teil, um einen symmetrischen Verschlüsselungsschlüssel mit der System-RSA-Verschlüsselungsfunktion ("RSA / ECB / OAEPWithSHA1AndMGF1Padding") zu verschlüsseln und in der richtigen Struktur ("TcTssConstants.TSS_ENCDATA_BIND") zu speichern. Zum Entbinden (Entschlüsseln) des Seks verwenden Sie einfach die TPM-Entbindungsfunktion und verwenden den Sek in einer beliebigen symmetrischen Verschlüsselungsfunktion. Ich habe eine ziemlich alte Codebasis dafür, die ich vor einiger Zeit gemacht habe, vielleicht hilft es: goo.gl/jV1Ouw
evildead
In Wikipedia verschlüsselt die Bindung Daten mit dem TPM-Bindeschlüssel, einem eindeutigen RSA-Schlüssel, der von einem Speicherschlüssel abstammt. en.wikipedia.org/wiki/Trusted_Platform_Module Klingt so, als ob dieses Befehlspaar (TSpi_Data_Bind / TPM_UnBind) für Ihre Bedürfnisse ausreichen sollte ...
Alex Mazzariol
1
Ich glaube nicht, dass Sie das TPM direkt verwenden müssen. Es wird über die Standard-CNG / NCryptXXX-APIs und den "Microsoft Platform Crypto Provider" unterstützt (für aktuelle Windows-Betriebssystemplattformen und wenn die Hardware in Ordnung und natürlich aktiviert ist). Vielleicht können Sie sich das "TPM Platform Crypto-Provider Toolkit" hier ansehen : research.microsoft.com/en-us/downloads/… überprüfen Sie dies auch: tiw2013.cse.psu.edu/slides/…
Simon Mourier
CryptProtectData verwendet nicht unbedingt das TPM. Wenn Sie andererseits ein gültiges CNG- oder CSP-Handle für das TPM erhalten können, können Sie es in Kryptofunktionen verwenden.
Michael Chourdakis
1
@ b3nj1 Nein, war ich nicht; niemand konnte die Frage beantworten.
Ian Boyd

Antworten:

7

Grundierung

Alles was folgt ist über TPM 1.2. Beachten Sie, dass Microsoft für alle zukünftigen Windows-Versionen ein TPM 2.0 benötigt. Die 2.0-Generation unterscheidet sich grundlegend von der 1.2

Aufgrund der TPM-Entwurfsprinzipien gibt es keine einzeilige Lösung. Stellen Sie sich das TPM als einen Mikrocontroller mit begrenzten Ressourcen vor. Das Hauptziel des Designs war es, billig und dennoch sicher zu sein. Das TPM wurde also von jeglicher Logik befreit, die für einen sicheren Betrieb nicht erforderlich war. Daher funktioniert ein TPM nur, wenn Sie mindestens eine mehr oder weniger fette Software haben, die viele Befehle in der richtigen Reihenfolge ausgibt. Und diese Befehlssequenzen können sehr komplex werden. Aus diesem Grund hat TCG das TSS mit einer genau definierten API spezifiziert. Wenn Sie den Java-Weg gehen möchten, gibt es sogar eine Java-API auf hoher Ebene . Mir ist kein ähnliches Projekt für C # / .net bekannt

Entwicklung

In Ihrem Fall würde ich vorschlagen, dass Sie sich die IBM-Software TPM ansehen.

Im Paket finden Sie 3 sehr nützliche Komponenten:

  • ein Software-TPM-Emulator
  • eine leichte tpm lib
  • Einige grundlegende Befehlszeilenprogramme

Sie benötigen nicht unbedingt den Software-TPM-Emulator, sondern können auch eine Verbindung zum HW-TPM des Geräts herstellen. Sie können jedoch die ausgegebenen Befehle abfangen und die Antworten anzeigen, um zu erfahren, wie sie zusammengesetzt sind und wie sie der Befehlsspezifikation entsprechen.

Hohes Level

Voraussetzungen:

  1. TPM ist aktiviert
  2. TPM-Treiber wird geladen
  3. Sie haben das TPM übernommen

Um einen Blob zu versiegeln, müssen Sie Folgendes tun:

  1. Erstellen Sie einen Schlüssel
  2. Bewahren Sie den Key-Blob irgendwo auf
  3. Stellen Sie sicher, dass der Schlüssel im TPM geladen ist
  4. Versiegeln Sie den Klecks

Zum Entsiegeln müssen Sie:

  1. Erhalten Sie den Key-Blob
  2. Laden Sie den Schlüssel in das TPM
  3. Entsiegeln Sie den versiegelten Klecks

Sie können den Key-Blob in Ihrer Datenstruktur speichern, in der Sie die geschützten Bytes speichern.

Die meisten TPM-Befehle, die Sie benötigen, sind autorisierte Befehle. Daher müssen Sie bei Bedarf Autorisierungssitzungen einrichten. AFAIR das sind meistens OSAP-Sitzungen.

TPM-Befehle

Derzeit kann ich keine Debug-Version ausführen, daher kann ich Ihnen nicht die genaue Reihenfolge mitteilen. Betrachten Sie dies als eine ungeordnete Liste von Befehlen, die Sie verwenden müssen:

  • TPM_OSAP
  • TPM_CreateWrapKey
  • TPM_LoadKey2
  • TPM_Seal

Wenn Sie auch die aktuellen PCR-Werte lesen möchten:

  • TPM_PCRRead
Scolytus
quelle
Microsoft verfügt über eine von C # .NET verwaltete Bibliothek zur Verwendung des TPM . Sie haben auch einen TPM-Emulator , mit dem die verwaltete Bibliothek als Debugging-Alternative eine Verbindung herstellen kann, wenn kein echtes TPM vorhanden ist. Sie verfügen außerdem über das TPM Platform Provider Toolkit , das Dokumentation und Beispielcode für die Verwendung des TPM enthält. Wenn nur jemand herausfinden könnte, wie man das TPM zum Verschlüsseln von Bytes verwendet.
Ian Boyd
Ihre ersten beiden Links sind nur TPM 2.0. Wenn Sie diese verwenden möchten, habe ich leider keine Hilfe.
Scolytus
4

Vertrauenswürdige und verschlüsselte Schlüssel

Vertrauenswürdige und verschlüsselte Schlüssel sind zwei neue Schlüsseltypen, die dem vorhandenen Kernel-Schlüsselringdienst hinzugefügt werden. Diese beiden neuen Typen sind symmetrische Schlüssel mit variabler Länge. In beiden Fällen werden alle Schlüssel im Kernel erstellt, und der Benutzerbereich sieht, speichert und lädt nur verschlüsselte Blobs. Vertrauenswürdige Schlüssel erfordern die Verfügbarkeit eines TPM-Chips (Trusted Platform Module) für mehr Sicherheit, während verschlüsselte Schlüssel auf jedem System verwendet werden können. Alle Blobs auf Benutzerebene werden der Einfachheit halber in hexadezimaler ASCII angezeigt und geladen und auf Integrität überprüft.

Vertrauenswürdige Schlüssel verwenden ein TPM, um die Schlüssel zu generieren und zu versiegeln. Die Schlüssel werden unter einem 2048-Bit-RSA-Schlüssel im TPM versiegelt und optional auf bestimmte PCR-Werte (Integritätsmessung) versiegelt und vom TPM nur entsiegelt, wenn PCRs und Blob-Integritätsprüfungen übereinstimmen. Ein geladener vertrauenswürdiger Schlüssel kann mit neuen (zukünftigen) PCR-Werten aktualisiert werden, sodass Schlüssel leicht auf neue pcr-Werte migriert werden können, z. B. wenn der Kernel und die initramfs aktualisiert werden. Mit demselben Schlüssel können viele Blobs unter verschiedenen PCR-Werten gespeichert werden, sodass mehrere Startvorgänge problemlos unterstützt werden.

Standardmäßig werden vertrauenswürdige Schlüssel unter dem SRK versiegelt, das den Standardautorisierungswert (20 Nullen) hat. Dies kann zum Zeitpunkt des Besitzes mit dem Dienstprogramm der Hose eingestellt werden : tpm_takeownership -u -z.

Usage:
    keyctl add trusted name "new keylen [options]" ring
    keyctl add trusted name "load hex_blob [pcrlock=pcrnum]" ring
    keyctl update key "update [options]"
    keyctl print keyid

    options:
    keyhandle= ascii hex value of sealing key default 0x40000000 (SRK)
    keyauth=   ascii hex auth for sealing key default 0x00...i
        (40 ascii zeros)
    blobauth=  ascii hex auth for sealed data default 0x00...
        (40 ascii zeros)
    blobauth=  ascii hex auth for sealed data default 0x00...
        (40 ascii zeros)
    pcrinfo=   ascii hex of PCR_INFO or PCR_INFO_LONG (no default)
    pcrlock=   pcr number to be extended to "lock" blob
    migratable= 0|1 indicating permission to reseal to new PCR values,
                default 1 (resealing allowed)

keyctl printGibt eine ASCII-Hex-Kopie des versiegelten Schlüssels zurück, die im Standardformat TPM_STORED_DATA vorliegt. Die Schlüssellänge für neue Schlüssel wird immer in Byte angegeben. Vertrauenswürdige Schlüssel können 32 - 128 Byte (256 - 1024 Bit) groß sein. Die Obergrenze muss innerhalb der 2048-Bit-SRK-Schlüssellänge (RSA) mit allen erforderlichen Strukturen / Auffüllungen liegen.

Verschlüsselte Schlüssel hängen nicht von einem TPM ab und sind schneller, da sie AES zur Ver- / Entschlüsselung verwenden. Neue Schlüssel werden aus vom Kernel generierten Zufallszahlen erstellt und mit einem angegebenen Hauptschlüssel verschlüsselt / entschlüsselt. Der Hauptschlüssel kann entweder ein vertrauenswürdiger Schlüssel oder ein Benutzerschlüsseltyp sein. Der Hauptnachteil von verschlüsselten Schlüsseln besteht darin, dass sie nur so sicher sind, wie der Benutzerschlüssel, der sie verschlüsselt, wenn sie nicht in einem vertrauenswürdigen Schlüssel verwurzelt sind. Der Hauptbenutzerschlüssel sollte daher so sicher wie möglich geladen werden, vorzugsweise zu Beginn des Startvorgangs.

Der entschlüsselte Teil der verschlüsselten Schlüssel kann entweder einen einfachen symmetrischen Schlüssel oder eine komplexere Struktur enthalten. Das Format der komplexeren Struktur ist anwendungsspezifisch und wird durch "Format" gekennzeichnet.

Usage:
    keyctl add encrypted name "new [format] key-type:master-key-name keylen"
        ring
    keyctl add encrypted name "load hex_blob" ring
    keyctl update keyid "update key-type:master-key-name"

format:= 'default | ecryptfs'
key-type:= 'trusted' | 'user'

Beispiele für die Verwendung vertrauenswürdiger und verschlüsselter Schlüssel

Erstellen und speichern Sie einen vertrauenswürdigen Schlüssel mit dem Namen "kmk" mit einer Länge von 32 Byte:

$ keyctl add trusted kmk "new 32" @u
440502848

$ keyctl show
Session Keyring
       -3 --alswrv    500   500  keyring: _ses
 97833714 --alswrv    500    -1   \_ keyring: _uid.500
440502848 --alswrv    500   500       \_ trusted: kmk

$ keyctl print 440502848
0101000000000000000001005d01b7e3f4a6be5709930f3b70a743cbb42e0cc95e18e915
3f60da455bbf1144ad12e4f92b452f966929f6105fd29ca28e4d4d5a031d068478bacb0b
27351119f822911b0a11ba3d3498ba6a32e50dac7f32894dd890eb9ad578e4e292c83722
a52e56a097e6a68b3f56f7a52ece0cdccba1eb62cad7d817f6dc58898b3ac15f36026fec
d568bd4a706cb60bb37be6d8f1240661199d640b66fb0fe3b079f97f450b9ef9c22c6d5d
dd379f0facd1cd020281dfa3c70ba21a3fa6fc2471dc6d13ecf8298b946f65345faa5ef0
f1f8fff03ad0acb083725535636addb08d73dedb9832da198081e5deae84bfaf0409c22b
e4a8aea2b607ec96931e6f4d4fe563ba

$ keyctl pipe 440502848 > kmk.blob

Laden Sie einen vertrauenswürdigen Schlüssel aus dem gespeicherten Blob:

$ keyctl add trusted kmk "load `cat kmk.blob`" @u
268728824

$ keyctl print 268728824
0101000000000000000001005d01b7e3f4a6be5709930f3b70a743cbb42e0cc95e18e915
3f60da455bbf1144ad12e4f92b452f966929f6105fd29ca28e4d4d5a031d068478bacb0b
27351119f822911b0a11ba3d3498ba6a32e50dac7f32894dd890eb9ad578e4e292c83722
a52e56a097e6a68b3f56f7a52ece0cdccba1eb62cad7d817f6dc58898b3ac15f36026fec
d568bd4a706cb60bb37be6d8f1240661199d640b66fb0fe3b079f97f450b9ef9c22c6d5d
dd379f0facd1cd020281dfa3c70ba21a3fa6fc2471dc6d13ecf8298b946f65345faa5ef0
f1f8fff03ad0acb083725535636addb08d73dedb9832da198081e5deae84bfaf0409c22b
e4a8aea2b607ec96931e6f4d4fe563ba

Versiegeln Sie einen vertrauenswürdigen Schlüssel unter neuen pcr-Werten erneut:

$ keyctl update 268728824 "update pcrinfo=`cat pcr.blob`"
$ keyctl print 268728824
010100000000002c0002800093c35a09b70fff26e7a98ae786c641e678ec6ffb6b46d805
77c8a6377aed9d3219c6dfec4b23ffe3000001005d37d472ac8a44023fbb3d18583a4f73
d3a076c0858f6f1dcaa39ea0f119911ff03f5406df4f7f27f41da8d7194f45c9f4e00f2e
df449f266253aa3f52e55c53de147773e00f0f9aca86c64d94c95382265968c354c5eab4
9638c5ae99c89de1e0997242edfb0b501744e11ff9762dfd951cffd93227cc513384e7e6
e782c29435c7ec2edafaa2f4c1fe6e7a781b59549ff5296371b42133777dcc5b8b971610
94bc67ede19e43ddb9dc2baacad374a36feaf0314d700af0a65c164b7082401740e489c9
7ef6a24defe4846104209bf0c3eced7fa1a672ed5b125fc9d8cd88b476a658a4434644ef
df8ae9a178e9f83ba9f08d10fa47e4226b98b0702f06b3b8

Der Erstverbraucher vertrauenswürdiger Schlüssel ist EVM, das beim Booten einen hochwertigen symmetrischen Schlüssel für den HMAC-Schutz von Dateimetadaten benötigt. Die Verwendung eines vertrauenswürdigen Schlüssels bietet starke Garantien dafür, dass der EVM-Schlüssel nicht durch ein Problem auf Benutzerebene beeinträchtigt wurde, und schützt vor Boot- und Offline-Angriffen, wenn er an bestimmte Boot-PCR-Werte gebunden ist. Erstellen und speichern Sie einen verschlüsselten Schlüssel "evm" mit dem oben genannten vertrauenswürdigen Schlüssel "kmk":

Option 1: Auslassen des 'Formats'

$ keyctl add encrypted evm "new trusted:kmk 32" @u
159771175

Option 2: 'Format' explizit als 'Standard' definieren

$ keyctl add encrypted evm "new default trusted:kmk 32" @u
159771175

$ keyctl print 159771175
default trusted:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b3
82dbbc55be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e0
24717c64 5972dcb82ab2dde83376d82b2e3c09ffc

$ keyctl pipe 159771175 > evm.blob

Laden Sie einen verschlüsselten Schlüssel "evm" aus dem gespeicherten Blob:

$ keyctl add encrypted evm "load `cat evm.blob`" @u
831684262

$ keyctl print 831684262
default trusted:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b3
82dbbc55be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e0
24717c64 5972dcb82ab2dde83376d82b2e3c09ffc

Andere Verwendungen für vertrauenswürdige und verschlüsselte Schlüssel, z. B. für die Festplatten- und Dateiverschlüsselung, werden erwartet. Insbesondere wurde das neue Format 'ecryptfs' definiert, um verschlüsselte Schlüssel zum Mounten eines eCryptfs-Dateisystems zu verwenden. Weitere Details zur Verwendung finden Sie in der Datei 'Documentation / security / keys-ecryptfs.txt'.

Chandana
quelle
Haben Sie eine Idee, wann diese beiden neuen Schlüsseltypen hinzugefügt wurden? In welcher Version meine ich. Ich verwende derzeit 1.2 (Firmenpakete) und dieses unterstützt diese nicht. Vielleicht in 1.5+?
Acapulco
1
Was ist die Quelle dieses Beitrags? Das Ende bezieht sich auf ein DokumentDocumentation/security/keys-ecryptfs.tx
goodguys_activate
Dies scheinen alles Aufrufe eines Befehlszeilenprogramms zu sein. Ich sehe keinen Code zur Verwendung des TPM.
Ian Boyd
3

Wie kann ich Bytes mit dem TPM-Modul eines Computers verschlüsseln?

Hängt von Ihrer Absicht und Ihren Umständen ab:

  • Was für ein TPM haben Sie (1-Familie oder 2-Familie)?
  • In welchem ​​Zustand befindet sich das TPM? Wurde es besessen? Wurde es bereitgestellt?
  • Was ist Ihre Programmiersprache?
  • Möchten Sie verschlüsseln oder signieren? (Das ist vage vom Rest der Frage)
  • Wie groß sind die Daten, die Sie verschlüsseln möchten?
  • Möchten Sie einen symmetrischen oder einen asymmetrischen Schlüssel verwenden?
  • Möchten Sie einen Schlüssel verwenden, der bereits im TPM vorhanden ist, oder möchten Sie, dass dieser zuerst den Schlüssel erstellt?
  • Mit "verschlüsseln" meinen Sie vielleicht "einen Schlüssel einwickeln"?
  • Möchten Sie die verschlüsselten Daten für die Systemkonfiguration sperren, damit sie nur entschlüsselt werden können, wenn sich das System wieder in derselben Konfiguration befindet?
  • Möchten Sie eine Autorisierung zum Entschlüsseln benötigen?
  • Vielleicht müssen Sie gar nicht verschlüsseln, sondern die Daten im TPM speichern?
  • Wenn Sie die Daten im TPM speichern, möchten Sie eine Autorisierung benötigen oder dass sich das System zum Abrufen in einer bestimmten Konfiguration befindet?

Jeder dieser Anwendungsfälle (und es gibt mehr) - oder eine Kombination davon - bietet einen anderen Implementierungspfad. Stellen Sie sich das TPM als ein Schweizer Taschenmesser für kryptografische Geräte vor: Es gibt nicht viel, was Sie damit nicht tun können, aber die Benutzerfreundlichkeit leidet unter dieser Vielseitigkeit. Die Frage wechselt ständig zwischen Verschlüsselung, Signatur und Sperrung der Systemkonfiguration. Im Hauptteil dieser Antwort wird jedoch der Befehl Versiegeln berücksichtigt, um die meisten der in der Frage beschriebenen Anforderungen abzudecken.

Jetzt ist es Zeit, noch einen Schritt weiter zu gehen. Ich möchte einige Daten verschlüsseln (z. B. einen Hauptschlüssel für die Festplattenverschlüsselung), die nur vom lokalen TPM entschlüsselt werden können.

Dafür ist der Befehl Bind gedacht (ersetzt durch den Befehl Create für TPM 2). Sie laden einen Schlüssel, der von einem TPM-gebundenen Schlüssel abgeleitet ist, und verschlüsseln ihn (oder direkt mit einem hardwaregebundenen Schlüssel). Auf diese Weise können die Daten nur mit Zugriff auf dasselbe TPM entschlüsselt werden.

Mit anderen Worten, ich möchte die TEE (Qualcomm Trusted Execution Environment) im folgenden Blockdiagramm für Android durch das TPM in Windows ersetzen:

Ich bin mir nicht sicher, ob es eine gute Idee ist, diesen gesamten Prozess zu replizieren. Zum einen muss an keiner Stelle des Prozesses eine Signaturoperation verwendet werden. Es scheint, dass sich die Keystore-API zum Zeitpunkt der Entwicklung von Android 5 auf Signatur- und Überprüfungsvorgänge beschränkte. Ich vermute, dass das Festplattenverschlüsselungsteam sein Bestes getan hat, um mit dem zu arbeiten, was es hatte, und einen Algorithmus entwickelt hat, bei dem einer der Zwischenschlüssel mit einer Signaturoperation unter Verwendung eines gespeicherten TEE-Schlüssels abgeleitet wurde, wodurch der gesamte Prozess an eine Hardware gebunden wurde. gebundener Schlüssel nur auf der Plattform verfügbar - da dies zu diesem Zeitpunkt nur durch Signieren möglich war. Sie müssen sich jedoch nicht auf diese Weise einschränken, wenn Sie Zugriff auf ein TPM haben, wodurch Sie mehr Funktionen erhalten, als Sie für nötig gehalten haben!

Mir ist klar, dass das TPM keine Datensignatur ausführt

Dies ist falsch. Beide Versionen von TPM unterstützen das Signieren.

(oder wenn dies der Fall ist, kann nicht garantiert werden, dass das Signieren derselben Daten jedes Mal dieselbe Binärausgabe liefert)

Das macht keinen Sinn. Wenn Sie dieselben Daten mit demselben Schlüssel signieren , wird dieselbe Signatur erstellt. Möglicherweise verwechseln Sie den Signiervorgang mit dem Anführungsvorgang, bei dem eine Nonce gemischt wird.

Aus diesem Grund wäre ich bereit, "RSA-Signatur" durch "Verschlüsselung eines 256-Bit-Blobs mit einem hardwaregebundenen Schlüssel" zu ersetzen.

Dies sollte eigentlich die bevorzugte Option sein, obwohl beide mit einem TPM möglich sind. Siehe oben.

Das Problem ist, dass die TPM-Programmierung auf MSDN vollständig undokumentiert ist. Es ist keine API verfügbar, um Vorgänge auszuführen.

Leider gibt es nicht viel zu dokumentieren. Die Win-API ist auf einige TBS-Funktionen beschränkt, die eine Ebene vom Treiber entfernt sind.

Stattdessen müssen Sie sich eine Kopie des Software Stack (auch bekannt als TSS) der Trusted Computing Group suchen, herausfinden, welche Befehle mit Nutzdaten in welcher Reihenfolge an das TPM gesendet werden sollen, und die Tbsip_Submit_Command-Funktion von Window aufrufen, um Befehle direkt zu senden:

Nein, wenn Sie ein TSS hätten, müssten Sie es nicht verwenden Tbsip_submit_Command(). Das ist der springende Punkt bei einem TSS - die Details auf niedriger Ebene werden weg abstrahiert.

Windows verfügt über keine übergeordnete API zum Ausführen von Aktionen.

Immer noch wahr für TPM 1, aber für TPM 2 gibt es TSS.MSR .

Dies ist das moralische Äquivalent zum Versuch, eine Textdatei zu erstellen, indem SATA-E / A-Befehle an Ihre Festplatte ausgegeben werden.

Richtig.

Warum nicht einfach Hosen verwenden ... Das Problem mit diesem Code ist, dass er nicht in die Windows-Welt portierbar ist. Sie können es beispielsweise nicht in Delphi verwenden, Sie können es nicht in C # verwenden. Es erfordert: OpenSSL, pThread

Es ist nicht klar, dass dies eine unüberwindliche Herausforderung ist. Der Zugriff auf TrouSerS über ein Interop sollte dem Umschreiben des gesamten Datenstrukturierungscodes vorzuziehen sein. Auch gab es doTSSzum Zeitpunkt des Schreibens die Frage.

Was ist der entsprechende Code zum Verschlüsseln von Daten mit dem TPM? Es handelt sich wahrscheinlich um den Befehl TPM_seal. Obwohl ich denke, dass ich Daten nicht versiegeln möchte, denke ich, dass ich sie binden möchte:

Die Frage enthält ein Zitat, das den Unterschied zwischen den beiden Befehlen beschreibt, daher sollte es nicht viel Verwirrung geben. Das Versiegeln ähnelt dem Binden, mit der zusätzlichen Einschränkung, dass der Systemstatus derselbe sein muss, damit die Daten entsiegelt werden.

Auf die gleiche Weise konnte ich Folgendes bereitstellen:

Byte[] ProtectBytes_Crypt(Byte[] plaintext)
{
   //...
   CryptProtectData(...); 
   //...
}

kann jemand das entsprechende Äquivalent liefern:

Byte[] ProtectBytes_TPM(Byte[] plaintext)
{
   //...
   Tbsip_Submit_Command(...);
   Tbsip_Submit_Command(...);
   Tbsip_Submit_Command(...);
   //...snip...
   Tbsip_Submit_Command(...);
   //...
}

das macht das gleiche, außer dass ein in System LSA gesperrter Schlüssel im TPM gesperrt ist?

Zunächst ist darauf hinzuweisen, dass es zwei Hauptversionen von TPM gibt, die untereinander völlig inkompatibel sind. Daher funktioniert praktisch kein Code, den Sie möglicherweise für TPM 1 geschrieben haben, für TPM 2. Die TBS-API ist der einzige gemeinsame Code zwischen beiden, und um Microsoft gegenüber fair zu sein, war dies möglicherweise einer der Gründe, warum diese API nie gewachsen ist. Der Hauptteil der Antwort enthält den Code für TPM 1 aus zwei Gründen:

  • Die Frage enthält TPM 1-spezifische Konzepte, sodass Personen, die TPM 1 verwenden, eher hier landen und nach ihnen suchen
  • Es gibt eine Microsoft-Implementierung von TSS für TPM 2.

Zweitens wollen wir die Frage genauer formulieren. Ich interpretiere es wie folgt neu:

How do I write code in C#, using only the TBS API, to interface with
an already owned and provisioned TPM to, without user interaction,
encrypt no more than 128 bytes of arbitrary data with an asymmetric
key already resident in the TPM and bound to it, but not protected
with a password, so that in order to decrypt the data the system may
need to be in the same state it was in at encryption time based on an
easily configurable variable?

Der Seal-Befehl ist hierfür am besten geeignet, da er dieselbe Funktion wie der Bind-Befehl ausführt, wenn die PCR-Auswahlgröße auf Null gesetzt ist. Die PCR-Auswahl kann jedoch leicht geändert werden, um alle gewünschten PCRs einzuschließen. Man wundert sich, warum der Bind-Befehl überhaupt in der Spezifikation enthalten war, und wie bereits erwähnt, wurde er in der TPM 2-Spezifikation entfernt und die beiden wurden in einem Create-Befehl kombiniert.

Hier ist der C # -Code für die Verwendung des TPM 1.2 Seal-Befehls zum Verschlüsseln von Daten nur mit TBS-Funktionen (Hinweis: Dieser Code ist nicht getestet und funktioniert wahrscheinlich nicht ohne Debugging) :

[DllImport ("tbs.dll")]
unsafe static extern UInt32 Tbsi_Context_Create (UInt32 * version, IntPtr * hContext);

[DllImport ("tbs.dll")]
unsafe static extern UInt32 Tbsip_Context_Close (IntPtr hContext);

[DllImport ("tbs.dll")]
unsafe static extern UInt32 Tbsip_Submit_Command (
    IntPtr hContext, UInt32 Locality, 
    UInt32 Priority, 
    byte * pCommandBuf, 
    UInt32 CommandBufLen, 
    byte * pResultBuf, 
    UInt32 * pResultBufLen);

byte[] ProtectBytes_TPM (byte[] plaintext) {

    void AddUInt32Reversed (byte[] a, System.UInt32 o, ref int i) {
        byte[] bytes = System.BitConverter.GetBytes (o);
        Array.Reverse (bytes);
        Array.Copy (bytes, 0, a, i, bytes.Length);
        i += bytes.Length;
    }
    void AddUInt16Reversed (byte[] a, System.UInt16 o, ref int i) {
        byte[] bytes = System.BitConverter.GetBytes (o);
        Array.Reverse (bytes);
        Array.Copy (bytes, 0, a, i, bytes.Length);
        i += bytes.Length;
    }
    void AddBool (byte[] a, byte b, ref int i) {
        a[i] = b;
        i += 1;
    }
    void AddBlob (byte[] a, byte[] b, ref int i) {
        Array.Copy (b, 0, a, i, b.Length);
        i += b.Length;
    }
    byte[] Xor (byte[] text, byte[] key) {
        byte[] xor = new byte[text.Length];
        for (int i = 0; i < text.Length; i++) {
            xor[i] = (byte) (text[i] ^ key[i % key.Length]);
        }
        return xor;
    }

    int offset;

    Random rnd = new Random ();

    IntPtr hContext = IntPtr.Zero;
    unsafe {
        UInt32 version = 1;
        IntPtr handle = hContext;
        UInt32 result = Tbsi_Context_Create ( & version, & handle);

        if (result == 0) {
            hContext = handle;
        }
    }

    byte[] cmdBuf = new byte[768];

    //OSAP
    System.UInt32 outSize;

    byte[] oddOsap = new byte[20];
    byte[] evenOsap = new byte[20];
    byte[] nonceEven = new byte[20];
    byte[] nonceOdd = new byte[20];
    System.UInt32 hAuth = 0;

    offset = 0;
    AddUInt16Reversed (cmdBuf, 0x00C1, ref offset);
    offset = 6;
    AddUInt32Reversed (cmdBuf, 0x0000000B, ref offset);

    offset = 2 + 4 + 4; //2 for tag, 4 for size and 4 for command code

    AddUInt16Reversed (cmdBuf, 0x0004, ref offset); //Entity Type SRK = 0x0004
    AddUInt32Reversed (cmdBuf, 0x40000000, ref offset); //Entity Value SRK = 0x40000000
    rnd.NextBytes (oddOsap);
    AddBlob (cmdBuf, oddOsap, ref offset);
    uint cmdSize = (System.UInt32) offset;
    offset = 2;
    AddUInt32Reversed (cmdBuf, cmdSize, ref offset);

    outSize = (System.UInt32) (Marshal.SizeOf (hAuth) + nonceEven.Length + evenOsap.Length);

    byte[] response = new byte[outSize];
    unsafe {
        UInt32 result = 0;

        //uint cmdSize = (uint)offset;
        uint resSize = outSize;
        fixed (byte * pCmd = cmdBuf, pRes = response) {
            result = Tbsip_Submit_Command (hContext, 0, 200, pCmd, cmdSize, pRes, & resSize);
        }
    }

    byte contSession = 0;
    System.UInt32 hKey = 0x40000000; //TPM_KH_SRK;
    System.UInt32 pcrInfoSize = 0;
    byte[] srkAuthdata = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    uint inDataSize = (uint) plaintext.Length;

    offset = 2 + 4 + 4; //2 for tag, 4 for size and 4 for return code
    byte[] hauthbytes = new byte[Marshal.SizeOf (hAuth)];
    Array.Copy (response, offset, hauthbytes, 0, hauthbytes.Length);
    Array.Reverse (hauthbytes);
    hAuth = System.BitConverter.ToUInt32 (hauthbytes, 0);
    offset += Marshal.SizeOf (hAuth);
    Array.Copy (response, offset, nonceEven, 0, nonceEven.Length);
    offset += nonceEven.Length;
    Array.Copy (response, offset, evenOsap, 0, evenOsap.Length);

    //shared-secret = HMAC(srk_auth, even_osap || odd_osap)
    byte[] sharedSecretBuf = new byte[evenOsap.Length + oddOsap.Length];
    Array.Copy (evenOsap, 0, sharedSecretBuf, 0, evenOsap.Length);
    Array.Copy (oddOsap, 0, sharedSecretBuf, evenOsap.Length, oddOsap.Length);
    System.Security.Cryptography.HMACSHA1 sharedSecretHmac = new System.Security.Cryptography.HMACSHA1 (srkAuthdata);
    byte[] sharedSecret = sharedSecretHmac.ComputeHash (sharedSecretBuf);

    byte[] authSha1InBuf = new byte[sharedSecret.Length + nonceEven.Length];
    Array.Copy (sharedSecret, 0, authSha1InBuf, 0, sharedSecret.Length);
    Array.Copy (nonceEven, 0, authSha1InBuf, sharedSecret.Length, nonceEven.Length);
    System.Security.Cryptography.SHA1Managed sha1 = new System.Security.Cryptography.SHA1Managed ();
    byte[] authSha1 = sha1.ComputeHash (authSha1InBuf);
    byte[] encAuth = Xor (srkAuthdata, authSha1);

    //inParamDigest = sha1(1S ~ 6S) 
    int paramInDigestInBufSize =
        sizeof (System.UInt32) + 
        encAuth.Length +
        Marshal.SizeOf (pcrInfoSize) +
        Marshal.SizeOf (inDataSize) +
        (int) inDataSize;
    byte[] paramInDigestInBuf = new byte[paramInDigestInBufSize];
    offset = 0;
    AddUInt32Reversed (paramInDigestInBuf, 0x00000017, ref offset);
    AddBlob (paramInDigestInBuf, encAuth, ref offset);
    AddUInt32Reversed (paramInDigestInBuf, 0x0, ref offset); //PCR info size
    AddUInt32Reversed (paramInDigestInBuf, inDataSize, ref offset);
    AddBlob (paramInDigestInBuf, plaintext, ref offset);

    byte[] paramInDigest = sha1.ComputeHash (paramInDigestInBuf);

    int pubAuthInBufSize = paramInDigest.Length + nonceEven.Length + nonceOdd.Length + Marshal.SizeOf (contSession);
    byte[] pubAuthInBuf = new byte[pubAuthInBufSize];

    offset = 0;
    AddBlob (pubAuthInBuf, paramInDigest, ref offset);
    AddBlob (pubAuthInBuf, nonceEven, ref offset);
    AddBlob (pubAuthInBuf, nonceOdd, ref offset);
    AddBool (pubAuthInBuf, contSession, ref offset);
    System.Security.Cryptography.HMACSHA1 pubAuthHmac = new System.Security.Cryptography.HMACSHA1 (sharedSecret);
    byte[] pubAuth = pubAuthHmac.ComputeHash (pubAuthInBuf);

    //Seal
    offset = 0;
    AddUInt16Reversed (cmdBuf, 0x00C2, ref offset); // TPM_TAG_RQU_AUTH1_COMMAND;
    offset = 6;
    AddUInt32Reversed (cmdBuf, 0x00000017, ref offset); // TPM_ORD_SEAL;
    offset = 2 + 4 + 4; //2 for tag, 4 for size and 4 for command code

    AddUInt32Reversed (cmdBuf, hKey, ref offset);
    AddBlob (cmdBuf, encAuth, ref offset);
    AddUInt32Reversed (cmdBuf, pcrInfoSize, ref offset);
    AddUInt32Reversed (cmdBuf, inDataSize, ref offset);
    AddBlob (cmdBuf, plaintext, ref offset);

    AddUInt32Reversed (cmdBuf, hAuth, ref offset);
    AddBlob (cmdBuf, nonceOdd, ref offset);
    AddBool (cmdBuf, contSession, ref offset);
    AddBlob (cmdBuf, pubAuth, ref offset);
    cmdSize = (System.UInt32) offset;
    offset = 2;
    AddUInt32Reversed (cmdBuf, cmdSize, ref offset);

    outSize = 768;
    uint responseSize = 0;

    response = new byte[outSize];
    unsafe {
        UInt32 result = 0;

        uint resSize = outSize;
        fixed (byte * pCmd = cmdBuf, pRes = response) {
            result = Tbsip_Submit_Command (hContext, 0, 200, pCmd, cmdSize, pRes, & resSize);
        }
        responseSize = resSize;
    }

    byte[] retBuffer = new byte[responseSize - 10];
    Array.Copy (response, 10, retBuffer, 0, retBuffer.Length);
    Tbsip_Context_Close (hContext);
    return retBuffer;

}

Code-Analyse:

[DllImport ("tbs.dll")]
...

Dies sind einige der wenigen Funktionen, die in Tbs.h verfügbar sind, und die einzigen, die wir hier verwenden werden. Sie ermöglichen es Ihnen grundsätzlich, ein Handle für das Gerät zu öffnen und mit ihm zu kommunizieren, indem Sie Rohbytes senden und empfangen.

    void AddUInt32Reversed (byte[] a, System.UInt32 o, ref int i) { ... }
    void AddUInt16Reversed (byte[] a, System.UInt16 o, ref int i) { ... }
    void AddBool (byte[] a, byte b, ref int i) { ... }
    void AddBlob (byte[] a, byte[] b, ref int i) { ... }

TPM ist Big Endian, Windows ist Little Endian. Daher muss die Bytereihenfolge für alle Daten, über die wir senden, umgekehrt werden. Wir müssen uns hier nur darum kümmern, 32-Bit- und 16-Bit-Ints ohne Vorzeichen umzukehren.

    ...
    UInt32 result = Tbsi_Context_Create ( & version, & handle);
    ...

Hier verwenden wir Tbsi_Context_Create () , um ein Handle zu öffnen, um mit dem TPM zu sprechen. Der TBS_CONTEXT_PARAMSParameter ist nur eine C-Struktur mit einem vorzeichenlosen 32-Bit-Int-Feld, das auf 1 gesetzt werden muss, um mit einer TPM 1.2-Instanz zu kommunizieren, und auf das, was wir gesetzt haben.

    byte[] cmdBuf = new byte[768];

Dies wird als Mindestpuffergröße in der TPM PC-Client- Spezifikation angegeben . Es wird mehr als genug für unsere Bedürfnisse hier sein.

In TPM 1.2 Spec Part 3 heißt es:

TPM_Seal requires the encryption of one parameter (“Secret”). For the
sake of uniformity with other commands that require the encryption of
more than one parameter, the string used for XOR encryption is
generated by concatenating a nonce (created during the OSAP session)
with the session shared secret and then hashing the result.

Wir müssen diesen "geheimen" Parameter mit einer Nonce, die während einer OSAP-Sitzung generiert wurde, XOR-verschlüsseln. Eines der Eingabe-Handles für Seal-Befehle ist auch ein OSAP-Handle:

The authorization session handle used for keyHandle authorization.
Must be an OSAP session for this command.

Wir müssen also zuerst diese OSAP-Sitzung einrichten. OSAP ist in TPM 1.2 Spec Part 1 beschrieben . OSAP oder Object-Specific Authorization Protocol wurde entwickelt, um den Anwendungsfall zu behandeln, bei dem Sie ein TPM-Objekt verwenden möchten, für das eine mehrfache Autorisierung erforderlich ist, das jedoch nicht jedes Mal autorisiert werden soll: Stattdessen wird eine OSAP-Sitzung verwendet, die sich darauf stützt über das Konzept des "geteilten Geheimnisses", das ein HMAC ist , in dem die Objektautorisierungsdaten mit auf jeder Seite generierten Nonces gemischt werden, um Antwortangriffe zu verhindern. Daher ist das "gemeinsame Geheimnis" nur den beiden Seiten in dieser Sitzung bekannt: der Seite, die die Sitzung initiiert hat (Benutzer) und der Seite, die sie akzeptiert hat (TPM); Außerdem müssen beide Seiten dieselben Objektautorisierungsdaten haben, damit das "gemeinsame Geheimnis" identisch ist. Außerdem ist das in einer Sitzung verwendete "gemeinsame Geheimnis" in einer anderen Sitzung ungültig. Dieses Diagramm aus der Spezifikation beschreibt den Prozess:

OSAP

In diesem speziellen Fall werden nicht mehrere Sitzungen verwendet (tatsächlich wird dieser Parameter mit dem Befehl Seal ignoriert!), Und der Schlüssel, den wir verwenden, erfordert keine Autorisierung, aber leider sind wir immer noch an die Spezifikation gebunden, um ein OSAP einzurichten Session.

    offset = 0;
    AddUInt16Reversed (cmdBuf, 0x00C1, ref offset);
    offset = 6;
    AddUInt32Reversed (cmdBuf, 0x0000000B, ref offset);

    offset = 2 + 4 + 4; //2 for tag, 4 for size and 4 for command code

    AddUInt16Reversed (cmdBuf, 0x0004, ref offset); //Entity Type SRK = 0x0004
    AddUInt32Reversed (cmdBuf, 0x40000000, ref offset); //Entity Value SRK = 0x40000000
    rnd.NextBytes (oddOsap);
    AddBlob (cmdBuf, oddOsap, ref offset);
    uint cmdSize = (System.UInt32) offset;

TPM_OSAP-Befehlsoperanden sind:

TPM_OSAP-Operanden

Jeder TPM 1.2-Befehl ist wie folgt aufgebaut:

  2 bytes       4 bytes             4 bytes
+---------+------------------+------------------+---------------------------
|   Tag   |       Size       |   Command code   |    Command body    ....
+---------+------------------+------------------+---------------------------

Das Tag ist ein Zwei-Byte-Wert, der angibt, ob das Folgende entweder eingegeben oder ausgegeben wird und ob nach den Befehlsparametern Authentifizierungsdatenwerte vorhanden sind. Für TPM_OSAP muss das Tag gemäß der Spezifikation TPM_TAG_RQU_COMMAND (0x00C1) sein, was "ein Befehl ohne Berechtigung" bedeutet.

Größe ist ein Vier-Byte-Wert, der die Größe des Befehls in Byte angibt, einschließlich des Tags und der Größe selbst. Wir werden diesen Wert später einstellen, sobald wir ihn berechnet haben.

Befehlscode ist ein Vier-Byte-Wert, den Server als Befehls-ID verwenden: Er teilt dem TPM mit, wie der Rest des Befehls zu interpretieren ist. Unser Befehlscode hier ist TPM_OSAP (0x0000000B).

Die nächsten beiden Dinge, die festgelegt werden müssen, sind Entitätstyp und Entitätswert. Da wir einen Schlüssel verwenden möchten, der bereits im TPM vorhanden ist, verwenden wir den Entitätstyp "SRK" (0x0004). Da wir davon ausgehen, dass das TPM bereits im Besitz ist, können wir davon ausgehen, dass dies der Fall ist Ein SRK, das gemäß der Spezifikation unter dem permanenten Handle 0x40000000 geladen wurde, sodass wir diesen permanenten Handle-Wert für unseren Entitätswert verwenden. (SRK steht für "Storage Root Key" und ist der Root-Schlüssel, von dem die meisten anderen TPM-eigenen Schlüssel abgeleitet sind.)

    result = Tbsip_Submit_Command (hContext, 0, 200, pCmd, cmdSize, pRes, & resSize);

Schließlich berechnen wir die Befehlsgröße und legen sie fest und senden den Befehl.

    offset = 2 + 4 + 4; //2 for tag, 4 for size and 4 for return code
    byte[] hauthbytes = new byte[Marshal.SizeOf (hAuth)];
    Array.Copy (response, offset, hauthbytes, 0, hauthbytes.Length);
    Array.Reverse (hauthbytes);
    hAuth = System.BitConverter.ToUInt32 (hauthbytes, 0);
    offset += Marshal.SizeOf (hAuth);
    Array.Copy (response, offset, nonceEven, 0, nonceEven.Length);
    offset += nonceEven.Length;
    Array.Copy (response, offset, evenOsap, 0, evenOsap.Length);

Die Daten, die wir vom TPM auf TPM_OSAP zurückerhalten sollen, sind:

TPM_OSAP-Antwort

Also kommen wir zurück:

  • Das Autorisierungshandle zur Verwendung mit unserem Hauptbefehl (Siegel)
  • nonceEven: Die vom TPM generierte Nonce zur Verwendung mit dem Hauptbefehl
  • nonceEvenOSAP: Die OSAP-Nonce, die die Gegen-Nonce zu der Nonce ist, die wir vor dem Senden des Befehls TPM_OSAP auf unserer Seite generiert haben. Diese beiden Nonces werden zur Erzeugung des "gemeinsamen Geheimnisses" verwendet.

Wir extrahieren diese Werte und speichern sie in Variablen.

    byte[] sharedSecretBuf = new byte[evenOsap.Length + oddOsap.Length];
    Array.Copy (evenOsap, 0, sharedSecretBuf, 0, evenOsap.Length);
    Array.Copy (oddOsap, 0, sharedSecretBuf, evenOsap.Length, oddOsap.Length);
    System.Security.Cryptography.HMACSHA1 sharedSecretHmac = new System.Security.Cryptography.HMACSHA1 (srkAuthdata);
    byte[] sharedSecret = sharedSecretHmac.ComputeHash (sharedSecretBuf);

Dann berechnen wir das "gemeinsame Geheimnis". Gemäß der Spezifikation sind die Werte, die in die Berechnung einfließen, die beiden OSAP-Nonces (eine vom Benutzer und eine vom TPM generiert) und der Berechtigungswert für den Schlüssel, den wir verwenden möchten - das SRK. Konventionell ist der SRK-Authentifizierungswert die "bekannte Authentifizierung": ein auf Null ausgelöster 20-Byte-Puffer. Technisch gesehen könnte man diesen Wert in etwas anderes ändern, wenn man das TPM übernimmt, aber dies wird in der Praxis nicht durchgeführt, so dass wir sicher davon ausgehen können, dass der "bekannte Auth" -Wert gut ist.

Schauen wir uns als nächstes an, was im Befehl TPM_Seal enthalten ist:

TPM_Seal

Die meisten dieser Parameter sind trivial zu erstellen, mit Ausnahme von zwei: encAuthund pubAuth. Schauen wir sie uns einzeln an.

encAuthist "Die verschlüsselten AuthData für die versiegelten Daten." Unsere AuthData hier ist die "bekannte Auth" von früher, aber ja, wir müssen sie noch verschlüsseln. Da wir eine OSAP-Sitzung verwenden, wird diese nach ADIP oder Authorization-Data Insertion Protocol verschlüsselt. Aus der Spezifikation: "Das ADIP ermöglicht die Erstellung neuer Entitäten und das sichere Einfügen der neuen Entität AuthData. Die Übertragung der neuen AuthData verwendet die Verschlüsselung mit dem Schlüssel basierend auf dem gemeinsamen Geheimnis einer OSAP-Sitzung." Zusätzlich: "Für den obligatorischen XOR-Verschlüsselungsalgorithmus erstellt der Ersteller einen Verschlüsselungsschlüssel unter Verwendung eines SHA-1-Hash des gemeinsam genutzten OSAP-Geheimnisses und einer Sitzungs-Nonce. Der Ersteller XOR verschlüsselt die neuen AuthData unter Verwendung des Verschlüsselungsschlüssels als einmaliges Pad und sendet diese verschlüsselten Daten zusammen mit der Erstellungsanforderung an das TPM. "

Das folgende Diagramm erläutert die Funktionsweise von ADIP:

EIN DIP

pubAuthist "Der Digest der Autorisierungssitzung für Eingaben und keyHandle". Teil 1 der Spezifikation in "Parameterdeklarationen für OIAP- und OSAP-Beispiele" erläutert die Interpretation der obigen TPM_Seal-Parametertabelle: "In der Spalte HMAC # sind die in der HMAC-Berechnung verwendeten Parameter aufgeführt. Die Parameter 1S, 2S usw. sind verkettet und Hash zu inParamDigest oder outParamDigest, implizit 1H1 und möglicherweise 1H2 genannt, wenn zwei Autorisierungssitzungen vorhanden sind. Für die erste Sitzung werden 1H1, 2H1, 3H1 und 4H1 verkettet und HMAC'ed. Für die zweite Sitzung 1H2, 2H2, 3H2, und 4H2 sind verkettet und HMAC'ed. " Also müssen wir den Klartext, seine Größe, die Größe der PCR-Informationen encAuthvon oben und die TPM_Seal-Ordnungszahl und dann die HMAC, die mit den beiden Nonces und dem Booleschen Wert "Sitzung fortsetzen" unter Verwendung des OSAP "hasht.

Alles in einem Diagramm zusammenfassen:

pubAuth-Berechnung

Beachten Sie, wie wir "PCR-Info-Größe" in diesem Code auf Null setzen, da wir die Daten nur verschlüsseln möchten, ohne sie an einen Systemstatus zu binden. Es ist jedoch trivial, bei Bedarf eine "PCR-Info" -Struktur bereitzustellen.

    offset = 0;
    AddUInt16Reversed (cmdBuf, 0x00C2, ref offset); 
    offset = 6;
    AddUInt32Reversed (cmdBuf, 0x00000017, ref offset); // TPM_ORD_SEAL;
    ...
    result = Tbsip_Submit_Command (hContext, 0, 200, pCmd, cmdSize, pRes, & resSize);

Schließlich konstruieren wir den Befehl und senden ihn.

    byte[] retBuffer = new byte[responseSize - 10];
    Array.Copy (response, 10, retBuffer, 0, retBuffer.Length);
    Tbsip_Context_Close (hContext);
    return retBuffer;

Wir verwenden die Funktion Tbsip_Context_Close () , um unser Kommunikationshandle zu schließen.

Wir geben die Antwort so wie sie ist zurück. Idealerweise möchten Sie die Bytes erneut umkehren und validieren, indem Sie den resAuthWert neu berechnen, um Man-in-the-Middle-Angriffe zu verhindern.


Was verwirrend ist, ist, dass es keinen Tspi_Data_Bind-Befehl gibt.

Dies liegt daran, dass Tspi_Data_Bind ein TSS-Befehl und kein TPM-Befehl ist. Der Grund dafür ist, dass keine Geheimnisse erforderlich sind (nur der öffentliche Schlüssel wird verwendet), sodass dies ohne Beteiligung des TPM möglich ist. Dies führte jedoch zu Verwirrung, und selbst die Befehle, für die keine Geheimnisse erforderlich sind, sind jetzt in der TPM 2-Spezifikation enthalten.

Wie kann ich einen Schlüssel mit dem öffentlichen Schlüssel des TPM verschlüsseln?

Hängt von der TPM-Version ab. Mit dem Befehl TPM_CreateWrapKey für TPM 1.2. Mit dem Befehl TPM2_Create für TPM 2.

Wie sperrt ein Entwickler einen Schlüssel für das TPM?

Erstellen Sie es entweder im TPM oder verpacken Sie es oder verwenden Sie eine andere der verfügbaren Methoden.

TPM2_Create, Angabe eines HMAC-Schlüssels

Der Text im Buch ist verwirrend. Sie geben den HMAC-Schlüssel nicht an, sondern geben an , dass Sie einen HMAC-Schlüssel wünschen .

Die Tatsache, dass der HMAC-Schlüssel nicht geheim ist, macht Sinn

Nein, es macht keinen Sinn. Der Schlüssel ist geheim.

... Schlüssel verwenden, während sie in einem Hardwaregerät sicher aufbewahrt werden ... Ausgezeichnet! Wie machst du das!?

Es gibt Befehle zum Erstellen oder Importieren von Schlüsseln für beide TPM-Versionen. Für TPM 1 gab es nur einen Stammschlüssel - den SRK - aus dem Sie eine Schlüsselhierarchie erstellen konnten, indem Sie umschlossene Schlüssel erstellen. Mit TPM 2 können Sie mehrere Primär- oder Root-Schlüssel haben.

Kann das TPM kryptografische Schlüssel generieren und seine Geheimnisse innerhalb einer Hardwaregrenze schützen? Ist so, wie?

Siehe oben.

Ausgezeichnet! Dies ist genau der Anwendungsfall, den ich zufällig möchte. Dies ist auch der Anwendungsfall, für den Microsoft das TPM verwendet. Wie mache ich es!?

Hängt wahrscheinlich vom Typ des Laufwerks ab. Bei Nicht-SED-Laufwerken ist der Laufwerkverschlüsselungsschlüssel wahrscheinlich mit einem TPM-Schlüssel umwickelt. Bei SED-Laufwerken ist das Admin1-Kennwort (oder ein solches Kennwort) mit dem TPM versiegelt.

Der Endorsement Key oder EK ... Irgendwo im TPM befindet sich ein privater RSA-Schlüssel. Dieser Schlüssel ist dort eingesperrt - von der Außenwelt nie zu sehen. Ich möchte, dass das TPM etwas mit seinem privaten Schlüssel signiert (dh es mit seinem privaten Schlüssel verschlüsselt).

Der EK ist kein Signaturschlüssel, sondern ein Verschlüsselungsschlüssel. Es handelt sich jedoch nicht um einen allgemeinen Verschlüsselungsschlüssel, sondern kann nur in bestimmten Kontexten verwendet werden .

Aber das, was ich wirklich tun möchte, ist, einige Daten zu "versiegeln"

Siehe oben.

mnistisch
quelle
2

Wenn es heißt

Angabe des HMAC-Schlüssels

Dies bedeutet NICHT, dass Sie den HMAC-Schlüssel bereitstellen müssen. Es bedeutet, dass Sie auf den HMAC-Schlüssel zeigen, den Sie verwenden möchten .

TPMs können eine praktisch unbegrenzte Anzahl von HMAC-Schlüsseln verwenden, wie im Buch ausgeführt. Sie müssen dem TPM mitteilen, welches verwendet werden soll.

DCC
quelle
Gibt es also vielleicht ein Codebeispiel, das zeigt, wie der in C # oder einer anderen Sprache zu verwendende HMAC-Schlüssel angegeben wird (darauf zeigt)?
Chad