11.13. Pareamento e vinculação¶
Tudo o que foi abordado até aqui movimenta bytes pelo rádio em texto claro. Qualquer pessoa com um notebook com suporte a BLE na mesma sala pode escutar os canais de anúncio, acompanhar a sequência de saltos de uma conexão aberta e ler cada leitura, escrita e notificação que trafega. Para a maioria dos dados públicos de sensores (nível de bateria, temperatura ambiente) isso não é problema. Para qualquer coisa que os dois endpoints queiram manter em sigilo – um registrador de controle que aciona um relé, uma senha, uma medição que não deveria ser amplamente transmitida – o enlace precisa ser criptografado e, idealmente, a câmera precisa saber com quem está se comunicando.
O BLE oferece ambos por meio de pareamento e vinculação.
11.13.1. Pareamento, vinculação, criptografia¶
Três conceitos intimamente relacionados:
Criptografia é o objetivo final. Uma vez que o enlace está criptografado, cada pacote nos canais de dados só pode ser decifrado pelos dois endpoints; um bisbilhoteiro vê apenas ruído.
Pareamento é o procedimento que os dois endpoints executam para combinar as chaves que a criptografia utiliza. É uma troca única que produz material de chave compartilhado que a camada de enlace conecta ao seu mecanismo de criptografia.
Vinculação é a opção de persistir as chaves em armazenamento não volátil após a conclusão do pareamento, de modo que a próxima conexão entre os mesmos dois dispositivos pula o pareamento e vai direto para a criptografia.
Em linguagem simples: pareamento é “apresentem-se”; vinculação é “lembre-se desta apresentação”; criptografia é “a partir de agora, conversem em sigilo”.
O fluxo de pareamento sobre uma conexão BLE aberta. Uma vez concluída a troca de chaves, a camada de enlace criptografa cada pacote subsequente. A vinculação é a etapa extra de gravar as chaves no flash.¶
11.13.2. LE Secure Connections¶
A troca de chaves moderna usada pelo BLE é a LE Secure Connections, construída sobre o Elliptic Curve Diffie-Hellman. Ambos os lados geram um par de chaves temporário, trocam as metades públicas e combinam o resultado com suas próprias chaves privadas para chegar ao mesmo segredo compartilhado – um segredo que um bisbilhoteiro não consegue calcular nem mesmo com um registro completo da troca.
O método mais antigo, LE Legacy, é menos seguro (um bisbilhoteiro com a troca completa geralmente consegue recuperar a chave) e existe apenas para compatibilidade retroativa com periféricos antigos. O padrão do aioble é o método moderno (le_secure=True); mantenha-o.
11.13.3. Iniciando o pareamento¶
Uma central pareia chamando aioble.DeviceConnection.pair() em uma conexão já aberta:
async with await device.connect() as connection:
await connection.pair(bond=True, le_secure=True, mitm=False)
# ... GATT work, now over an encrypted link ...
Após o retorno de pair, os atributos encrypted, authenticated, bonded e key_size da conexão refletem o que foi negociado.
Os quatro argumentos nomeados mais úteis:
bond=True– salva as chaves resultantes no flash para que a próxima conexão entre os mesmos dois dispositivos pule o handshake de pareamento. PadrãoTrue.le_secure=True– usa LE Secure Connections. PadrãoTrue. Deixe ativado.mitm=False– define se deve exigir proteção contra man-in-the-middle. Isso requer um canal fora de banda (um código numérico exibido em um lado e confirmado no outro, uma senha de acesso digitada, …) para que o usuário possa verificar que os dois dispositivos no handshake de pareamento são realmente os que ele imagina. O padrão éFalse(sem proteção MITM – um bisbilhoteiro passivo não consegue ler o enlace, mas um atacante redirecionando ativamente as conexões poderia se parear). Defina comoTruepara qualquer coisa sensível, mas esteja ciente de que isso exige que o periférico realmente suporte uma capacidade de IO.io=3– a capacidade de IO que o dispositivo declara. A especificação Bluetooth define cinco:0apenas display,1display + sim/não,2apenas teclado,3sem entrada e sem saída,4teclado + display. Uma câmera sem interface de usuário normalmente reporta3; se a própria câmera tiver um display, a aplicação poderia exibir a confirmação numérica e usar1. A combinação das capacidades de IO dos dois lados decide se a proteção MITM real é alcançável.
Periféricos não chamam pair por conta própria – eles respondem ao que a central iniciar. Se a criptografia é exigida para uma determinada característica é uma propriedade de como ela é declarada na base de dados GATT; os bits de acesso que exigem criptografia fazem parte da API de baixo nível bluetooth e não estão atualmente expostos pelo construtor de característica do aioble.
11.13.4. Vinculação – e onde as chaves residem¶
Quando bond=True, o aioble grava as chaves em um arquivo JSON no sistema de arquivos local. O nome de arquivo padrão é ble_secrets.json, gravado em relação ao diretório de trabalho atual. Em uma cam recém-inicializada, o _boot.py já escolheu esse diretório: /sdcard quando um cartão está montado, /flash caso contrário – então o arquivo fica em /sdcard/ble_secrets.json ou /flash/ble_secrets.json. O arquivo contém as entradas necessárias para recriptografar o enlace na próxima vez que o par vinculado se reconectar, incluindo o endereço de identidade do par.
Uma assimetria a ter em mente: o salvamento acontece automaticamente conforme as chaves mudam, mas o carregamento do arquivo na próxima inicialização não. Chame aioble.security.load_secrets() uma vez na inicialização (antes de qualquer pareamento ou anúncio) para que pares previamente vinculados sejam reconhecidos:
import aioble
aioble.security.load_secrets() # default path: ble_secrets.json
Depois disso, na próxima vez que um par vinculado aparecer, o aioble reutiliza as chaves armazenadas e o enlace passa a ser criptografado sem nenhum handshake adicional.
Duas consequências práticas de armazenar chaves no flash:
Esquecer um dispositivo. Exclua o
ble_secrets.json(ou remova a entrada relevante) para esquecer todos os pares vinculados e, então, refaça o pareamento do zero.Acesso físico vaza chaves. Qualquer pessoa com acesso ao sistema de arquivos da câmera pode ler o JSON. Esse é o mesmo tipo de restrição que surgiu no lado da rede com as chaves TLS (Operações: chaves, expiração e solução de problemas): use chaves por dispositivo, trate qualquer chave armazenada como recuperável e confie na capacidade de revogar (aqui, removendo a vinculação no lado da central) em vez de no segredo da chave permanecer secreto.
11.13.5. O que a criptografia garante – e o que não garante¶
Um enlace pareie-e-depois-criptografe oferece, em ordem de robustez:
Confidencialidade. Sempre. Um bisbilhoteiro não consegue ler os bytes.
Integridade. Sempre. Pacotes modificados falham na verificação de criptografia autenticada da camada de enlace e são descartados.
Autenticação. Somente com
mitm=Truee um IO capaz. Sem isso, um man-in-the-middle que tenha interceptado a troca de pareamento original poderia ter se inserido; sem proteção MITM não há como os dois lados saberem.
Para a maioria dos casos de uso de câmera – um celular pareando com a câmera uma vez e depois se conectando novamente – mitm=False geralmente é suficiente, pois o pareamento original acontece em um ambiente controlado (o usuário segura ambos os dispositivos na mesma sala). Para aplicações em que um dispositivo pareado possa encontrar a câmera pela primeira vez a longa distância ou por meio de um intermediário não confiável, o MITM é a configuração correta.
11.13.6. Quando o pareamento é a resposta errada¶
O pareamento tem um custo real: alguns segundos de troca na primeira conexão, uso persistente do flash para cada dispositivo vinculado e o procedimento de recuperação de “esquecer a vinculação” se algo der errado. Para dados genuinamente públicos – leituras de sensores ambientais publicadas como um beacon, uma placa exibindo seu nome, qualquer coisa que não mude o mundo ao ser lida ou escrita – a resposta correta é não criptografar de modo algum, e deixar que qualquer scanner próximo leia os valores.
Para todo o resto, connection.pair(bond=True) na central é o acréscimo de uma linha que transforma o enlace de um canal público em um canal privado.