Schlüsselspeicherformat in ASP.NET Core

Ruhende Objekte werden in XML-Darstellung gespeichert. Das Standardverzeichnis für die Speicherung von Schlüsseln lautet wie folgt:

  • Windows: *%LOCALAPPDATA%\ASP.NET\DataProtection-Keys*
  • macOS/Linux: $HOME/.aspnet/DataProtection-Keys

Das <key>-Element

Schlüssel liegen als Objekte der obersten Ebene im Schlüsselrepository vor. Gemäß Konvention weisen Schlüssel den Dateinamen key-{guid}.xml auf, wobei {guid} für die ID des Schlüssels steht. Jede solche Datei enthält einen einzelnen Schlüssel. Das Format der Datei lautet wie folgt.

<?xml version="1.0" encoding="utf-8"?>
<key id="80732141-ec8f-4b80-af9c-c4d2d1ff8901" version="1">
  <creationDate>2015-03-19T23:32:02.3949887Z</creationDate>
  <activationDate>2015-03-19T23:32:02.3839429Z</activationDate>
  <expirationDate>2015-06-17T23:32:02.3839429Z</expirationDate>
  <descriptor deserializerType="{deserializerType}">
    <descriptor>
      <encryption algorithm="AES_256_CBC" />
      <validation algorithm="HMACSHA256" />
      <enc:encryptedSecret decryptorType="{decryptorType}" xmlns:enc="...">
        <encryptedKey>
          <!-- This key is encrypted with Windows DPAPI. -->
          <value>AQAAANCM...8/zeP8lcwAg==</value>
        </encryptedKey>
      </enc:encryptedSecret>
    </descriptor>
  </descriptor>
</key>

Das <key>-Element enthält die folgenden Attribute und untergeordneten Elemente:

  • Die Schlüssel-ID. Dieser Wert wird als autoritativ betrachtet. Der Dateiname wird nur aus Gründen der Lesbarkeit angegeben.

  • Die Version des <Key>-Elements, die derzeit auf 1 festgelegt ist.

  • Das Erstellungs-, Aktivierungs- und Ablaufdatum des Schlüssels.

  • Ein <descriptor>-Element, das Informationen zur authentifizierten Verschlüsselungsimplementierung enthält, die in diesem Schlüssel enthalten ist.

Im obigen Beispiel lautet die ID des Schlüssels {80732141-ec8f-4b80-af9c-c4d2d1ff8901}, er wurde am 19. März 2015 erstellt und aktiviert und hat eine Lebensdauer von 90 Tagen. (Gelegentlich kann es vorkommen, dass das Aktivierungsdatum geringfügig vor dem Erstellungsdatum liegt, wie in diesem Beispiel. Das liegt an einem Fehler in der Funktionsweise der APIs und hat in der Praxis keine Folgen.)

Das <descriptor>-Element

Das äußere <descriptor>-Element enthält ein deserializerType-Attribut, bei dem es sich um den Namen mit Assemblyqualifikation eines Typs handelt, der IAuthenticatedEncryptorDescriptorDeserializer implementiert. Dieser Typ ist für das Lesen des inneren <descriptor>-Elements und für das Parsen der darin enthaltenen Informationen zuständig.

Das jeweilige Format des <descriptor>-Elements hängt von der durch den Schlüssel gekapselten authentifizierten Verschlüsselungsimplementierung ab, und jeder Deserialisierertyp erwartet hierfür ein etwas anderes Format. Im Allgemeinen enthält dieses Element jedoch Informationen zum Algorithmus (Namen, Typen, OIDs oder ähnliches) und geheimes Schlüsselmaterial. Im obigen Beispiel gibt der Deskriptor an, dass dieser Schlüssel eine AES-256-CBC-Verschlüsselung + HMACSHA256-Validierung umschließt.

Das <encryptedSecret>-Element

Ein <encryptedSecret>-Element, das die verschlüsselte Form des geheimen Schlüsselmaterials enthält, kann vorhanden sein, wenn die Verschlüsselung von Geheimnissen im Ruhezustand aktiviert ist. Das Attribut decryptorType ist der Name mit Assemblyqualifikation eines Typs, der IXmlDecryptor implementiert. Dieser Typ ist dafür verantwortlich, das innere <encryptedKey>-Element zu lesen und es zu entschlüsseln, um den ursprünglichen Klartext wiederherzustellen.

Wie bei <descriptor> hängt das jeweilige Format des <encryptedSecret>-Elements vom verwendeten Verschlüsselungsmechanismus im Ruhezustand ab. Im obigen Beispiel wird der Hauptschlüssel mit Windows DPAPI verschlüsselt, wie im Kommentar angegeben.

Das <revocation>-Element

Sperrungen liegen als Objekte der obersten Ebene im Schlüsselrepository vor. Gemäß Konvention weisen Sperrungen den Dateinamen revocation-{timestamp}.xml (für den Widerruf aller Schlüssel vor einem bestimmten Datum) oder revocation-{guid}.xml (für den Widerruf eines bestimmten Schlüssels) auf. Jede Datei enthält ein einzelnes <revocation>-Element.

Bei Sperrungen einzelner Schlüssel lautet der Dateiinhalt wie folgt.

<?xml version="1.0" encoding="utf-8"?>
<revocation version="1">
  <revocationDate>2015-03-20T22:45:30.2616742Z</revocationDate>
  <key id="eb4fc299-8808-409d-8a34-23fc83d026c9" />
  <reason>human-readable reason</reason>
</revocation>

In diesem Fall wird nur der angegebene Schlüssel widerrufen. Wenn die Schlüssel-ID jedoch (wie im folgenden Beispiel) „*“ lautet, werden alle Schlüssel widerrufen, deren Erstellungsdatum vor dem angegebenen Sperrdatum liegt.

<?xml version="1.0" encoding="utf-8"?>
<revocation version="1">
  <revocationDate>2015-03-20T15:45:45.7366491-07:00</revocationDate>
  <!-- All keys created before the revocation date are revoked. -->
  <key id="*" />
  <reason>human-readable reason</reason>
</revocation>

Das <reason>-Element wird nie vom System gelesen. Es ist einfach ein praktischer Ort, um einen für Menschen lesbaren Grund für den Widerruf zu speichern.