11.13. Emparelhamento e vinculação¶
Tudo o que foi abordado até aqui transmite bytes pelo rádio em claro. Qualquer pessoa com um portátil com suporte BLE na mesma sala pode escutar os canais de publicidade, seguir a sequência de saltos de uma ligação aberta e ler cada leitura, escrita e notificação que passa. Para a maioria dos dados de sensor públicos (nível de bateria, temperatura ambiente) isso é aceitável. Para qualquer coisa que os dois endpoints queiram manter privada – um registo de controlo que activa um relé, uma palavra-passe, uma medição que não deve ser amplamente difundida – a ligação precisa de ser encriptada e, idealmente, a câmara precisa de saber com quem está a falar.
O BLE fornece ambos através de emparelhamento e vinculação.
11.13.1. Emparelhamento, vinculação, encriptação¶
Três conceitos intimamente relacionados:
Encriptação é o objectivo final. Uma vez encriptada a ligação, cada pacote nos canais de dados só é decifrável pelos dois endpoints; um intruso vê apenas ruído.
Emparelhamento é o procedimento que os dois endpoints executam para chegarem a acordo sobre as chaves que a encriptação utiliza. É uma troca única que produz material de chave partilhada que a camada de ligação insere no seu motor de encriptação.
Vinculação é a opção de persistir as chaves em armazenamento não volátil após o emparelhamento terminar, para que a próxima ligação entre os mesmos dois dispositivos salte o emparelhamento e vá directamente para a encriptação.
Em linguagem simples: emparelhamento é «apresentem-se»; vinculação é «lembrem-se desta apresentação»; encriptação é «falem em privado a partir de agora».
O fluxo de emparelhamento sobre uma ligação BLE aberta. Assim que a troca de chaves termina, a camada de ligação encripta todos os pacotes subsequentes. A vinculação é o passo extra de escrever as chaves em flash.¶
11.13.2. Ligações Seguras LE¶
A troca de chaves moderna utilizada pelo BLE é Ligações Seguras LE, baseada em Curvas Elípticas Diffie-Hellman. Ambos os lados geram um par de chaves temporário, trocam as metades públicas e combinam o resultado com as suas próprias chaves privadas para chegarem ao mesmo segredo partilhado – um segredo que um intruso não consegue calcular mesmo com um registo completo da troca.
O método LE Legacy mais antigo é menos seguro (um intruso com a troca completa geralmente consegue recuperar a chave) e existe apenas para compatibilidade retroactiva com periféricos antigos. A predefinição do aioble é o método moderno (le_secure=True); mantenha-o.
11.13.3. Iniciar o emparelhamento¶
Uma central emparelha chamando aioble.DeviceConnection.pair() numa ligaçã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 na ligação reflectem o que foi negociado.
Os quatro argumentos de palavra-chave mais úteis:
bond=True– guardar as chaves resultantes em flash para que a próxima ligação entre os mesmos dois dispositivos salte o handshake de emparelhamento. PredefiniçãoTrue.le_secure=True– utilizar Ligações Seguras LE. PredefiniçãoTrue. Mantenha activo.mitm=False– se deve exigir protecção contra man-in-the-middle. Isto requer um canal fora de banda (um código numérico exibido num lado e confirmado no outro, uma palavra-passe digitada, …) para que o utilizador possa verificar que os dois dispositivos no handshake de emparelhamento são realmente os que pensa. A predefinição éFalse(sem protecção MITM – um intruso passivo não consegue ler a ligação, mas um atacante que redireccionasse activamente as ligações poderia emparelhar-se). Defina paraTrueem qualquer coisa sensível, mas tenha em conta que requer que o periférico suporte realmente uma capacidade de IO.io=3– a capacidade de IO que o dispositivo declara. A especificação Bluetooth define cinco:0apenas ecrã,1ecrã + sim/não,2apenas teclado,3sem entrada sem saída,4teclado + ecrã. Uma câmara sem interface de utilizador normalmente reporta3; se a câmara tiver um ecrã, 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 protecção MITM real é alcançável.
Os periféricos não chamam pair eles próprios – respondem ao que a central iniciar. Se a encriptação é obrigatória para uma determinada característica é uma propriedade de como está declarada na base de dados GATT; os bits de acesso que requerem encriptação fazem parte da API de baixo nível bluetooth e não estão actualmente expostos através do construtor de características do aioble.
11.13.4. Vinculação – e onde as chaves ficam¶
Quando bond=True, o aioble escreve as chaves num ficheiro JSON no sistema de ficheiros local. O nome de ficheiro predefinido é ble_secrets.json, escrito relativamente ao directório de trabalho actual. Numa câmara recém-iniciada, o _boot.py já escolheu esse directório: /sdcard quando um cartão está montado, /flash caso contrário – portanto o ficheiro fica em /sdcard/ble_secrets.json ou /flash/ble_secrets.json. O ficheiro contém as entradas necessárias para re-encriptar a ligação na próxima vez que o par vinculado se reconectar, incluindo o endereço de identidade do par.
Uma assimetria a ter em conta: guardar acontece automaticamente quando as chaves mudam, mas carregar o ficheiro no próximo arranque não. Chame aioble.security.load_secrets() uma vez na inicialização (antes de qualquer emparelhamento ou publicidade) para que os 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 a ligação fica encriptada sem mais nenhum handshake.
Duas consequências práticas de guardar chaves em flash:
Esquecer um dispositivo. Elimine
ble_secrets.json(ou remova a entrada relevante) para esquecer todos os pares vinculados, e depois emparelhe novamente de raiz.O acesso físico expõe as chaves. Qualquer pessoa com acesso ao sistema de ficheiros da câmara pode ler o JSON. Esta é o mesmo tipo de restrição que surgiu no lado da rede com chaves TLS (Operações: chaves, expiração e resoluçã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 central) em vez de confiar em que a chave permaneça secreta.
11.13.5. O que a encriptação garante – e o que não garante¶
Uma ligação com emparelhamento seguido de encriptação fornece, por ordem de robustez:
Confidencialidade. Sempre. Um intruso não consegue ler os bytes.
Integridade. Sempre. Os pacotes modificados falham a verificação de encriptação autenticada da camada de ligação e são descartados.
Autenticação. Apenas com
mitm=Truee um IO capaz. Sem isso, um man-in-the-middle que tivesse interceptado a troca de emparelhamento original poderia ter-se inserido; sem protecção MITM não há forma de os dois lados saberem.
Para a maioria dos casos de utilização de câmara – um telemóvel a emparelhar com a câmara uma vez, e depois a conectar novamente mais tarde – mitm=False é geralmente suficiente, porque o emparelhamento original acontece num ambiente controlado (o utilizador segura ambos os dispositivos na mesma sala). Para aplicações em que um dispositivo emparelhado pode encontrar pela primeira vez a câmara a longa distância ou através de um intermediário não confiável, o MITM é a configuração correcta.
11.13.6. Quando o emparelhamento é a resposta errada¶
O emparelhamento tem um custo real: alguns segundos de troca na primeira ligação, uso persistente de flash para cada dispositivo vinculado, e a história de recuperação de «esquecer a vinculação» se algo correr mal. Para dados genuinamente públicos – leituras de sensor ambiente publicadas como beacon, uma placa a exibir o seu nome, qualquer coisa que não muda o mundo por ser lida ou escrita – a resposta certa é não encriptar de todo, e deixar qualquer scanner próximo ler os valores.
Para todo o resto, connection.pair(bond=True) na central é a adição de uma linha que transforma a ligação de um canal público num canal privado.