SecurePair is een bibliotheek voor ESP32-boards die cryptografisch veilige koppeling en communicatie mogelijk maakt. Het systeem maakt gebruik van industrieel gestandaardiseerde cryptografie, waaronder X25519 voor sleutelovereenkomst en AES-256-GCM voor versleuteling en authenticatie.
De belangrijkste kenmerken zijn:
- Medium-onafhankelijkheid: Koppeling en communicatie kunnen plaatsvinden via ESP-NOW, LoRa of een enkele LED (
PacketLED).
- Visuele verificatie: Bij koppeling via licht tonen beide boards een synchrone knippercode. De gebruiker vergelijkt deze visueel, wat effectief beschermt tegen man-in-the-middle aanvallen zonder dat er een scherm of app nodig is.
- Beheer van peers: Elk board kan tot 8 unieke partners onthouden met eigen sleutels.
- Hardware-beveiliging: Op ondersteunde chips kan de sleutelopslag in de NVS worden versleuteld met een hardware-sleutel in de eFuse, waardoor fysiek uitlezen van de flash wordt bemoeilijkt.
- Eenvoudige implementatie: De bibliotheek is ontworpen voor minimale impact op de
loop() van de applicatie, waarbij het koppelproces via een provision() functie in de setup() wordt afgehandeld.
SecurePair: Cryptografisch veilige koppeling en communicatie tussen ESP32-boards
Sleutels worden overeengekomen via een elliptic-curve exchange (X25519) en berichten worden versleuteld met AES-256-GCM. De bibliotheek is onafhankelijk van het medium: hij werkt over ESP-NOW, LoRa of elk ander systeem dat pakketten verzendt, en zelfs via een enkele standaard rode LED per board met behulp van de PacketLED-bibliotheek.
Kernpunten van de koppeling
- Eenvoudige interactie: De koppeling vereist een knop op elk board en een persoon die een korte code vergelijkt. Er is geen app, QR-code, wachtwoord of vooraf geïnstalleerde sleutel in de firmware nodig.
- Sleutels via licht: Met
PacketLED verzendt, ontvangt en toont dezelfde LED de code. Er wordt geen radiosignaal uitgezonden. Een aanvaller zou beide LED's fysiek moeten kunnen bereiken met eigen lichtbronnen direct voor de gebruiker, waarbij de code de poging alsnog zou verraden.
- Menselijke controle: Beide boards knipperen synchroon dezelfde 20-staps code. De kans dat een apparaat in het midden twee codes exact gelijk kan maken, is één op een miljoen.
- Meerdere boards: Elk board heeft een eigen permanente identiteit en kan tot 8 peers (partners) onthouden, elk met een eigen sleutel. Het opnieuw koppelen met een bekend board vervangt de bestaande sleutel, mits beide zijden dit bevestigen.
- Medium-onafhankelijk: Na de koppeling kunnen berichten versleuteld en geauthenticeerd worden verzonden via LED's, ESP-NOW (tientallen meters), LoRa (kilometers) of een eigen transportmiddel. Indien LED's niet beschikbaar zijn, kan de koppeling zelf ook via radio verlopen.
- Standaard cryptografie: Gebruik van X25519, HKDF en AES-256-GCM (de bouwstenen van TLS 1.3) inclusief replay-protectie. Koppelsleutels overleven resets en kunnen versleuteld worden opgeslagen met een sleutel die in de chip zelf is bewaard.
- Minimale code: Gebruik
provision() in setup(), en vervolgens send() en receive() voor berichten. Er is geen koppeling-code nodig in de loop().
Status: Beta (0.5). Getest op: ESP32, ESP32-C3 en ESP32-C6 boards (koppeling via LED's tot 2m, ESP-NOW, versleutelde opslag). Nog niet getest op hardware: LoRa.
---
Wat het doet
Twee boards die met elkaar communiceren hebben een gedeeld geheim (secret key) nodig. Zonder deze sleutel kan iedereen binnen bereik berichten meelezen of vervalsen. Het veilig overbrengen van deze sleutel is vaak het lastigste punt; in firmware hardcoderen betekent dat elke device dezelfde sleutel heeft, en handmatige invoer vereist een scherm en toetsenbord.
SecurePair automatiseert dit gehele proces:
- De boards komen onderling een nieuwe sleutel overeen; de gebruiker bevestigt dit door een korte code te vergelijken.
- De sleutel wordt samen met de identiteit van het andere board opgeslagen en blijft behouden na een reset.
- Berichten worden versleuteld, geauthenticeerd en beschermd tegen replay-aanvallen via hetzelfde medium als de koppeling, of via een ander medium.
Waarom licht?
Hoewel SecurePair onafhankelijk is van het transportmedium (ondersteuning voor PacketLED, ESP-NOW en LoRa), is het systeem ontworpen met licht als uitgangspunt.
- Fysieke beperking: Licht gaat niet door muren.
PacketLED werkt tussen twee LED's die enkele centimeters van elkaar verwijderd zijn. Meeluisteren levert niets op omdat de sleuteluitwisseling veilig is; een "man-in-the-middle" aanval vereist fysieke toegang tot beide LED's met sensoren en eigen lichtbronnen, direct in het zicht van de gebruiker.
- Geen radiostraling: Tijdens het overeenkomen van de sleutels wordt geen radiosignaal uitgezonden dat kan worden opgevangen of gestoord.
- Visuele bevestiging: De LED die de sleutels transporteerde, toont ook de code via 20 korte en lange knipperimpulsen. De gebruiker vergelijkt de twee LED's naast elkaar; een verschil is direct zichtbaar zonder dat er getypt of gelezen hoeft te worden.
- Minimale hardware: Slechts één LED en één weerstand per board zijn nodig. De LED kan tevens dienen als statusindicator.
Gebruiksgevallen
- Sensornodes en gateways: Koppel elke node met de gateway op het bureau (LED-naar-LED) en installeer deze daarna. Metingen reizen versleuteld via ESP-NOW of LoRa, waardoor fake nodes geen data kunnen injecteren.
- Afstandsbedieningen en actuatoren: Voor relais, poortopeners of sloten. Commando's zijn geauthenticeerd en worden slechts één keer geaccepteerd, waardoor opgenomen commando's niet later kunnen worden afgespeeld (anti-replay).
- Apparaten zonder scherm of toetsenbord: Een LED en een knop volstaan om een sleutel in te stellen door het apparaat tegen de controller te houden.
- Vervangen van boards in het veld: Een nieuw board koppelt bij de eerste start. Een bestaand board kan opnieuw koppelen als het wordt opgestart terwijl de knop wordt ingedrukt.
- Hub-structuur: Elk board kan tot 8 peers onthouden, elk met een eigen unieke sleutel.
- Educatie: Een compacte, leesbare implementatie van key agreement, short authentication strings en authenticated encryption, inclusief PC-tests.
Wat de gebruiker ziet
- Druk op de knop van beide boards binnen enkele seconden van elkaar.
- Twee knipperimpulsen, gevolgd door een aftelling van drie: plaats de LED's tegenover elkaar.
- De LED's flikkeren tijdens de sleuteluitwisseling, pauzeren, en knipperen vervolgens samen de code: 20 korte en lange impulsen.
- Zelfde code: Druk op beide boards. Verschillende code: Houd de knop op één van de boards ingedrukt.
- Drie korte knipperimpulsen en één lange: opgeslagen. Een snelle flikkering: mislukt, er is niets gewijzigd.
Om later opnieuw te koppelen (met een nieuwe sleutel of ander board), houd de knop ingedrukt tijdens het inschakelen of resetten van beide boards (binnen 20 seconden).
Opmerking: Een korte druk tijdens de code telt niet, omdat de gebruiker de volledige code moet bekijken. Bij een RGB LED heeft elke knipperimpuls ook een kleur, waardoor verschillen nog sneller opvallen. Zonder LED's kan de code als zes cijfers worden geprint.
Technische specificaties
Ondersteuning
- Transporten:
PacketLED (één LED), ESP-NOW, LoRa (SX1276/78, nog niet hardware-getest).
- Codeweergave: Standaard LED, WS2812 RGB LED, of zes cijfers via elke
Print interface.
- Statusweergave: Standaard LED, WS2812 RGB LED.
- Input: Push-button (korte en lange druk).
- Opslag: ESP32 NVS, onversleuteld of versleuteld met een sleutel die de chip nooit verlaat.
Peer-beheer
- Meerdere peers: Ondersteuning voor tot 8 peers (configureerbaar tot 16). Herkent reeds gekoppelde boards; een nieuwe koppeling vervangt de bestaande sleutel in plaats van een nieuwe record toe te voegen.
- Veilige sleutelvervanging: De oude sleutel blijft geldig totdat beide boards de nieuwe hebben opgeslagen. Een afgebroken koppeling laat de bestaande sleutels intact.
- Efficiëntie: Buiten het koppelproces voert SecurePair geen eigen code uit en is de
loop() vrij.
Cryptografie
Alleen standaard, goed bestudeerde primitieven worden gebruikt:
| Doel | Algoritme | Standaard |
| Sleutelovereenkomst | X25519 (Curve25519 Diffie-Hellman) | RFC 7748 |
| Hashing, commitments, transcript | SHA-256 | FIPS 180-4 |
| Authenticatie van koppelberichten | HMAC-SHA256 | RFC 2104 |
| Sleutelafleiding | HKDF-SHA256 | RFC 5869 |
| Berichtversleuteling en authenticatie | AES-256-GCM | FIPS 197, NIST SP 800-38D |
X25519 en AES-GCM zijn afkomstig van Mbed TLS (onderdeel van de ESP32 core) en maken gebruik van de hardware AES van de ESP32. SHA-256, HMAC en HKDF zijn geïmplementeerd in de bibliotheek en gecontroleerd tegen referentiewaarden.
Implementatiedetails
- Koppeling: Elke koppeling gebruikt nieuwe X25519-sleutels. Eén board committeert zich aan zijn sleutel via een hash voordat hij die van de ander ziet. Dit voorkomt dat iemand een sleutel kiest om de codes kunstmatig gelijk te maken. Hierdoor is een 20-bit code (kans van 1 op 1.048.576 per poging) voldoende.
- Identiteit: Elk board heeft een permanente identiteitssleutel. Identiteiten worden versleuteld verzonden tijdens de koppeling.
- Transcript: Alles wat wordt uitgewisseld, inclusief de protocolversie, wordt via HKDF in de sleutels gehasht. Een wijziging in het bericht of een downgrade-aanval resulteert in andere sleutels, waardoor de koppeling mislukt.
- Bevestiging: Bevestigingen zijn geauthenticeerd via HMAC. Een board slaat de nieuwe sleutel pas op nadat de andere gebruiker ook heeft bevestigd.
- Berichten: Elke richting heeft een eigen AES-256-GCM sleutel. De 96-bit nonce bestaat uit een boot-counter in flash plus een berichtenteller, zodat deze nooit wordt herhaald, zelfs niet na resets. Elk bericht bevat een 128-bit tag.
- Sleutels in rust: Indien de chip een eigen eFuse-sleutel heeft, versleutelt
NvsPairStorage elk record met AES-256-GCM. De opslagsleutel wordt via HKDF afgeleid van een HMAC die door de HMAC-peripheral van de chip wordt berekend.
- Hygiëne: Tags worden in constante tijd vergeleken, ongeldige sleutels worden geweigerd en tijdelijke sleutels worden na gebruik uit het RAM gewist. Willekeurige getallen komen uit de ESP32-generator, gemengd met ruis van de LED via SHA-256.
Wat niet beschermd wordt
- Een gebruiker die bevestigt zonder te kijken.
- Iemand die de flash van een board uitleest (tenzij eFuse-sleutels worden gebruikt).
- Berichten die eerder zijn opgenomen (geen forward secrecy). De berichten-sleutel is opgeslagen, dus wie deze later uitleest, kan oude berichten ontsleutelen. Opnieuw koppelen vervangt de sleutel.
Vereisten
- Een ESP32-board met de Arduino-ESP32 core 3.x. Gecompileerd voor ESP32, ESP32-C3 en ESP32-C6 met core 3.3.12.
- Voor versleutelde opslag is een chip met een HMAC-peripheral nodig: ESP32-S2, S3, C3, C5, C6, H2 of P4.
- Een push-button. Plaats deze niet op een boot-strapping pin (zoals BOOT), omdat dit de downloadmodus kan activeren in plaats van de sketch.
- Voor koppeling via licht: de
PacketLED bibliotheek (1.1.0 of later) en één LED met weerstand per board.
- Voor LoRa: de LoRa-bibliotheek van Sandeep Mistry.
Installatie
- Arduino IDE: Open de Library Manager, zoek naar
SecurePair en klik op Install. Installeer ook PacketLED (en optioneel LoRa) wanneer gevraagd.
- PlatformIO: Voeg de bibliotheek toe aan
platformio.ini:
lib_deps = toggio/SecurePair
- Handmatig: Download de repository als ZIP-bestand en voeg deze toe via
Sketch > Include Library > Add .ZIP Library.
Gebruik
Koppeling via licht, berichten via ESP-NOW
Voor twee ESP32-boards met elk een LED op de PacketLED pinnen en een knop:
#include <PacketLED.h>
#include <SecurePairLed.h>
#include <transport/EspNowTransport.h>
ArduinoLedPhy phy(32, 33); // LED anode (ADC1 pin), kathode; ESP32-C3/C6: 0, 1
PacketLED led(phy);
PacketLedTransport optical(led); // koppeling via LED
EspNowTransport radio; // berichten via ESP-NOW
LedDisplay display(optical); // code en status op dezelfde LED
NvsPairStorage storage; // sleutels overleven reset
SecurePair pairing(optical, storage, display, display);
SecureLink channel(pairing, radio); // versleutelde berichten
ButtonInput button(13); // knop tussen GPIO13 en GND; ESP32-C3/C6: 3
void setup() {
button.begin();
led.begin();
pairing.begin();
pairing.provision(button); // koppelt bij eerste start of knop ingedrukt
radio.begin(); // Wi-Fi starten pas na koppeling om LED's niet te storen
channel.sync();
}
void loop() {
// Voorbeeld: korte druk verzendt "hello" naar elke gekoppelde peer
if (button.read() == PairButton::Short) {
PeerInfo peer;
for (size_t i = 0; pairing.peerInfo(i, peer); ++i) channel.send(peer.id, "hello");
}
// Berichten ontvangen:
uint8_t buf[256];
PeerId from;
int n = channel.receive(buf, sizeof(buf), from);
if (n > 0) {
// n bytes van board `from`, ontsleuteld en gecontroleerd
}
}
Toelichting op de code:
provision() handelt de koppeling af bij de eerste start of wanneer de knop bij het opstarten is ingedrukt.
loop() bevat geen koppeling-code, waardoor de knop volledig beschikbaar blijft voor de applicatie.
radio.begin() komt ná de koppeling omdat PacketLED timing op microseconden nauwkeurig is en Wi-Fi-interrupts dit kunnen verstoren.
Andere media
Voor koppeling via ESP-NOW en berichten via LoRa (zonder LED's):
#include <LoRa.h>
#include <SecureLink.h>
#include <SecurePair.h>
#include <storage/NvsPairStorage.h>
#include <transport/EspNowTransport.h>
#include <transport/LoRaTransport.h>
#include <ui/ButtonInput.h>
#include <ui/GpioLedSink.h>
#include <ui/LedDisplay.h>
using namespace securepair;
EspNowTransport radio; // koppeling
LoRaTransport lora; // berichten
GpioLedSink statusLed(LED_BUILTIN); // status LED
LedDisplay display(statusLed); // code en status op board LED
NvsPairStorage storage;
SecurePair pairing(radio, storage, display, display);
SecureLink channel(pairing, lora);
ButtonInput button(13);
void setup() {
button.begin();
statusLed.begin();
LoRa.begin(868E6); // frequentie en pinnen
lora.begin();
radio.begin();
pairing.begin(PairConfig::forRadio()); // kortere pauzes dan bij LED's
pairing.provision(button);
channel.sync();
}
void loop() {
// channel.send() en channel.receive() zoals hierboven
}
Versleutelde sleutelopslag
NvsPairStorage bewaart sleutels standaard onversleuteld. Iemand met fysieke toegang tot het board kan deze dan uitlezen via USB. Op chips met een HMAC-peripheral (ESP32-S2, S3, C3, C5, C6, H2, P4) kan dit worden voorkomen met een chip-sleutel:
- Upload het
ChipKeySetup voorbeeld naar elk board, typ burn en bevestig.
- Er wordt een willekeurige 256-bit sleutel in een eFuse key block geschreven. Deze kan niet worden uitgelezen, alleen gebruikt door de HMAC-peripheral. Let op: het schrijven van eFuses is onomkeerbaar.
Vanaf dat moment versleutelt NvsPairStorage elk record met AES-256-GCM. Een kopie van de flash werkt dan niet op een ander board.
Transporten
Een transport verplaatst pakketten. SecurePair kan verschillende transporten gebruiken voor koppeling en berichten.
| Transport | Bereik | Berichtgrootte | Opmerkingen |
PacketLedTransport | enkele cm tot 2m (zichtlijn) | 35 bytes | één LED per board |
EspNowTransport | tientallen meters | 217 bytes | gedeeld Wi-Fi kanaal |
LoRaTransport | kilometers | 216 bytes | let op duty cycle (niet hardware-getest) |
Elk medium dat pakketten van 58 bytes of meer kan verzenden (bijv. Bluetooth, UART) kan worden toegevoegd.
Voorbeelden
| Voorbeeld | Koppeling | Berichten | Hardware | Provisioning |
LedOnly | LED | LED | LED + knop per board | LED |
LedPairEspNowLink | LED | ESP-NOW | LED + knop | LED |
LedPairLoRaLink | LED | LoRa | LED + knop + SX1276/78 | LED |
EspNowOnly | ESP-NOW | ESP-NOW | Knop | ESP-NOW |
EspNowPairLoRaLink | ESP-NOW | LoRa | SX1276/78 + knop | ESP-NOW |
WaveshareC3Zero | LED | LED | Waveshare ESP32-C3-Zero | RGB LED |
ChipKeySetup | - | - | schrijft de chip-sleutel (éénmalig) | - |
CryptoSelfTest | - | - | test cryptografie op het board | - |
Probleemoplossing
- Serial Monitor: Controleer eerst de output op 115200 baud.
- Koppeling mislukt (no peer): Start de koppeling op beide boards binnen 20 seconden. Houd bij
PacketLED de LED's vlak tegenover elkaar en scherm ze af van direct zonlicht.
- Codes verschillen: Wijs de koppeling af met een lange druk. Dit kan gebeuren als er een andere koppeling in de buurt plaatsvindt.
- Protocolfout: Meestal veroorzaakt door andere boards die in de buurt koppelen. Probeer het verder uit elkaar.
- Geen output op ESP32-C3/C6: Schakel
Tools > USB CDC On Boot in.
- Sketch start niet bij ingedrukte knop: De knop zit waarschijnlijk op een boot-strapping pin. Verplaats deze naar een andere pin.
- Berichten worden geweigerd na reboot: Roep
SecureLink::sync() aan bij opstarten en gebruik receive() regelmatig.
Beperkingen
- Momenteel alleen voor ESP32.
- Zonder chip-sleutel worden koppelsleutels onversleuteld opgeslagen. De originele ESP32 heeft geen HMAC-peripheral; gebruik daar NVS- en flash-encryptie.
- Na een reboot wordt het eerste bericht van elke peer geweigerd en beantwoord met een "challenge".
SecureLink::sync() regelt dit.
- Op broadcast-media (ESP-NOW/LoRa) bevestigt elk board in bereik een frame. "Delivered" betekent hier "ontvangen door iemand".
- Bij een fabrieksreset houden andere boards het oude record vast tot
forget() wordt aangeroepen.
- Bij koppeling via LED's is de radio uit, waardoor de random generator van de ESP32 niet optimaal is. Er wordt ruis van de LED via SHA-256 toegevoegd, maar de exacte kwaliteit hiervan is niet gemeten.
Gerelateerd werk
SecurePair bouwt voort op bestaande concepten van menselijke verificatie via korte codes:
- S. Vaudenay (2005): Waarom een korte code volstaat als beide zijden zich aan hun sleutel hebben gecommitteerd.
- J. M. McCune et al. (2005): Visuele kanalen voor menselijke verificatie.
- R. Prasad et al. (2008): Gebruik van synchrone audiovisuele patronen (knipperen).
SecurePair combineert dit door dezelfde LED te gebruiken voor zowel transport als verificatie, permanente identiteiten bij te houden en berichten over elk gewenst medium te verzenden.
SecurePair: Cryptografisch veilige koppeling en communicatie tussen ESP32-boards
Sleutels worden overeengekomen via een elliptic-curve exchange (X25519) en berichten worden versleuteld met AES-256-GCM. De bibliotheek is onafhankelijk van het medium: hij werkt over ESP-NOW, LoRa of elk ander systeem dat pakketten verzendt, en zelfs via een enkele standaard rode LED per board met behulp van de PacketLED-bibliotheek.
Kernpunten van de koppeling
- Eenvoudige interactie: De koppeling vereist een knop op elk board en een persoon die een korte code vergelijkt. Er is geen app, QR-code, wachtwoord of vooraf geïnstalleerde sleutel in de firmware nodig.
- Sleutels via licht: Met
PacketLED verzendt, ontvangt en toont dezelfde LED de code. Er wordt geen radiosignaal uitgezonden. Een aanvaller zou beide LED's fysiek moeten kunnen bereiken met eigen lichtbronnen direct voor de gebruiker, waarbij de code de poging alsnog zou verraden.
- Menselijke controle: Beide boards knipperen synchroon dezelfde 20-staps code. De kans dat een apparaat in het midden twee codes exact gelijk kan maken, is één op een miljoen.
- Meerdere boards: Elk board heeft een eigen permanente identiteit en kan tot 8 peers (partners) onthouden, elk met een eigen sleutel. Het opnieuw koppelen met een bekend board vervangt de bestaande sleutel, mits beide zijden dit bevestigen.
- Medium-onafhankelijk: Na de koppeling kunnen berichten versleuteld en geauthenticeerd worden verzonden via LED's, ESP-NOW (tientallen meters), LoRa (kilometers) of een eigen transportmiddel. Indien LED's niet beschikbaar zijn, kan de koppeling zelf ook via radio verlopen.
- Standaard cryptografie: Gebruik van X25519, HKDF en AES-256-GCM (de bouwstenen van TLS 1.3) inclusief replay-protectie. Koppelsleutels overleven resets en kunnen versleuteld worden opgeslagen met een sleutel die in de chip zelf is bewaard.
- Minimale code: Gebruik
provision() in setup(), en vervolgens send() en receive() voor berichten. Er is geen koppeling-code nodig in de loop().
Status: Beta (0.5). Getest op: ESP32, ESP32-C3 en ESP32-C6 boards (koppeling via LED's tot 2m, ESP-NOW, versleutelde opslag). Nog niet getest op hardware: LoRa.
---
Wat het doet
Twee boards die met elkaar communiceren hebben een gedeeld geheim (secret key) nodig. Zonder deze sleutel kan iedereen binnen bereik berichten meelezen of vervalsen. Het veilig overbrengen van deze sleutel is vaak het lastigste punt; in firmware hardcoderen betekent dat elke device dezelfde sleutel heeft, en handmatige invoer vereist een scherm en toetsenbord.
SecurePair automatiseert dit gehele proces:
- De boards komen onderling een nieuwe sleutel overeen; de gebruiker bevestigt dit door een korte code te vergelijken.
- De sleutel wordt samen met de identiteit van het andere board opgeslagen en blijft behouden na een reset.
- Berichten worden versleuteld, geauthenticeerd en beschermd tegen replay-aanvallen via hetzelfde medium als de koppeling, of via een ander medium.
Waarom licht?
Hoewel SecurePair onafhankelijk is van het transportmedium (ondersteuning voor PacketLED, ESP-NOW en LoRa), is het systeem ontworpen met licht als uitgangspunt.
- Fysieke beperking: Licht gaat niet door muren.
PacketLED werkt tussen twee LED's die enkele centimeters van elkaar verwijderd zijn. Meeluisteren levert niets op omdat de sleuteluitwisseling veilig is; een "man-in-the-middle" aanval vereist fysieke toegang tot beide LED's met sensoren en eigen lichtbronnen, direct in het zicht van de gebruiker.
- Geen radiostraling: Tijdens het overeenkomen van de sleutels wordt geen radiosignaal uitgezonden dat kan worden opgevangen of gestoord.
- Visuele bevestiging: De LED die de sleutels transporteerde, toont ook de code via 20 korte en lange knipperimpulsen. De gebruiker vergelijkt de twee LED's naast elkaar; een verschil is direct zichtbaar zonder dat er getypt of gelezen hoeft te worden.
- Minimale hardware: Slechts één LED en één weerstand per board zijn nodig. De LED kan tevens dienen als statusindicator.
Gebruiksgevallen
- Sensornodes en gateways: Koppel elke node met de gateway op het bureau (LED-naar-LED) en installeer deze daarna. Metingen reizen versleuteld via ESP-NOW of LoRa, waardoor fake nodes geen data kunnen injecteren.
- Afstandsbedieningen en actuatoren: Voor relais, poortopeners of sloten. Commando's zijn geauthenticeerd en worden slechts één keer geaccepteerd, waardoor opgenomen commando's niet later kunnen worden afgespeeld (anti-replay).
- Apparaten zonder scherm of toetsenbord: Een LED en een knop volstaan om een sleutel in te stellen door het apparaat tegen de controller te houden.
- Vervangen van boards in het veld: Een nieuw board koppelt bij de eerste start. Een bestaand board kan opnieuw koppelen als het wordt opgestart terwijl de knop wordt ingedrukt.
- Hub-structuur: Elk board kan tot 8 peers onthouden, elk met een eigen unieke sleutel.
- Educatie: Een compacte, leesbare implementatie van key agreement, short authentication strings en authenticated encryption, inclusief PC-tests.
Wat de gebruiker ziet
- Druk op de knop van beide boards binnen enkele seconden van elkaar.
- Twee knipperimpulsen, gevolgd door een aftelling van drie: plaats de LED's tegenover elkaar.
- De LED's flikkeren tijdens de sleuteluitwisseling, pauzeren, en knipperen vervolgens samen de code: 20 korte en lange impulsen.
- Zelfde code: Druk op beide boards. Verschillende code: Houd de knop op één van de boards ingedrukt.
- Drie korte knipperimpulsen en één lange: opgeslagen. Een snelle flikkering: mislukt, er is niets gewijzigd.
Om later opnieuw te koppelen (met een nieuwe sleutel of ander board), houd de knop ingedrukt tijdens het inschakelen of resetten van beide boards (binnen 20 seconden).
Opmerking: Een korte druk tijdens de code telt niet, omdat de gebruiker de volledige code moet bekijken. Bij een RGB LED heeft elke knipperimpuls ook een kleur, waardoor verschillen nog sneller opvallen. Zonder LED's kan de code als zes cijfers worden geprint.
Technische specificaties
Ondersteuning
- Transporten:
PacketLED (één LED), ESP-NOW, LoRa (SX1276/78, nog niet hardware-getest).
- Codeweergave: Standaard LED, WS2812 RGB LED, of zes cijfers via elke
Print interface.
- Statusweergave: Standaard LED, WS2812 RGB LED.
- Input: Push-button (korte en lange druk).
- Opslag: ESP32 NVS, onversleuteld of versleuteld met een sleutel die de chip nooit verlaat.
Peer-beheer
- Meerdere peers: Ondersteuning voor tot 8 peers (configureerbaar tot 16). Herkent reeds gekoppelde boards; een nieuwe koppeling vervangt de bestaande sleutel in plaats van een nieuwe record toe te voegen.
- Veilige sleutelvervanging: De oude sleutel blijft geldig totdat beide boards de nieuwe hebben opgeslagen. Een afgebroken koppeling laat de bestaande sleutels intact.
- Efficiëntie: Buiten het koppelproces voert SecurePair geen eigen code uit en is de
loop() vrij.
Cryptografie
Alleen standaard, goed bestudeerde primitieven worden gebruikt:
| Doel | Algoritme | Standaard |
| Sleutelovereenkomst | X25519 (Curve25519 Diffie-Hellman) | RFC 7748 |
| Hashing, commitments, transcript | SHA-256 | FIPS 180-4 |
| Authenticatie van koppelberichten | HMAC-SHA256 | RFC 2104 |
| Sleutelafleiding | HKDF-SHA256 | RFC 5869 |
| Berichtversleuteling en authenticatie | AES-256-GCM | FIPS 197, NIST SP 800-38D |
X25519 en AES-GCM zijn afkomstig van Mbed TLS (onderdeel van de ESP32 core) en maken gebruik van de hardware AES van de ESP32. SHA-256, HMAC en HKDF zijn geïmplementeerd in de bibliotheek en gecontroleerd tegen referentiewaarden.
Implementatiedetails
- Koppeling: Elke koppeling gebruikt nieuwe X25519-sleutels. Eén board committeert zich aan zijn sleutel via een hash voordat hij die van de ander ziet. Dit voorkomt dat iemand een sleutel kiest om de codes kunstmatig gelijk te maken. Hierdoor is een 20-bit code (kans van 1 op 1.048.576 per poging) voldoende.
- Identiteit: Elk board heeft een permanente identiteitssleutel. Identiteiten worden versleuteld verzonden tijdens de koppeling.
- Transcript: Alles wat wordt uitgewisseld, inclusief de protocolversie, wordt via HKDF in de sleutels gehasht. Een wijziging in het bericht of een downgrade-aanval resulteert in andere sleutels, waardoor de koppeling mislukt.
- Bevestiging: Bevestigingen zijn geauthenticeerd via HMAC. Een board slaat de nieuwe sleutel pas op nadat de andere gebruiker ook heeft bevestigd.
- Berichten: Elke richting heeft een eigen AES-256-GCM sleutel. De 96-bit nonce bestaat uit een boot-counter in flash plus een berichtenteller, zodat deze nooit wordt herhaald, zelfs niet na resets. Elk bericht bevat een 128-bit tag.
- Sleutels in rust: Indien de chip een eigen eFuse-sleutel heeft, versleutelt
NvsPairStorage elk record met AES-256-GCM. De opslagsleutel wordt via HKDF afgeleid van een HMAC die door de HMAC-peripheral van de chip wordt berekend.
- Hygiëne: Tags worden in constante tijd vergeleken, ongeldige sleutels worden geweigerd en tijdelijke sleutels worden na gebruik uit het RAM gewist. Willekeurige getallen komen uit de ESP32-generator, gemengd met ruis van de LED via SHA-256.
Wat niet beschermd wordt
- Een gebruiker die bevestigt zonder te kijken.
- Iemand die de flash van een board uitleest (tenzij eFuse-sleutels worden gebruikt).
- Berichten die eerder zijn opgenomen (geen forward secrecy). De berichten-sleutel is opgeslagen, dus wie deze later uitleest, kan oude berichten ontsleutelen. Opnieuw koppelen vervangt de sleutel.
Vereisten
- Een ESP32-board met de Arduino-ESP32 core 3.x. Gecompileerd voor ESP32, ESP32-C3 en ESP32-C6 met core 3.3.12.
- Voor versleutelde opslag is een chip met een HMAC-peripheral nodig: ESP32-S2, S3, C3, C5, C6, H2 of P4.
- Een push-button. Plaats deze niet op een boot-strapping pin (zoals BOOT), omdat dit de downloadmodus kan activeren in plaats van de sketch.
- Voor koppeling via licht: de
PacketLED bibliotheek (1.1.0 of later) en één LED met weerstand per board.
- Voor LoRa: de LoRa-bibliotheek van Sandeep Mistry.
Installatie
- Arduino IDE: Open de Library Manager, zoek naar
SecurePair en klik op Install. Installeer ook PacketLED (en optioneel LoRa) wanneer gevraagd.
- PlatformIO: Voeg de bibliotheek toe aan
platformio.ini:
lib_deps = toggio/SecurePair
- Handmatig: Download de repository als ZIP-bestand en voeg deze toe via
Sketch > Include Library > Add .ZIP Library.
Gebruik
Koppeling via licht, berichten via ESP-NOW
Voor twee ESP32-boards met elk een LED op de PacketLED pinnen en een knop:
#include <PacketLED.h>
#include <SecurePairLed.h>
#include <transport/EspNowTransport.h>
ArduinoLedPhy phy(32, 33); // LED anode (ADC1 pin), kathode; ESP32-C3/C6: 0, 1
PacketLED led(phy);
PacketLedTransport optical(led); // koppeling via LED
EspNowTransport radio; // berichten via ESP-NOW
LedDisplay display(optical); // code en status op dezelfde LED
NvsPairStorage storage; // sleutels overleven reset
SecurePair pairing(optical, storage, display, display);
SecureLink channel(pairing, radio); // versleutelde berichten
ButtonInput button(13); // knop tussen GPIO13 en GND; ESP32-C3/C6: 3
void setup() {
button.begin();
led.begin();
pairing.begin();
pairing.provision(button); // koppelt bij eerste start of knop ingedrukt
radio.begin(); // Wi-Fi starten pas na koppeling om LED's niet te storen
channel.sync();
}
void loop() {
// Voorbeeld: korte druk verzendt "hello" naar elke gekoppelde peer
if (button.read() == PairButton::Short) {
PeerInfo peer;
for (size_t i = 0; pairing.peerInfo(i, peer); ++i) channel.send(peer.id, "hello");
}
// Berichten ontvangen:
uint8_t buf[256];
PeerId from;
int n = channel.receive(buf, sizeof(buf), from);
if (n > 0) {
// n bytes van board `from`, ontsleuteld en gecontroleerd
}
}
Toelichting op de code:
provision() handelt de koppeling af bij de eerste start of wanneer de knop bij het opstarten is ingedrukt.
loop() bevat geen koppeling-code, waardoor de knop volledig beschikbaar blijft voor de applicatie.
radio.begin() komt ná de koppeling omdat PacketLED timing op microseconden nauwkeurig is en Wi-Fi-interrupts dit kunnen verstoren.
Andere media
Voor koppeling via ESP-NOW en berichten via LoRa (zonder LED's):
#include <LoRa.h>
#include <SecureLink.h>
#include <SecurePair.h>
#include <storage/NvsPairStorage.h>
#include <transport/EspNowTransport.h>
#include <transport/LoRaTransport.h>
#include <ui/ButtonInput.h>
#include <ui/GpioLedSink.h>
#include <ui/LedDisplay.h>
using namespace securepair;
EspNowTransport radio; // koppeling
LoRaTransport lora; // berichten
GpioLedSink statusLed(LED_BUILTIN); // status LED
LedDisplay display(statusLed); // code en status op board LED
NvsPairStorage storage;
SecurePair pairing(radio, storage, display, display);
SecureLink channel(pairing, lora);
ButtonInput button(13);
void setup() {
button.begin();
statusLed.begin();
LoRa.begin(868E6); // frequentie en pinnen
lora.begin();
radio.begin();
pairing.begin(PairConfig::forRadio()); // kortere pauzes dan bij LED's
pairing.provision(button);
channel.sync();
}
void loop() {
// channel.send() en channel.receive() zoals hierboven
}
Versleutelde sleutelopslag
NvsPairStorage bewaart sleutels standaard onversleuteld. Iemand met fysieke toegang tot het board kan deze dan uitlezen via USB. Op chips met een HMAC-peripheral (ESP32-S2, S3, C3, C5, C6, H2, P4) kan dit worden voorkomen met een chip-sleutel:
- Upload het
ChipKeySetup voorbeeld naar elk board, typ burn en bevestig.
- Er wordt een willekeurige 256-bit sleutel in een eFuse key block geschreven. Deze kan niet worden uitgelezen, alleen gebruikt door de HMAC-peripheral. Let op: het schrijven van eFuses is onomkeerbaar.
Vanaf dat moment versleutelt NvsPairStorage elk record met AES-256-GCM. Een kopie van de flash werkt dan niet op een ander board.
Transporten
Een transport verplaatst pakketten. SecurePair kan verschillende transporten gebruiken voor koppeling en berichten.
| Transport | Bereik | Berichtgrootte | Opmerkingen |
PacketLedTransport | enkele cm tot 2m (zichtlijn) | 35 bytes | één LED per board |
EspNowTransport | tientallen meters | 217 bytes | gedeeld Wi-Fi kanaal |
LoRaTransport | kilometers | 216 bytes | let op duty cycle (niet hardware-getest) |
Elk medium dat pakketten van 58 bytes of meer kan verzenden (bijv. Bluetooth, UART) kan worden toegevoegd.
Voorbeelden
| Voorbeeld | Koppeling | Berichten | Hardware | Provisioning |
LedOnly | LED | LED | LED + knop per board | LED |
LedPairEspNowLink | LED | ESP-NOW | LED + knop | LED |
LedPairLoRaLink | LED | LoRa | LED + knop + SX1276/78 | LED |
EspNowOnly | ESP-NOW | ESP-NOW | Knop | ESP-NOW |
EspNowPairLoRaLink | ESP-NOW | LoRa | SX1276/78 + knop | ESP-NOW |
WaveshareC3Zero | LED | LED | Waveshare ESP32-C3-Zero | RGB LED |
ChipKeySetup | - | - | schrijft de chip-sleutel (éénmalig) | - |
CryptoSelfTest | - | - | test cryptografie op het board | - |
Probleemoplossing
- Serial Monitor: Controleer eerst de output op 115200 baud.
- Koppeling mislukt (no peer): Start de koppeling op beide boards binnen 20 seconden. Houd bij
PacketLED de LED's vlak tegenover elkaar en scherm ze af van direct zonlicht.
- Codes verschillen: Wijs de koppeling af met een lange druk. Dit kan gebeuren als er een andere koppeling in de buurt plaatsvindt.
- Protocolfout: Meestal veroorzaakt door andere boards die in de buurt koppelen. Probeer het verder uit elkaar.
- Geen output op ESP32-C3/C6: Schakel
Tools > USB CDC On Boot in.
- Sketch start niet bij ingedrukte knop: De knop zit waarschijnlijk op een boot-strapping pin. Verplaats deze naar een andere pin.
- Berichten worden geweigerd na reboot: Roep
SecureLink::sync() aan bij opstarten en gebruik receive() regelmatig.
Beperkingen
- Momenteel alleen voor ESP32.
- Zonder chip-sleutel worden koppelsleutels onversleuteld opgeslagen. De originele ESP32 heeft geen HMAC-peripheral; gebruik daar NVS- en flash-encryptie.
- Na een reboot wordt het eerste bericht van elke peer geweigerd en beantwoord met een "challenge".
SecureLink::sync() regelt dit.
- Op broadcast-media (ESP-NOW/LoRa) bevestigt elk board in bereik een frame. "Delivered" betekent hier "ontvangen door iemand".
- Bij een fabrieksreset houden andere boards het oude record vast tot
forget() wordt aangeroepen.
- Bij koppeling via LED's is de radio uit, waardoor de random generator van de ESP32 niet optimaal is. Er wordt ruis van de LED via SHA-256 toegevoegd, maar de exacte kwaliteit hiervan is niet gemeten.
Gerelateerd werk
SecurePair bouwt voort op bestaande concepten van menselijke verificatie via korte codes:
- S. Vaudenay (2005): Waarom een korte code volstaat als beide zijden zich aan hun sleutel hebben gecommitteerd.
- J. M. McCune et al. (2005): Visuele kanalen voor menselijke verificatie.
- R. Prasad et al. (2008): Gebruik van synchrone audiovisuele patronen (knipperen).
SecurePair combineert dit door dezelfde LED te gebruiken voor zowel transport als verificatie, permanente identiteiten bij te houden en berichten over elk gewenst medium te verzenden.