Sommario:

Comunicazione crittografata wireless Arduino: 5 passaggi
Comunicazione crittografata wireless Arduino: 5 passaggi

Video: Comunicazione crittografata wireless Arduino: 5 passaggi

Video: Comunicazione crittografata wireless Arduino: 5 passaggi
Video: Comunicazione Seriale tra Arduino e Raspberry (e programmare Arduino da Raspy) 2024, Dicembre
Anonim
Comunicazione crittografata wireless Arduino
Comunicazione crittografata wireless Arduino

Ciao a tutti, In questo secondo articolo ti spiegherò come utilizzare il chip Atecc608a per proteggere la tua comunicazione wireless. Per questo, userò NRF24L01+ per la parte Wireless e Arduino UNO.

Il microchip ATECC608A è stato progettato da MicroChip e dispone di molteplici strumenti di sicurezza. Ad esempio, questo chip può memorizzare chiavi ECC, chiavi AES (per AES 128) e hash SHA2.

L'articolo: NRF24L01 + Arduino UNO + ATECC608A

Durante una comunicazione tra due oggetti IoT, possono esistere più attacchi: Man Of the mild, Copy of information e altro.. Quindi la mia idea è molto semplice:

  1. Utilizzo di dati crittografati tra due o più oggetti IoT.
  2. Forniture a basso costo
  3. Può funzionare con un Arduino UNO

Nel mio caso, io uso

  • l'Atecc608a per memorizzare la mia chiave AES e per crittografare/decrittografare i miei dati.
  • l'Arduino Uno come Microcontrollore
  • Il NRF24L01 per inviare i miei dati

Devi seguire questi passaggi per questo progetto:

  1. Configura il chip ATECC608A
  2. Eseguire il circuito (Master Node e Slave Node)
  3. Codice parte
  4. Vai oltre!

Per i primi passi "Configura il chip ATECC608A", ho scritto un altro articolo che spiega ogni passaggio in ordine. Il link è qui:

Ora inizia!

Forniture

Per questo progetto hai bisogno di:

  • 2 Arduino UNO o Arduino NANO o Arduino Mega
  • Un po' di filo
  • 2 Atecc608a (ciascuno costa meno di 0,60$)
  • 2 NRF24L01+
  • 2 condensatori (10 μF)
  • taglieri

Link al mio articolo che spiega come configurare il chip ATECC608A -> Come configurare Atecc608a

Passaggio 1: 1. Configurare Atecc608a

1. Configurare l'Atecc608a
1. Configurare l'Atecc608a
1. Configurare l'Atecc608a
1. Configurare l'Atecc608a

Non descriverò in dettaglio tutti i passaggi da seguire per configurare un ATECC608A perché ho scritto un articolo completo che spiega tutti i passaggi per farlo. Per configurarlo è necessario seguire lo "Step 4" di questo articolo chiamato "2. Configurazione del Chip (Atecc608a)"

Il link è: Come configurare un ATECC608A

Inoltre, devi mettere la stessa configurazione per l'Atecc608a, lato master e lato slave, altrimenti non sarai in grado di decifrare i tuoi dati

Avvertimento:

Per configurare questo chip, devi seguire tutti i passaggi dell'articolo sopra in ordine. Se manca un passaggio o il chip non è bloccato, non sarai in grado di eseguire questo progetto

Resto:

Passaggio da seguire per questo:

  • Crea un modello di configurazione
  • Scrivi questo modello sul chip
  • Blocca la zona di configurazione
  • Scrivi la tua chiave AES (128 bit) in uno slot
  • Blocca l'area dati

Fase 2: 2. Progettazione del circuito (master e slave)

2. Progettazione del Circuito (Master e Slave)
2. Progettazione del Circuito (Master e Slave)
2. Progettazione del Circuito (Master e Slave)
2. Progettazione del Circuito (Master e Slave)

In questo progetto, avrai un nodo master e un nodo slave.

Il nodo master stamperà in chiaro i dati inviati dal nodo slave. Richiederà dati dal nodo slave ogni X volte.

Il nodo slave ascolterà la "rete" e quando riceverà un "Richiesta dati", lo genererà, lo crittograferà e lo invierà al nodo master.

Per entrambi i lati, master e slave il circuito è lo stesso:

  • Un arduino Nano
  • Un ATECC608A
  • Un NRF24L01

Ho collegato il circuito a questo passaggio (vedi immagine sopra).

Per l'ATECC608A per Arduino UNO, questo è un 8 pin soic. Ho aggiunto la "vista dall'alto" sopra:

  • ARDUINO 3.3V -> PIN 8 (Atecc608a)
  • ARDUINO GND -> PIN 4 (Atecc608a)
  • ARDUINO A4 (SDL) -> PIN 5 (Atecc608a)
  • ARDUINO A5 (SCL) -> PIN 6 (Atecc608a)

Per NRF24L01 ad Arduino:

  • ARDUINO 3.3V -> VCC (nrf24l01)
  • ARDUINO GND -> GND (nrf24l01)
  • ARDUINO 9 -> CE (nrf24l01)
  • ARDUINO 10 -> CSN (nrf24l01)
  • ARDUINO 11 -> MOSI (nrf24L01)
  • ARDUINO 12 -> MISO (nrf24l01)
  • ARDUINO 13 -> SCK (nrf24l01)
  • ARDUINO 3 -> IRQ (nrf24l01) -> solo per nodo Slave, non utilizzato in modalità Master

Perché usare il pin IRQ di NRF24L01

Il pin IRQ è molto utile, questo pin permette di dire (LOW) quando un pacchetto viene ricevuto dall'NRF24L01, quindi possiamo collegare un Interrupt a questo pin per svegliare il nodo slave.

Passaggio 3: 3. il Codice (Slave e Master)

3. il Codice (Slave e Master)
3. il Codice (Slave e Master)

Nodo Schiavo

Uso il risparmio energetico per il nodo slave perché non ha bisogno di ascoltare tutto il tempo.

Come funziona: il nodo slave ascolta e aspetta di ricevere un "pacchetto Wake UP". Questo pacchetto viene inviato dal nodo Master per richiedere dati allo slave.

Nel mio caso uso un array di due int:

// Pacchetto Wake UP

const int wake_packet[2] = {20, 02};

Se il mio nodo riceve un pacchetto,

  1. si sveglia, leggi questo pacchetto, se il pacchetto è un "Wake UP",
  2. genera i dati,
  3. crittografare i dati,
  4. inviare i dati al master, attendere un pacchetto ACK,
  5. dormire.

Per la crittografia AES, utilizzo una chiave nello slot numero 9.

Questo è il mio codice per il nodo Slave

#include "Arduino.h"#include "avr/sleep.h" #include "avr/wdt.h"

#include "SPI.h"

#include "nRF24L01.h" #include "RF24.h"

#include "Wire.h"

// Libreria ATECC608A

#include "ATECCX08A_Arduino/cryptoauthlib.h" #include "AES BASIC/aes_basic.h"

#define ID_NODE 255

#define AES_KEY (uint8_t)9

ATCAIfaceCfg cfg;

stato ATCA_STATUS;

radio RF24 (9, 10);

const uint64_t masteraddresse = 0x11111111111;

const uint64_t slaveaddresse = 0x1111111100;

/**

* \brief Funzione eseguita quando l'interrupt è impostato (IRQ LOW) * * */ void wakeUpIRQ() { while (radio.available()) { int data[32]; radio.read(&data, 32); if (data[0] == 20 && data[1] == 02) { float temp = 17,6; ronzio galleggiante = 16,4;

uint8_t dati[16];

uint8_t dati cifrati[16];

// Costruisci una stringa per impostare tutto il mio valore

// Ogni valore è separato da un "|" e "$" indica la fine dei dati // ATTENZIONE: deve essere inferiore a 11 di lunghezza String tmp_str_data = String(ID_NODE) + "|" + Stringa(temp, 1) + "|" + Stringa(ronzio, 1) + "$"; //dimensione di 11 Serial.println("tmp_str_data: " + tmp_str_data);

tmp_str_data.getBytes(data, sizeof(data));

// Cripta i dati

ATCA_STATUS status = aes_basic_encrypt(&cfg, data, sizeof(data), cypherdata, AES_KEY); if (status == ATCA_SUCCESS) { long rand = random((long)10000, (long)99999);

// genera un UUID basato sui primi tre numeri = nodo ID

String uuid = String(ID_NODE) + String(rand); // Dimensione di 8

uint8_t tmp_uuid[8];

uint8_t data_to_send[32];

uuid.getBytes(tmp_uuid, sizeof(tmp_uuid) + 1);

memcpy(data_to_send, tmp_uuid, sizeof(tmp_uuid));

memcpy(data_to_send + sizeof(tmp_uuid), cypherdata, sizeof(cypherdata)); // Interrompi l'ascolto radio.stopListening();

bool rslt;

// Invia dati rslt = radio.write(&data_to_send, sizeof(data_to_send)); // Inizia ad ascoltare radio.startListening(); if (rslt) { // Fine e modalità di sospensione Serial.println(F("Fatto")); } } } } }

configurazione nulla()

{ Serial.begin(9600);

// Inizia il costruttore per la libreria

cfg.iface_type = ATCA_I2C_IFACE; // Tipo di comunicazione -> Modalità I2C cfg.devtype = ATECC608A; // Tipo di chip cfg.atcai2c.slave_address = 0XC0; // indirizzo I2C (valore predefinito) cfg.atcai2c.bus = 1; cfg.atcai2c.baud = 100000; cfg.wake_delay = 1500; // Ritardo di risveglio (1500 ms) cfg.rx_retries = 20;

radio.begin();

radio.setDataRate(RF24_250KBPS); radio.maskIRQ(1, 1, 0); radio.enableAckPayload(); radio.setRetries(5, 5);

radio.openWritingPipe(masteraddresse);

radio.openReadingPipe(1, slaveaddresse); // Collega l'interrupt al pin 3 // Modifica 1 con O se vuoi l'interrupt al pin 2 // FALLING MODE = Pin at LOW attachInterrupt(1, wakeUpIRQ, FALLING); }

ciclo vuoto()

{ // Non c'è bisogno }

Nodo principale

Il nodo master si sveglia ogni 8 secondi per chiedere dati al nodo slave

Come funziona: Il nodo master invia un pacchetto "WakeUP" allo slave e dopo attende una risposta dello slave con i dati.

Nel mio caso uso un array di due int:

// Pacchetto Wake UP

const int wake_packet[2] = {20, 02};

Se il nodo slave invia un pacchetto ACK dopo che il master ha inviato un pacchetto WakeUp:

  1. Master impostato in modalità Listen e attendere una comunicazione
  2. Se la comunicazione
  3. Estrai il primo byte 8, saccheggia i primi tre byte degli 8 byte, se questo è il nodo ID
  4. Estrai i 16 byte di cifratura
  5. Decifra i dati
  6. Stampa i dati in Seriale
  7. Modalità risparmio

Per la crittografia AES, utilizzo una chiave nello slot numero 9.

Questo è il mio codice per il nodo Master

#include "Arduino.h"

#include "avr/sleep.h" #include "avr/wdt.h" #include "SPI.h" #include "nRF24L01.h" #include "RF24.h" #include "Wire.h" // Libreria ATECC608A #include "ATECCX08A_Arduino/cryptoauthlib.h" #include "AES BASIC/aes_basic.h" #define ID_NODE 255 #define AES_KEY (uint8_t)9 ATCAIfaceCfg cfg; stato ATCA_STATUS; radio RF24 (9, 10); const uint64_t masteraddresse = 0x11111111111; const uint64_t slaveaddresse = 0x1111111100; // Pacchetto Wake UP const int wake_packet[2] = {20, 02}; // watchdog interrupt ISR(WDT_vect) { wdt_disable(); // disabilita watchdog } void sleepmode() { // disabilita ADC ADCSRA = 0; // cancella vari flag di "reset" MCUSR = 0; // consenti le modifiche, disabilita il ripristino WDTCSR = bit(WDCE) | bit(WDE); // imposta la modalità di interruzione e un intervallo WDTCSR = bit(WDIE) | bit(WDP3) | bit(WDP0); // imposta WDIE e 8 secondi di ritardo wdt_reset(); // resetta il watchdog set_sleep_mode(SLEEP_MODE_PWR_DOWN); noInterrupt(); // la sequenza a tempo segue sleep_enable(); // disattiva l'abilitazione del brown-out nel software MCUCR = bit(BODS) | bit(BODSE); MCUCR = bit(BODS); interrompe(); // garantisce l'esecuzione dell'istruzione successiva sleep_cpu(); // annulla il sonno per precauzione sleep_disable(); } void setup() { Serial.begin(9600); // Inizia il costruttore per la libreria cfg.iface_type = ATCA_I2C_IFACE; // Tipo di comunicazione -> Modalità I2C cfg.devtype = ATECC608A; // Tipo di chip cfg.atcai2c.slave_address = 0XC0; // indirizzo I2C (valore predefinito) cfg.atcai2c.bus = 1; cfg.atcai2c.baud = 100000; cfg.wake_delay = 1500; // Ritardo di risveglio (1500 ms) cfg.rx_retries = 20; radio.begin(); radio.setDataRate(RF24_250KBPS); radio.maskIRQ(1, 1, 0); radio.enableAckPayload(); radio.setRetries(5, 5); radio.openWritingPipe(slaveaddresse); radio.openReadingPipe(1, masteraddresse); } void loop() { bool rslt; // Invia dati rslt = radio.write(&wake_packet, sizeof(wake_packet)); if (rslt) { // Inizia ad ascoltare radio.startListening(); while (radio.available()) { uint8_t risposta[32]; radio.read(&answer, sizeof(answer)); uint8_t node_id[3]; uint8_t cifra[16]; memcpy(node_id, risposta, 3); memcpy(cifra, risposta + 3, 16); if ((int)node_id == ID_NODE) { uint8_t output[16]; ATCA_STATUS status = aes_basic_decrypt(&cfg, cypher, 16, output, AES_KEY); if (status == ATCA_SUCCESS) { Serial.println("Dati decrittografati: "); for (size_t i = 0; i < 16; i++) { Serial.print((char)output); } } } } } else{ Serial.println("Riconoscimento non ricevuto per Wakup Packet"); } // Sleep mode 8 secondi sleepmode(); }

Se hai domande, sono qui per rispondere

Passaggio 4: 4. Vai oltre

Questo esempio è semplice in modo da poter migliorare questo progetto

Miglioramenti:

  • L'AES 128 è di base e puoi utilizzare un altro algoritmo di AES come AES CBC per essere più sicuro.
  • Cambiare il modulo wireless (il NRF24L01 è limitato da un payload di 23 Byte)

Se vedi miglioramenti da fare, spiegalo nell'area di discussione

Passaggio 5: conclusione

Spero che questo articolo ti sia utile. Scusa se ho sbagliato nel testo, ma l'inglese non è la mia lingua principale e parlo meglio di quanto scrivo.

Grazie per aver letto tutto.

Divertirsi.

Consigliato: