AEAD de streaming AES-GCM-HKDF

Neste documento, definimos formalmente a função matemática representada pelas chaves de streaming AES-GCM-HKDF, codificadas no formato proto como type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey.

Essa criptografia é vagamente baseada no HRRV151. Para análise de segurança, nos referimos ao HS202.

Chave e parâmetros

As chaves são descritas pelas seguintes partes (todos os tamanhos neste documento estão em bytes):

  • \(\mathrm{KeyValue}\), uma string de bytes.
  • \(\mathrm{CiphertextSegmentSize} \in \{1, 2, \ldots, 2^{31}-1\}\).
  • \(\mathrm{DerivedKeySize} \in \{16, 32\}\).
  • \(\mathrm{HkdfHashType} \in \{\mathrm{SHA1}, \mathrm{SHA256}, \mathrm{SHA512}\}\).

As chaves válidas também satisfazem as seguintes propriedades:

  • \(\mathrm{len}(\mathrm{KeyValue}) \geq \mathrm{DerivedKeySize}\).
  • \(\mathrm{CiphertextSegmentSize} > \mathrm{DerivedKeySize} + 24\) (isso é igual a \(\mathrm{len}(\mathrm{Header}) + 16\) , conforme explicado mais adiante).

As chaves que não atendem a nenhuma dessas propriedades são rejeitadas pela Tink quando a chave é analisada ou quando o primitivo correspondente é criado.

Função de criptografia

Para criptografar uma mensagem \(\mathrm{Msg}\) com dados associados \(\mathrm{AssociatedData}\), criamos um cabeçalho, dividimos a mensagem em segmentos, criptografamos cada um e concatenamos os segmentos criptografados.

Criar o cabeçalho

Escolhemos uma string aleatória uniforme \(\mathrm{Salt}\) de comprimento\(\mathrm{DerivedKeySize}\) e uma string aleatória uniforme \(\mathrm{NoncePrefix}\)de comprimento 7.

Em seguida, definimos \(\mathrm{Header} := \mathrm{len}(\mathrm{Header}) \| \mathrm{Salt} \| \mathrm{NoncePrefix}\), em que o comprimento do cabeçalho é codificado como um único byte. Observe que \(\mathrm{len}(\mathrm{Header}) \in \{24, 40\}\).

Em seguida, usamos HKDF3 com a função hash fornecida por \(\mathrm{HkdfHashType}\) e entradas \(\mathrm{ikm} := \mathrm{KeyValue}\), \(\mathrm{salt} := \mathrm{Salt}\)e \(\mathrm{info} := \mathrm{AssociatedData}\), com comprimento de saída \(\mathrm{DerivedKeySize}\). Chamamos o resultado de \(\mathrm{DerivedKey}\).

Dividir a mensagem

A mensagem \(\mathrm{Msg}\) é dividida em partes: \(\mathrm{Msg} = M_0 \| M_1 \| \cdots \| M_{n-1}\).

Os comprimentos são escolhidos para satisfazer:

  • \(\mathrm{len}(M_0) \in \{0,\ldots, \mathrm{CiphertextSegmentSize} - \mathrm{len}(\mathrm{Header}) - \mathrm{16}\}\).
  • Se \(n>1\), então \(\mathrm{len}(M_1), \ldots, \mathrm{len}(M_{n-1}) \in \{1,\ldots, \mathrm{CiphertextSegmentSize} - \mathrm{16}\}\).
  • Se for \(n>1\), então \(\mathrm{len}(M_{0}), \ldots, \mathrm{len}(M_{n-2})\) precisará ter um comprimento máximo de acordo com o que foi descrito acima para as restrições.

\(n\) pode ser no máximo \(2^{32}\). Caso contrário, a criptografia vai falhar.

Criptografar os blocos

Para criptografar o segmento \(M_i\), calculamos \(\mathrm{IV}_i := \mathrm{NoncePrefix} \| \mathrm{i} \| b\), em que \(\mathrm{i}\) é 4 bytes na codificação big-endian e o byte $b$ é 0x00 se $i < n-1$ e 0x01, caso contrário.

Em seguida, criptografamos \(M_i\) usando AES-GCM4, em que a chave é \(\mathrm{DerivedKey}\), o vetor de inicialização é \(\mathrm{IV}_i\)e os dados associados são a string vazia. \(C_i\) é o resultado dessa criptografia (ou seja, a concatenação de \(C\) e \(T\) na seção 5.2.1.2 da referência de AES-GCM vinculada).

Concatenar os segmentos criptografados

Por fim, todos os segmentos são concatenados como \(\mathrm{Header} \| C_0 \| \cdots \| C_{n-1}\), que é o texto criptografado final.

Descriptografia

A descriptografia inverte a criptografia. Usamos o cabeçalho para obter \mathrm{NoncePrefix}$$ e descriptografamos cada segmento do texto criptografado individualmente.

As APIs podem (e normalmente permitem) acesso aleatório ou acesso ao início de um arquivo sem inspecionar o final dele. Isso é intencional, já que é possível descriptografar \(M_i\) de \(C_i\)sem descriptografar todos os blocos de texto cifrado anteriores e restantes.

No entanto, as APIs precisam ter cuidado para não permitir que os usuários confundam erros de fim de arquivo e descriptografia: em ambos os casos, a API provavelmente precisa retornar um erro, e ignorar a diferença pode fazer com que um invasor consiga truncar os arquivos de maneira eficaz.

Serialização e análise de chaves

Para serializar uma chave no formato "Tink Proto", primeiro mapeamos os parâmetros da maneira óbvia no proto fornecido em aes_gcm_hkdf_streaming.proto. O campo version precisa ser definido como 0. Em seguida, serializamos isso usando a serialização proto normal e incorporamos a string resultante no valor de campo de um proto KeyData. Definimos o campo type_url como type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey. Em seguida, definimos key_material_type como SYMMETRIC e o incorporamos a um conjunto de chaves. Geralmente, definimos output_prefix_type como RAW. A exceção é que, se a chave for analisada com um valor diferente definido para output_prefix_type, o Tink poderá gravar RAW ou o valor anterior.

Para analisar uma chave, revertemos o processo acima (da maneira normal ao analisar protos). O campo key_material_type será ignorado. O valor de output_prefix_type pode ser ignorado, ou as chaves com output_prefix_type diferente de RAW podem ser rejeitadas. As chaves com um version diferente de 0 precisam ser rejeitadas.

Problemas conhecidos

Não é esperado que as implementações da função de criptografia acima sejam seguras contra ramificações. Consulte Segurança de bifurcação.

Referências


  1. Hoang, Reyhanitabar, Rogaway, Vizar, 2015. Criptografia autenticada on-line e a resistência ao uso indevido de reutilização de valor de uso único. CRYPTO 2015. https://eprint.iacr.org/2015/189 

  2. Hoang, Shen, 2020. Segurança da criptografia de streaming na biblioteca Tink do Google. https://eprint.iacr.org/2020/1019 

  3. RFC 5869. Função de derivação de chaves de extração e expansão (HKDF, na sigla em inglês) baseada em HMAC (em inglês). https://www.rfc-editor.org/rfc/rfc5869 

  4. NIST SP 800-38D Recomendação para modos de operação de criptografia em bloco: modo Galois/Counter Mode (GCM) e GMAC. https://csrc.nist.gov/pubs/sp/800/38/d/final