Protegendo a comunicação entre sistemas embarcados limitados
Atualmente, estou tentando fortalecer a comunicação em um canal de comunicação físico limitado em um sistema embarcado.
O cenário
Acho que o sistema é bastante típico para pequenos aplicativos incorporados:
Os sistemas embarcados envolvidos são pequenos microcontroladores sem sistema operacional, que pode ser considerado em um ambiente físico seguro. O canal de conexão é fisicamente acessível aos agressores, eles podem interferir nas mensagens conforme desejado.
Diferentes canais de comunicação são possíveis: por exemplo, RS485 ou RS232. Existe um protocolo rudimentar que lida com coisas como endereçamento e integridade grosseira (por exemplo, CRC16 para bitflips), no qual podemos construir. Pense nisso como um TCP lento.
Cada parceiro de comunicação conhece um certificado raiz que pode atuar como uma CA e possui um certificado exclusivo (+ chave) assinado por ele. Os certificados são autoassinados, curva elíptica prime256v1
A biblioteca mbedTLS está disponível para esses sistemas (com DH, AES, ..).
Na maioria das vezes, não há internet disponível.
Os sistemas podem manter o tempo e podem criar números aleatórios suficientes
Eu quero alcançar privacidade, autenticidade e integridade.
Como pode ser resolvido
Uma regra em protocolos criptográficos é nunca implementá-los por conta própria. Infelizmente, não encontrei nada que corresponda a este caso de uso.
Também pesquisei as questões existentes, mas nada forneceu a solução completa que procurava.
Finalmente, nesta resposta, a implementação de um protocolo próprio é dada como a última opção.
É por isso que encontrei a solução descrita abaixo - mas não estou totalmente certo disso. Eu orientei esta resposta sobre como autenticar um Diffie-Hellmann Key Exchange , esta resposta sobre como verificar a integridade e esta thread me dando algumas idéias sobre como implementar tal protocolo .
Protocolo para comunicação segura
A primeira coisa a fazer é gerar aleatoriamente uma chave simétrica K. A primeira coisa a ser enviada é uma mensagem de handshake. Possui os seguintes campos:
Campo | Descrição |
---|---|
DH | A troca de chave Diffie-Hellmann msg g K |
Cert | O certificado (-chain) do dispositivo de envio |
MsgIdNonce | Um valor aleatório de 64 bits |
Assinatura | Uma assinatura da mensagem completa usando a chave privada do Cert |
Ambos os dispositivos enviam (e recebem) tal mensagem.
Quando uma mensagem é recebida, o seguinte é feito:
- Verifique se o certificado está assinado pelo CA esperado (deve estar na cadeia)
- Verifique se a msg está devidamente assinada com o certificado e sua chave
Quando essas verificações são bem-sucedidas, as mensagens DH g K enviadas e recebidas são usadas para calcular uma chave simétrica.
A partir deste ponto, os aplicativos podem enviar mensagens criptografadas com AES-CBC. Como as mensagens podem ser perdidas com relativa frequência, o IV está sempre na mensagem.
Este é o formato da mensagem:
Campo | Descrição | Criptografado |
---|---|---|
IV | Inicialmente aleatório IV para AES | Não |
MsgIdNonce | Aperto de mão / Última MsgIdNonce + 1 ou + 2 | sim |
dados de aplicativos | Os dados / comandos a serem protegidos | sim |
CMAC truncado para 64 bits | MAC para verificação de integridade | sim |
Para que uma mensagem seja aceita, ela deve
- Ter o MsgIdNonce esperado (1 ou 2 acima do último recebido) - evitando ataques de repetição, permitindo a perda de 1 mensagem
- Tenha um CMAC válido - evitando ataques à integridade
- Ser recebido no máximo. T segundos após a última mensagem - evitando ataques retardados
Se algo não for o esperado, o handshake é enviado novamente e a mensagem é enviada novamente com os parâmetros trocados recentemente.
Questões
Estou no caminho certo ou devo tentar algo completamente diferente?
Isso fornece meus objetivos de segurança ou perco alguma vulnerabilidade óbvia aqui?
Isso pode funcionar?
Espero que você possa ajudar a mim e a outros engenheiros embarcados que enfrentam problemas semelhantes!
Respostas
Uma regra em protocolos criptográficos é nunca implementá-los por conta própria. Infelizmente, não encontrei nada que corresponda a este caso de uso.
Você considerou o DTLS ? Isso tenta resolver o mesmo problema (exceto para carimbos de hora; que podem ser adicionados inserindo o carimbo de hora no datagrama), e já tem coisas pensadas. Outra possibilidade seria o IPsec; entretanto, o DTLS parece mais perto de resolver o problema que você tem (a menos que o tráfego de dados que você está protegendo seja tráfego IP).
Dito isso, aqui estão algumas idéias sobre o protocolo que você delineou:
O que acontece se duas mensagens sequenciais forem descartadas (por exemplo, recebidas incorretamente)? Os dois lados perceberão o que aconteceu ou continuarão a descartar todas as mensagens subsequentes (por causa da regra 'o nonce não precisa incrementar mais do que 2')?
Presumindo que eles tentem uma recodificação, como isso é coordenado? Se um lado pensa que ainda não foi reinserido e o outro pensa que está, o que acontecerá com as mensagens criptografadas com a chave antiga? Em geral, achamos útil incluir uma tag 'qual chave isso está criptografado em' com o texto cifrado (em DTLS, essa é a 'época').
Seu canal de comunicação pode reorganizar as mensagens? Suspeito que não seja possível no seu caso, mas, se puder, você deve pensar em como lidar com isso.
O que acontece se alguém injetar uma mensagem de handshake anterior (válida)? Como isso vai confundir as coisas?
No caminho de criptografia de dados, você usa criptografia CBC e integridade CMAC. Embora seja uma solução viável, ela está sujeita a vários ataques de preenchimento se eles não forem integrados corretamente. A moda atual é usar um modo AEAD (como GCM ou Chacha20 / Poly1305) que faz as duas coisas.
O tráfego criptografado é unidirecional ou bidirecional? Se o tráfego for nos dois sentidos, você usa o mesmo conjunto de chaves para proteger os dois conjuntos de tráfego?
"Se algo não for o esperado, o handshake é enviado novamente e a mensagem é enviada novamente com os parâmetros trocados." - como isso funciona? Se o destinatário decidiu que não gostou da mensagem, como o remetente sabe que deve reenviá-la?