Transporte Criptografado

Como a BOLT 8 cria uma sessão Noise autenticada entre dois nós

Lightning · Técnico

Antes de qualquer mensagem Wire aparecer, dois nós Lightning precisam criar uma sessão cifrada e autenticada. Esse e o papel da BOLT 8: ela define o transporte criptografado que fica entre o socket de rede e os bytes plaintext da BOLT 1.

A Lightning usa o Noise Protocol Framework, na variante Noise_XK_secp256k1_ChaChaPoly_SHA256. O iniciador ja precisa conhecer o node id do respondente, uma chave publica secp256k1 de longo prazo. Depois de tres atos de handshake, os dois lados derivam chaves de envio e recebimento e passam a trocar frames AEAD.

Esta pagina fala da camada de transporte entre peers. Ela nao define o formato das mensagens Lightning internas; depois da decriptacao, a mensagem resultante ainda precisa ser interpretada pelo Protocolo Wire.

Conteúdo

Onde o transporte entra

Uma conexao Lightning tem camadas. TCP, Tor ou outro transporte de rede entrega bytes. A BOLT 8 transforma esses bytes em uma sessao criptografada. So depois disso a BOLT 1 aparece, com mensagens como init, ping, open_channel e update_add_htlc.

socket de rede
  -> BOLT 8: handshake Noise + frames cifrados
  -> BOLT 1: type + payload da mensagem Lightning
  -> BOLT 2/4/7/11: significado especifico do payload

Essa separacao importa para debugging. Se o MAC do frame falha, o problema esta no transporte. Se o frame decripta, mas o tipo da mensagem e desconhecido ou o payload viola o schema, o problema esta no wire protocol ou no BOLT especifico daquela mensagem.

Objetivos de segurança

O transporte criptografado existe para proteger a conversa entre dois peers. Ele fornece:

Isso nao torna a Lightning anonima. O peer ainda conhece o IP ou circuito de rede usado, o node id com quem esta conectado, timing, volume de trafego e mensagens que ele mesmo processa. Privacidade de rota, probing e metadados sao tratados em outras camadas, como roteamento onion e seguranca e privacidade.

Identidade do nó

O node id de um no Lightning e uma chave publica secp256k1 comprimida. Em enderecos publicos, ele costuma aparecer como:

node_id@host:porta

O iniciador precisa desse node id antes de conectar. Isso explica o K em Noise_XK: a chave estatica do respondente e known, conhecida pelo iniciador. O respondente, por outro lado, ainda nao sabe a chave estatica do iniciador; ela e enviada cifrada no terceiro ato. Esse e o X: a chave estatica do iniciador e transmitida durante o handshake.

O respondente nao envia sua chave estatica durante o handshake. Ele prova controle dessa chave implicitamente: se nao tiver a chave privada correspondente ao node id conhecido pelo iniciador, nao consegue produzir/verificar os MACs corretos.

Instanciação Noise

A BOLT 8 fixa a variante exata de Noise. Uma implementacao nao deve escolher primitivas parecidas por conta propria.

Parâmetros criptográficos da BOLT 8
Item Valor Função
Nome do protocolo Noise_XK_secp256k1_ChaChaPoly_SHA256 Define a variante exata do Noise usada pela Lightning.
Curva secp256k1 A mesma familia de chaves usada por Bitcoin; node ids sao chaves publicas comprimidas.
Hash SHA-256 Inicializa e atualiza o handshake hash e participa do HKDF.
KDF HKDF Mistura saidas ECDH na chaining key e deriva chaves temporarias e finais.
AEAD ChaCha20-Poly1305 Cifra e autentica tags do handshake, tamanho de frame e mensagens Lightning.
Prologue lightning String fixa misturada ao estado inicial para separar este protocolo de outros usos de Noise.

O estado inicial mistura o nome do protocolo, a string lightning e a chave publica estatica do respondente. Se dois endpoints discordam sobre o nome do protocolo, a curva, o hash, a cifra ou o node id remoto, o handshake nao chega a uma sessao valida.

antes do Act One:

protocolName = "Noise_XK_secp256k1_ChaChaPoly_SHA256"
prologue = "lightning"

h  = SHA256(protocolName)
ck = h
h  = SHA256(h || prologue)
h  = SHA256(h || responder_static_pubkey_compressed)

resultado:
- os dois lados concordam no mesmo protocolo
- o iniciador esta preso ao node id que queria contatar
- qualquer byte posterior altera o handshake hash

Um detalhe facil de errar: os inteiros de nonce usados no ChaCha20-Poly1305 seguem a convencao do Noise. Eles sao codificados como 32 bits zero seguidos de um valor de 64 bits em little-endian, diferente de varias estruturas Lightning que usam big-endian.

Estado do handshake

Durante o handshake, cada lado mantem um pequeno conjunto de variaveis. Elas nao sao mensagens Lightning; sao estado criptografico local.

Estado mantido durante o handshake
Variável Papel
ck Chaining key. Acumula as saidas ECDH e depois deriva chaves de envio/recebimento.
h Handshake hash. Acumula todos os dados do handshake e entra como associated data nos MACs.
temp_k1, temp_k2, temp_k3 Chaves temporarias usadas durante os tres atos do handshake.
e Par de chaves efemero da sessao. Deve ser novo e aleatorio a cada conexao.
s Par de chaves estatico local, isto e, a identidade de longo prazo do no.
rs Chave publica estatica remota conhecida pelo iniciador antes da conexao.

O h nao e enviado na rede. Ele entra como associated data nos AEADs de handshake. Isso prende cada MAC ao transcript completo visto ate aquele ponto. Se um intermediario muda uma chave efemera, uma tag ou a chave estatica cifrada, a verificacao falha.

Handshake em três atos

O handshake tem 1,5 ida-e-volta e tres mensagens de tamanho fixo. Na notacao do Noise:

Noise_XK(s, rs):
  <- s
  ...
  -> e, es
  <- e, ee
  -> s, se
Atos do handshake BOLT 8
Ato Direção Noise Tamanho Conteúdo no fio
Act One iniciador -> respondente e, es 50 bytes versao 1 byte, chave publica efemera comprimida 33 bytes, tag Poly1305 16 bytes.
Act Two respondente -> iniciador e, ee 50 bytes versao 1 byte, chave publica efemera comprimida 33 bytes, tag Poly1305 16 bytes.
Act Three iniciador -> respondente s, se 66 bytes versao 1 byte, chave estatica do iniciador cifrada 33 bytes, tag da chave 16 bytes, tag final 16 bytes.
Handshake Noise_XK em tres atos entre iniciador e respondente, com troca de chaves efemeras e chave estatica do iniciador cifrada no terceiro ato.
As mensagens do handshake ainda nao sao mensagens Wire da Lightning.
Descricao longa do diagrama

O diagrama mostra dois nos, iniciador e respondente. No primeiro ato, o iniciador envia uma chave efemera e uma tag. No segundo, o respondente envia sua chave efemera e uma tag. No terceiro, o iniciador envia sua chave estatica cifrada e uma tag final. Setas indicam que, entre os atos, ambos misturam ECDH, chaining key e handshake hash para derivar chaves de sessao.

Exemplo de estrutura do primeiro ato, usando um valor de teste da BOLT 8:

00
036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7
0df6086551151f58b8afe6c195782c6a

00 = versao do handshake
03...f7 = chave publica efemera comprimida do iniciador, 33 bytes
0d...6a = tag Poly1305, 16 bytes

Os valores de teste da BOLT 8 usam chaves privadas fixas para tornar o resultado reproduzivel. Isso e apenas para teste. Uma conexao real precisa gerar chaves efemeras novas com aleatoriedade forte.

Frames cifrados

Quando o terceiro ato termina, os dois lados derivam duas chaves finais: uma para enviar e outra para receber. A partir dai, cada mensagem Lightning plaintext vira um frame cifrado.

Estrutura de um frame BOLT 8
Parte Tamanho Significado
lc 18 bytes 2 bytes de tamanho cifrado + tag Poly1305 de 16 bytes.
c len(m) + 16 bytes mensagem Lightning cifrada + tag Poly1305 de 16 bytes.
packet 18 + len(m) + 16 bytes frame completo enviado no stream TCP ou Tor.
maximo 65569 bytes 2 + 16 + 65535 + 16, porque o plaintext maximo e 65535 bytes.
Frame cifrado com tamanho de 2 bytes cifrado e autenticado, seguido da mensagem Lightning cifrada e autenticada.
A BOLT 8 cifra ate o tamanho da mensagem plaintext.
Descricao longa do diagrama

O diagrama mostra um frame dividido em quatro partes: primeiro o tamanho cifrado da mensagem, depois uma tag de 16 bytes para esse tamanho, depois o corpo cifrado da mensagem Lightning e por fim uma tag de 16 bytes para o corpo. Uma seta indica que, apos a decriptacao, o corpo vira uma mensagem BOLT 1 com type e payload.

O tamanho plaintext e codificado como u16 big-endian antes de ser cifrado. Isso permite ate 65535 bytes de mensagem Lightning. Na rede, o prefixo cifrado tem 18 bytes, porque os 2 bytes de tamanho recebem uma tag Poly1305 de 16 bytes.

para enviar uma mensagem Lightning m:

1. l = len(m)
2. rejeitar se l > 65535
3. lc = encryptWithAD(sk, sn, "", u16be(l))
4. sn = sn + 1
5. c = encryptWithAD(sk, sn, "", m)
6. sn = sn + 1
7. escrever lc || c no socket
8. se sn == 1000, rotacionar sk e zerar sn
para receber a proxima mensagem:

1. ler exatamente 18 bytes como lc
2. l = decryptWithAD(rk, rn, "", lc)
3. rn = rn + 1
4. ler exatamente l + 16 bytes como c
5. m = decryptWithAD(rk, rn, "", c)
6. rn = rn + 1
7. se rn == 1000, rotacionar rk e zerar rn
8. entregar m ao parser da BOLT 1

Depois que m e decriptada, o transporte acabou seu trabalho. O parser da BOLT 1 le os dois primeiros bytes como type e entrega o payload ao codigo apropriado.

Rotação de chaves

A BOLT 8 rotaciona chaves por sentido de trafego. A chave de envio (sk) e a chave de recebimento (rk) tem nonces separados e chaining keys separadas (sck e rck).

A regra operacional e: quando o nonce de uma chave chega a 1000, derive uma nova chave com HKDF, zere o nonce e esqueca a chave antiga. Como cada mensagem usa duas operacoes AEAD, uma para o tamanho e outra para o corpo, isso corresponde a uma rotacao a cada 500 mensagens naquele sentido.

ck', k' = HKDF(ck, k)
k = k'
ck = ck'
n = 0

Essa rotacao ajuda sessoes longas. Se uma chave atual vazar, ela nao deve permitir decriptar indefinidamente todo o trafego antigo daquele sentido.

Validação de implementação

Uma implementacao BOLT 8 precisa ser rígida. O transporte fica antes do parser de mensagens; aceitar bytes ambíguos aqui enfraquece todas as camadas acima.

Checagens essenciais no transporte
Condição Comportamento seguro
Versao de handshake desconhecida abortar a conexao. Versao 0 e o formato base; versoes desconhecidas nao devem ser aceitas.
Leitura curta falhar. Cada ato tem tamanho fixo: 50, 50 e 66 bytes.
Chave publica invalida falhar antes de ECDH; bytes de chave precisam ser ponto secp256k1 valido em formato comprimido.
MAC invalido encerrar imediatamente. Nao envie mensagem Lightning parcialmente autenticada.
Mensagem plaintext maior que 65535 bytes rejeitar; esse e o limite maximo antes da cifragem de transporte.
Nonce chegou a 1000 para uma chave rotacionar a chave com HKDF e reiniciar o nonce daquele sentido.

Para testar uma implementacao, use os vetores oficiais da BOLT 8. Eles cobrem handshake bem-sucedido, leitura curta, versao ruim, serializacao invalida de chave, tag ruim e cifragem de mensagens. Nao use esses vetores como chaves reais; eles existem justamente para repetir resultados em teste.

Limites reais

O transporte criptografado protege conteudo e autentica o peer, mas nao resolve todos os problemas de privacidade ou seguranca:

Armadilhas comuns

Resumo

Mapa de dependências conceituais

Antes de ler esta página

Depois desta página

Referências técnicas usadas

Com o transporte, o wire protocol, os canais, o onion routing, o gossip e a busca de caminho cobertos, o proximo passo e olhar a seguranca e a privacidade da rede como um sistema completo.