Esta tradução foi gerada usando aprendizado de máquina e pode não ser 100% precisa. Ver versão em inglês

PQ Hybrid NTCP2

Variante híbrida pós-quântica do protocolo de transporte NTCP2 usando ML-KEM

Estado

Beta Q1 2026, lançamento Q2 2026

Visão Geral

Esta é a variante pós-quântica híbrida do protocolo de transporte NTCP2, conforme projetado na Proposta 169. Consulte essa proposta para informações adicionais de contexto.

PQ Hybrid NTCP2 está definido apenas no mesmo endereço e porta que o NTCP2 padrão. A operação em uma porta diferente, ou sem suporte ao NTCP2 padrão, não é permitida, e não será por vários anos, quando o NTCP2 padrão for descontinuado.

Esta especificação documenta apenas as mudanças necessárias ao NTCP2 padrão para suportar PQ Hybrid. Consulte a especificação NTCP2 para os detalhes de implementação base.

Design

Nós suportamos os padrões NIST FIPS 203 e 204 FIPS 203 FIPS 204 que são baseados em, mas NÃO compatíveis com, CRYSTALS-Kyber e CRYSTALS-Dilithium (versões 3.1, 3 e anteriores).

Troca de Chaves

PQ KEM fornece apenas chaves efêmeras e não suporta diretamente handshakes de chave estática como Noise XK e IK. Os tipos de criptografia são os mesmos usados no PQ Hybrid Ratchet e são definidos no documento de estruturas comuns /docs/specs/common-structures/ , como em FIPS 203 . Tipos híbridos são definidos apenas em combinação com X25519.

Os tipos de criptografia são:

TipoCódigo
MLKEM512_X255195
MLKEM768_X255196
MLKEM1024_X255197

Combinações Legais

Os novos tipos de criptografia são indicados nos RouterAddresses. O tipo de criptografia no certificado de chave continuará sendo tipo 4.

Especificação

Padrões de Handshake

Os handshakes usam padrões de handshake do Noise Protocol .

O seguinte mapeamento de letras é usado:

  • e = chave efêmera de uso único
  • s = chave estática
  • p = carga útil da mensagem
  • e1 = chave PQ efêmera de uso único, enviada de Alice para Bob
  • ekem1 = o texto cifrado KEM, enviado de Bob para Alice

As seguintes modificações ao XK e IK para sigilo progressivo híbrido (hfs) são conforme especificado na especificação Noise HFS seção 5:

XK:                       XKhfs:
  <- s                      <- s
  ...                       ...
  -> e, es, p               -> e, es, e1, p
  <- e, ee, p               <- e, ee, ekem1, p
  -> s, se                  -> s, se
  <- p                      <- p
  p ->                      p ->


  e1 and ekem1 are encrypted. See pattern definitions below.
  NOTE: e1 and ekem1 are different sizes (unlike X25519)

O padrão e1 é definido da seguinte forma, conforme especificado na seção 4 da especificação Noise HFS :

For Alice:
  (encap_key, decap_key) = PQ_KEYGEN()

  // EncryptAndHash(encap_key)
  ciphertext = ENCRYPT(k, n, encap_key, ad)
  n++
  MixHash(ciphertext)

  For Bob:

  // DecryptAndHash(ciphertext)
  encap_key = DECRYPT(k, n, ciphertext, ad)
  n++
  MixHash(ciphertext)

O padrão ekem1 é definido da seguinte forma, conforme especificado na seção 4 da especificação Noise HFS :

For Bob:

  (kem_ciphertext, kem_shared_key) = ENCAPS(encap_key)

  // EncryptAndHash(kem_ciphertext)
  ciphertext = ENCRYPT(k, n, kem_ciphertext, ad)
  MixHash(ciphertext)

  // MixKey
  MixKey(kem_shared_key)


  For Alice:

  // DecryptAndHash(ciphertext)
  kem_ciphertext = DECRYPT(k, n, ciphertext, ad)
  MixHash(ciphertext)

  // MixKey
  kem_shared_key = DECAPS(kem_ciphertext, decap_key)
  MixKey(kem_shared_key)

KDF de Handshake Noise

Visão Geral

O handshake híbrido está definido na especificação Noise HFS . A primeira mensagem, de Alice para Bob, contém e1, a chave de encapsulamento, antes da carga útil da mensagem. Isso é tratado como uma chave estática adicional; chame EncryptAndHash() nela (como Alice) ou DecryptAndHash() (como Bob). Em seguida, processe a carga útil da mensagem normalmente.

A segunda mensagem, de Bob para Alice, contém ekem1, o texto cifrado, antes da carga útil da mensagem. Isso é tratado como uma chave estática adicional; chame EncryptAndHash() nela (como Bob) ou DecryptAndHash() (como Alice). Em seguida, calcule a kem_shared_key e chame MixKey(kem_shared_key). Depois processe a carga útil da mensagem como de costume.

Operações ML-KEM Definidas

Definimos as seguintes funções correspondentes aos blocos de construção criptográficos utilizados conforme definido em FIPS 203 .

(encap_key, decap_key) = PQ_KEYGEN()

Alice creates the encapsulation and decapsulation keys
The encapsulation key is sent in message 1.
encap_key and decap_key sizes vary based on ML-KEM variant.

(ciphertext, kem_shared_key) = ENCAPS(encap_key)

Bob calculates the ciphertext and shared key,
using the ciphertext received in message 1.
The ciphertext is sent in message 2.
ciphertext size varies based on ML-KEM variant.
The kem_shared_key is always 32 bytes.

kem_shared_key = DECAPS(ciphertext, decap_key)

Alice calculates the shared key,
using the ciphertext received in message 2.
The kem_shared_key is always 32 bytes.

Note que tanto a encap_key quanto o ciphertext são criptografados dentro de blocos ChaCha/Poly nas mensagens 1 e 2 do handshake Noise. Eles serão descriptografados como parte do processo de handshake.

A kem_shared_key é misturada na chaining key com MixHash(). Veja abaixo para detalhes.

Alice KDF para Mensagem 1

Após o padrão de mensagem ’es’ e antes do payload, adicione:

This is the "e1" message pattern:
  (encap_key, decap_key) = PQ_KEYGEN()

  // EncryptAndHash(encap_key)
  // AEAD parameters
  k = keydata[32:63]
  n = 0
  ad = h
  ciphertext = ENCRYPT(k, n, encap_key, ad)
  n++

  // MixHash(ciphertext)
  h = SHA256(h || ciphertext)


  End of "e1" message pattern.

  NOTE: For the next section (payload for XK or static key for IK),
  the keydata and chain key remain the same,
  and n now equals 1 (instead of 0 for non-hybrid).

Bob KDF para Mensagem 1

Após o padrão de mensagem ’es’ e antes do payload, adicione:

This is the "e1" message pattern:

  // DecryptAndHash(encap_key_section)
  // AEAD parameters
  k = keydata[32:63]
  n = 0
  ad = h
  encap_key = DECRYPT(k, n, encap_key_section, ad)
  n++

  // MixHash(encap_key_section)
  h = SHA256(h || encap_key_section)

  End of "e1" message pattern.

  NOTE: For the next section (payload for XK or static key for IK),
  the keydata and chain key remain the same,
  and n now equals 1 (instead of 0 for non-hybrid).

Bob KDF para Mensagem 2

Para XK: Após o padrão de mensagem ’ee’ e antes da carga útil, adicione:

This is the "ekem1" message pattern:

  (kem_ciphertext, kem_shared_key) = ENCAPS(encap_key)

  // EncryptAndHash(kem_ciphertext)
  // AEAD parameters
  k = keydata[32:63]
  n = 0
  ad = h
  ciphertext = ENCRYPT(k, n, kem_ciphertext, ad)

  // MixHash(ciphertext)
  h = SHA256(h || ciphertext)

  // MixKey(kem_shared_key)
  keydata = HKDF(chainKey, kem_shared_key, "", 64)
  chainKey = keydata[0:31]

  End of "ekem1" message pattern.

KDF de Alice para Mensagem 2

Após o padrão de mensagem ’ee’, adicione:

This is the "ekem1" message pattern:

  // DecryptAndHash(kem_ciphertext_section)
  // AEAD parameters
  k = keydata[32:63]
  n = 0
  ad = h
  kem_ciphertext = DECRYPT(k, n, kem_ciphertext_section, ad)

  // MixHash(kem_ciphertext_section)
  h = SHA256(h || kem_ciphertext_section)

  // MixKey(kem_shared_key)
  kem_shared_key = DECAPS(kem_ciphertext, decap_key)
  keydata = HKDF(chainKey, kem_shared_key, "", 64)
  chainKey = keydata[0:31]

  End of "ekem1" message pattern.

KDF para Mensagem 3 (apenas XK)

inalterado

KDF para split()

inalterado

Detalhes do Handshake

Identificadores de Noise

  • “Noise_XKhfsaesobfse+hs2+hs3_25519+MLKEM512_ChaChaPoly_SHA256”
  • “Noise_XKhfsaesobfse+hs2+hs3_25519+MLKEM768_ChaChaPoly_SHA256”
  • “Noise_XKhfsaesobfse+hs2+hs3_25519+MLKEM1024_ChaChaPoly_SHA256”

1) SessionRequest

Alterações: O NTCP2 atual contém apenas as opções na seção ChaCha. Com ML-KEM, a seção ChaCha também conterá a chave pública PQ criptografada.

Para que PQ e não-PQ NTCP2 possam ser suportados no mesmo endereço e porta do router, usamos o bit mais significativo do valor X (chave pública efêmera X25519) para marcar que é uma conexão PQ. Este bit está sempre desabilitado para conexões não-PQ.

Para Alice, depois que a mensagem é criptografada pelo Noise, mas antes da ofuscação AES de X, defina X[31] |= 0x7f.

Para Bob, após a des-ofuscação AES de X, teste X[31] & 0x80. Se o bit estiver definido, limpe-o com X[31] &= 0x7f, e descriptografe via Noise como uma conexão PQ. Se o bit estiver limpo, descriptografe via Noise como uma conexão não-PQ como de costume.

Para PQ NTCP2 anunciado em um endereço de router e porta diferentes, isso não é necessário.

Para informações adicionais, consulte a seção Endereços Publicados abaixo.

Conteúdo bruto:

  +----+----+----+----+----+----+----+----+
  |        MS bit set to 1 and then       |
  +        obfuscated with RH_B           +
  |       AES-CBC-256 encrypted X         |
  +             (32 bytes)                +
  |                                       |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |   ChaChaPoly frame (MLKEM)            |
  +      (see table below for length)     +
  |   k defined in KDF for message 1      |
  +   n = 0                               +
  |   see KDF for associated data         |
  ~   n = 0                               ~
  +----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |   ChaChaPoly frame (options)          |
  +         32 bytes                      +
  |   k defined in KDF for message 1      |
  +   n = 0                               +
  |   see KDF for associated data         |
  +----+----+----+----+----+----+----+----+
  |     unencrypted authenticated         |
  ~         padding (optional)            ~
  |     length defined in options block   |
  +----+----+----+----+----+----+----+----+

  Same as current specification except add a second ChaChaPoly frame

Dados não criptografados (tag de autenticação Poly1305 não mostrada):

  +----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |                   X                   |
  +              (32 bytes)               +
  |                                       |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |           ML-KEM encap_key            |
  +      (see table below for length)     +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |               options                 |
  +              (16 bytes)               +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |     unencrypted authenticated         |
  +         padding (optional)            +
  |     length defined in options block   |
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+

Nota: o campo de versão no bloco de opções da mensagem 1 deve ser definido como 2, mesmo para conexões PQ.

Tamanhos:

TipoCódigo do TipoX lenMsg 1 lenMsg 1 Enc lenMsg 1 Dec lenPQ key lenopt len
X2551943264+pad3216--16
MLKEM512_X25519532880+pad84881680016
MLKEM768_X255196321264+pad12321200118416
MLKEM1024_X255197321648+pad16161584156816

Nota: Os códigos de tipo são apenas para uso interno. Os routers permanecerão do tipo 4, e o suporte será indicado nos endereços do router.

2) SessionCreated

Conteúdo bruto:

  +----+----+----+----+----+----+----+----+
  |                                       |
  +        obfuscated with RH_B           +
  |       AES-CBC-256 encrypted Y         |
  +              (32 bytes)               +
  |                                       |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |   ChaChaPoly frame (MLKEM)            |
  +   Encrypted and authenticated data    +
  -      (see table below for length)     -
  +   k defined in KDF for message 2      +
  |   n = 0; see KDF for associated data  |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |   ChaChaPoly frame (options)          |
  +   Encrypted and authenticated data    +
  -           32 bytes                    -
  +   k defined in KDF for message 2      +
  |   n = 0; see KDF for associated data  |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |     unencrypted authenticated         |
  +         padding (optional)            +
  |     length defined in options block   |
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+

  Same as current specification except add a second ChaChaPoly frame

Dados não criptografados (tag de autenticação Poly1305 não mostrada):

  +----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |                  Y                    |
  +              (32 bytes)               +
  |                                       |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |           ML-KEM Ciphertext           |
  +      (see table below for length)     +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |               options                 |
  +              (16 bytes)               +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |     unencrypted authenticated         |
  +         padding (optional)            +
  |     length defined in options block   |
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+

Tamanhos:

TipoCódigo do TipoComprimento YComprimento Msg 2Comprimento Msg 2 EncComprimento Msg 2 DecComprimento PQ CTComprimento opt
X2551943264+pad3216--16
MLKEM512_X25519532848+pad81678476816
MLKEM768_X255196321136+pad11041104108816
MLKEM1024_X255197321616+pad15841584156816

Nota: Os códigos de tipo são apenas para uso interno. Os routers permanecerão tipo 4, e o suporte será indicado nos endereços do router.

3) SessionConfirmed

Inalterado

Função de Derivação de Chave (KDF) (para fase de dados)

Inalterado

Endereços Publicados

Em todos os casos, use o nome de transporte NTCP2 como de costume.

Use o mesmo endereço/porta como não-PQ, não-firewalled. Apenas uma variante PQ é suportada. No endereço do router, publique v=2 (como de costume) e o novo parâmetro pq=[3|4|5] para indicar MLKEM 512/768/1024. Alice define o MSB da chave efêmera (key[31] & 0x80) na solicitação de sessão para indicar que esta é uma conexão híbrida. Veja acima. Routers mais antigos irão ignorar o parâmetro pq e conectar não-pq como de costume.

Endereço/porta diferentes como não-PQ, ou apenas PQ, não-protegido por firewall NÃO é suportado. Isso não será implementado até que o NTCP2 não-PQ seja desabilitado, daqui a vários anos. Quando o não-PQ for desabilitado, múltiplas variantes PQ podem ser suportadas, mas apenas uma por endereço. Quando for suportado, no endereço do router, publique v=[3|4|5] para indicar MLKEM 512/768/1024. Alice não define o MSB da chave efêmera. Routers mais antigos verificarão o parâmetro v e pularão este endereço como não suportado.

Endereços com firewall (nenhum IP publicado): No endereço do router, publique v=2 (como de costume). Não há necessidade de publicar um parâmetro pq.

Alice pode conectar-se a um Bob PQ usando a variante PQ que Bob publica, independentemente de Alice anunciar suporte pq em suas informações do router, ou se ela anuncia a mesma variante.

Preenchimento Máximo

Na especificação atual, as mensagens 1 e 2 são definidas para ter uma quantidade “razoável” de padding, com um intervalo de 0-31 bytes recomendado, e nenhum máximo especificado.

Até a API 0.9.68 (versão 2.11.0), o Java I2P implementava um máximo de 256 bytes de padding para conexões não-PQ, porém isso não estava documentado anteriormente. A partir da API 0.9.69 (versão 2.12.0), o Java I2P implementa o mesmo padding máximo para conexões não-PQ que para MLKEM-512. Veja a tabela abaixo.

Use o tamanho de mensagem definido como o padding máximo, ou seja, o padding máximo dobrará o tamanho da mensagem para conexões PQ, da seguinte forma:

Preenchimento Máximo da Mensagemnão-PQ (até 0.9.68)não-PQ (a partir de 0.9.69)MLKEM-512MLKEM-768MLKEM-1024
Session Request25688088012641648
Session Created25684884811361616

Análise de Sobrecarga

Troca de Chaves

Aumento de tamanho (bytes):

TipoPubkey (Msg 1)Texto Cifrado (Msg 2)
MLKEM512_X25519+816+784
MLKEM768_X25519+1200+1104
MLKEM1024_X25519+1584+1584

Análise de Segurança

As categorias de segurança NIST estão resumidas no slide 10 da apresentação NIST . Critérios preliminares: Nossa categoria mínima de segurança NIST deve ser 2 para protocolos híbridos e 3 para apenas PQ.

CategoriaTão Seguro Quanto
1AES128
2SHA256
3AES192
4SHA384
5AES256

Handshakes

Estes são todos protocolos híbridos. As implementações devem preferir MLKEM768; MLKEM512 não é suficientemente seguro.

Categorias de segurança NIST FIPS 203 :

AlgoritmoCategoria de Segurança
MLKEM5121
MLKEM7683
MLKEM10245

Notas de Implementação

Suporte de Biblioteca

As bibliotecas Bouncycastle, BoringSSL e WolfSSL agora suportam MLKEM e MLDSA. O suporte do OpenSSL estará em sua versão 3.5 lançada em 8 de abril de 2025 OpenSSL .

Identificação de Tráfego de Entrada

Definimos o MSB da chave efêmera (key[31] & 0x80) na solicitação de sessão para indicar que esta é uma conexão híbrida. Isso nos permite executar tanto NTCP padrão quanto NTCP híbrido na mesma porta. Apenas uma variante híbrida é suportada para entrada e anunciada no endereço do router. Por exemplo, pq=3 ou pq=4.

Ofuscação

Como Alice, para uma conexão PQ, antes da ofuscação, defina X[31] |= 0x80. Isso torna X uma chave pública X25519 inválida. Após a ofuscação, AES-CBC irá randomizá-la. O MSB de X será aleatório após a ofuscação.

Como Bob, teste se (X[31] & 0x80) != 0 após a des-obfuscação. Se for o caso, é uma conexão PQ.

A versão mínima do router necessária para NTCP2-PQ é TBD.

Nota: Os códigos de tipo são apenas para uso interno. Os routers permanecerão tipo 4, e o suporte será indicado nos endereços do router.

Compatibilidade do Router

Nomes de Transporte

Em todos os casos, use o nome de transporte NTCP2 como de costume. Routers mais antigos irão ignorar o parâmetro pq e conectar com NTCP2 padrão como de costume.

Referências

Was this page helpful?