Formato de armazenamento de chaves no ASP.NET Core

Os objetos são armazenados em repouso na representação XML. O diretório padrão para armazenamento de chaves é:

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

O elemento <chave>

As chaves existem como objetos de nível superior no repositório de chaves. Por convenção, as chaves tem o nome de arquivo key-{guid}.xml, em que {guid} é a ID da chave. Cada arquivo desse tipo contém uma única chave. O formato do arquivo é o seguinte:

<?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>

O elemento <chave> contém os seguintes atributos e elementos filho:

  • A ID da chave. Esse valor é tratado como autoritativo. O nome do arquivo é simplesmente uma boa origem para a legibilidade humana.

  • A versão do elemento <chave>, atualmente fixada em 1.

  • As datas de criação, ativação e expiração da chave.

  • Um elemento <descritor>, que contém informações sobre a implementação de criptografia autenticada contida nessa chave.

No exemplo acima, a ID da chave é {80732141-ec8f-4b80-af9c-c4d2d1ff8901}, foi criada e ativada em 19 de março de 2015 e tem um tempo de vida de 90 dias. (Ocasionalmente, a data de ativação pode ser um pouco antes da data de criação, como nesse exemplo. Isso ocorre devido a um nit em como as APIs funcionam e são inofensivas na prática.)

O elemento <descritor>

O elemento de <descritor> externo contém um atributo deserializerType, que é o nome qualificado por assembly de um tipo que implementa IAuthenticatedEncryptorDescriptorDeserializer. Esse tipo é responsável por ler o elemento <descritor> interno e por analisar as informações contidas dentro.

O formato específico do <elemento descritor> depende da implementação do criptografador autenticado encapsulada pela chave e cada tipo de desserializador espera um formato ligeiramente diferente para isso. Em geral, porém, esse elemento conterá informações algorítmicas (nomes, tipos, OIDs ou similares) e material de chave secreta. No exemplo acima, o descritor especifica que essa chave encapsula a criptografia AES-256-CBC + validação HMACSHA256.

O elemento <encryptedSecret>

Um elemento <encryptedSecret> que contém a forma criptografada do material da chave secreta pode estar presente se a criptografia de segredos em repouso estiver habilitada. O atributo decryptorType é o nome qualificado por assembly de um tipo que implementa IXmlDecryptor. Esse tipo é responsável por ler o elemento <encryptedKey> interno e descriptografá-lo para recuperar o texto não criptografado original.

Assim como acontece com <descriptor>, o formato específico do elemento <encryptedSecret> depende do mecanismo de criptografia em repouso em uso. No exemplo acima, a chave mestra é criptografada usando o DPAPI do Windows de acordo com o comentário.

O elemento de <revogação>

As revogações existem como objetos de nível superior no repositório de chaves. Por convenção, as revogações têm o nome de arquivo revocation-{timestamp}.xml (para revogar todas as chaves antes de uma data específica) ou revocation-{guid}.xml (para revogar uma chave específica). Cada arquivo contém um único elemento de <revogação> .

Para revogações de chaves individuais, o conteúdo do arquivo será conforme mostrado abaixo.

<?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>

Nesse caso, somente a chave especificada é revogada. No entanto, se a ID da chave for "*", como no exemplo abaixo, todas as chaves cuja data de criação seja anterior à data de revogação especificada serão revogadas.

<?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>

O elemento <razão> nunca é lido pelo sistema. É simplesmente um lugar conveniente para armazenar uma razão legível para revogação.