Spisu treści:

Szyfrowana komunikacja bezprzewodowa Arduino: 5 kroków
Szyfrowana komunikacja bezprzewodowa Arduino: 5 kroków

Wideo: Szyfrowana komunikacja bezprzewodowa Arduino: 5 kroków

Wideo: Szyfrowana komunikacja bezprzewodowa Arduino: 5 kroków
Wideo: Sterowanie przez Internet z dowolnego miejsca Free IoT Raspberry pi / Arduino Ethernet WiFi Zdalne 2024, Listopad
Anonim
Szyfrowana komunikacja bezprzewodowa Arduino
Szyfrowana komunikacja bezprzewodowa Arduino

Cześć wszystkim, W tym drugim artykule wyjaśnię, jak wykorzystać chip Atecc608a do zabezpieczenia komunikacji bezprzewodowej. W tym celu użyję NRF24L01+ dla części bezprzewodowej i Arduino UNO.

Mikrochip ATECC608A został zaprojektowany przez MicroChip i posiada wiele narzędzi zabezpieczających. Na przykład ten układ może przechowywać klucze ECC, klucze AES (dla AES 128) i skrót SHA2.

Artykuł: NRF24L01 + Arduino UNO + ATECC608A

Podczas komunikacji między dwoma obiektami IoT może wystąpić wiele ataków: Man Of the mild, Copy of information i więcej.. Mój pomysł jest więc bardzo prosty:

  1. Wykorzystanie zaszyfrowanych danych między dwoma lub więcej obiektami IoT.
  2. Tanie materiały eksploatacyjne
  3. Może współpracować z Arduino UNO

W moim przypadku używam

  • Atecc608a do przechowywania mojego klucza AES i szyfrowania/odszyfrowywania moich danych.
  • Arduino Uno jako mikrokontroler
  • NRF24L01 do wysłania moich danych

Musisz wykonać te kroki dla tego projektu:

  1. Skonfiguruj układ ATECC608A
  2. Wykonaj obwód (węzeł główny i węzeł podrzędny)
  3. Część kodu
  4. Idź dalej !

W przypadku pierwszych kroków „Ustaw układ ATECC608A” napisałem inny artykuł, który wyjaśnia każdy krok w kolejności. Link jest tutaj:

Teraz zacznij!

Kieszonkowe dzieci

Do tego projektu potrzebujesz:

  • 2 Arduino UNO lub Arduino NANO lub Arduino Mega
  • Niektóre druty
  • 2 Atecc608a (każdy kosztuje mniej niż 0,60$)
  • 2 NRF24L01+
  • 2 kondensatory (10 μF)
  • Deski do krojenia chleba

Link do mojego artykułu wyjaśniającego jak skonfigurować układ ATECC608A -> Jak skonfigurować Atecc608a

Krok 1: 1. Skonfiguruj Atecc608a

1. Skonfiguruj Atecc608a
1. Skonfiguruj Atecc608a
1. Skonfiguruj Atecc608a
1. Skonfiguruj Atecc608a

Nie będę szczegółowo opisywał każdego kroku, który należy wykonać, aby skonfigurować ATECC608A, ponieważ napisałem pełny artykuł, który wyjaśnia wszystkie kroki, aby to zrobić. Aby to skonfigurować, musisz wykonać „Krok 4” tego artykułu zatytułowany „2. Konfiguracja układu (Atecc608a)”

Link to: jak skonfigurować ATECC608A?

Ponadto musisz wprowadzić tę samą konfigurację dla Atecc608a, po stronie master i slave, w przeciwnym razie nie będziesz w stanie odszyfrować swoich danych

Ostrzeżenie:

Aby skonfigurować ten chip, musisz wykonać kolejno wszystkie kroki powyższego artykułu. Jeśli brakuje jednego kroku lub chip nie jest zablokowany, nie będziesz w stanie wykonać tego projektu

Pozostała część:

Krok do naśladowania w tym celu:

  • Utwórz szablon konfiguracji
  • Napisz ten szablon do chipa
  • Zablokuj strefę konfiguracji
  • Wpisz swój klucz AES (128 bitów) w gnieździe
  • Zablokuj strefę danych

Krok 2: 2. Projekt obwodu (nadrzędny i podrzędny)

2. Projekt obwodu (nadrzędny i podrzędny)
2. Projekt obwodu (nadrzędny i podrzędny)
2. Projekt obwodu (nadrzędny i podrzędny)
2. Projekt obwodu (nadrzędny i podrzędny)

W tym projekcie będziesz miał węzeł główny i węzeł podrzędny.

Węzeł główny wydrukuje dane wysłane przez węzeł podrzędny w postaci wyraźnej. Co X będzie żądać danych od węzła podrzędnego.

Węzeł podrzędny będzie nasłuchiwał „sieci”, a gdy otrzyma „dane żądania”, wygeneruje je, zaszyfruje i wyśle do węzła głównego.

Dla obu stron, master i slave, obwód jest taki sam:

  • Jeden arduino Nano
  • Jeden ATECC608A
  • Jeden NRF24L01

Do tego kroku podłączyłem obwód (por. obrazek powyżej).

Dla ATECC608A do Arduino UNO jest to soic 8 pin. Dodałem "widok z góry" powyżej:

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

Dla NRF24L01 do 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) -> tylko dla węzła Slave, nieużywane w trybie Master

Dlaczego warto używać pinu IRQ w NRF24L01?

Pin IRQ jest bardzo przydatny, ten pin pozwala powiedzieć (LOW), kiedy pakiet zostanie odebrany przez NRF24L01, więc możemy dołączyć przerwanie do tego pinu, aby obudzić węzeł podrzędny.

Krok 3: 3. Kod (Slave i Master)

3. Kodeks (Slave and Master)
3. Kodeks (Slave and Master)

Węzeł podrzędny

Używam oszczędzania energii dla węzła podrzędnego, ponieważ nie musi on cały czas nasłuchiwać.

Jak to działa: węzeł podrzędny nasłuchuje i czeka na otrzymanie pakietu „Wake UP”. Ten pakiet jest wysyłany przez węzeł nadrzędny w celu zażądania danych od urządzenia podrzędnego.

W moim przypadku używam tablicy dwóch int:

// Pakiet wybudzania

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

Jeśli mój węzeł otrzyma pakiet,

  1. obudzi się, odczytaj ten pakiet, jeśli pakiet jest "Wake UP",
  2. generuje dane,
  3. szyfrować dane,
  4. wyślij dane do mastera, poczekaj na pakiet ACK,
  5. spać.

Do szyfrowania AES używam klucza w slocie numer 9.

To jest mój kod dla węzła Slave

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

#include "SPI.h"

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

#include "Drut.h"

// Biblioteka ATECC608A

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

#define ID_NODE 255

#define AES_KEY (uint8_t)9

ATCAIfaceCfg cfg;

status ATCA_STATUS;

radio RF24 (9, 10);

const uint64_t masteraddresse = 0x1111111111;

const uint64_t slaveaddresse = 0x11111111100;

/**

* \brief Funkcja wykonywana po ustawieniu przerwania (IRQ LOW) * * */ void wakeUpIRQ() { while (radio.available()) { int data[32]; radio.odczyt(&dane, 32); if (data[0] == 20 && data[1] == 02) { float temp = 17,6; szum pływaka = 16,4;

dane uint8_t[16];

zaszyfrowane dane uint8_t[16];

// Zbuduj ciąg, aby ustawić całą moją wartość

// Każda wartość jest oddzielona znakiem „|” a "$" oznacza koniec danych // UWAGA: Musi mieć mniej niż 11 długości String tmp_str_data = String(ID_NODE) + "|" + String(temp, 1) + "|" + String(hum, 1) + "$"; //rozmiar 11 Serial.println("tmp_str_data: " + tmp_str_data);

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

// Zaszyfruj dane

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

// wygeneruj UUID na podstawie trzech pierwszych liczb = ID węzła

Ciąg uuid = Ciąg (ID_NODE) + Ciąg (rand); // Rozmiar 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)); // Przestań słuchać radia.stopListening();

bool rslt;

// Wyślij dane rslt = radio.write(&data_to_send, sizeof(data_to_send)); // Rozpocznij słuchanie radio.startListening(); if (rslt) { // Koniec i tryb uśpienia Serial.println(F("Gotowe")); } } } } }

pusta konfiguracja()

{ Szeregowy.początek(9600);

// Uruchom konstruktora biblioteki

cfg.iface_type = ATCA_I2C_IFACE; // Rodzaj komunikacji -> tryb I2C cfg.devtype = ATECC608A; // Typ chipa cfg.atcai2c.slave_address = 0XC0; // adres I2C (wartość domyślna) cfg.atcai2c.bus = 1; cfg.atcai2c.baud = 100000; cfg.wake_delay = 1500; // Opóźnienie budzenia (1500 ms) cfg.rx_retries = 20;

radio.początek();

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

radio.openWritingPipe(adres główny);

radio.openReadingPipe(1, adres niewolnika); // Dołącz przerwanie do pinu 3 // Zmodyfikuj 1 przez O jeśli chcesz przerwać na pin 2 // FALLING MODE = Pin at LOW attachInterrupt(1, wakeUpIRQ, FALLING); }

pusta pętla()

{ // Nie ma potrzeby }

Węzeł główny

Węzeł główny budzi się co 8 sekund, aby poprosić o dane z węzła podrzędnego

Jak to działa: Węzeł główny wysyła pakiet „WakeUP” do urządzenia podrzędnego, a po odczekaniu odpowiedzi urządzenia podrzędnego z danymi.

W moim przypadku używam tablicy dwóch int:

// Pakiet wybudzania

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

Jeśli węzeł podrzędny wyśle pakiet ACK po tym, jak master wysłał pakiet WakeUp:

  1. Konfiguracja Master w trybie słuchania i czekanie na komunikację
  2. Jeśli komunikacja
  3. Wyodrębnij 8 pierwszych bajtów, zdobądź trzy pierwsze bajty z 8 bajtów, jeśli jest to węzeł ID
  4. Wyodrębnij 16 bajtów szyfru
  5. Odszyfruj dane
  6. Wydrukuj dane w serialu
  7. Tryb uśpienia

Do szyfrowania AES używam klucza w slocie numer 9.

To jest mój kod dla węzła głównego

#include "Arduino.h"

#include "avr/sleep.h" #include "avr/wdt.h" #include "SPI.h" #include "nRF24L01.h" #include "RF24.h" #include "Wire.h" // Biblioteka ATECC608A #include "ATECCX08A_Arduino/cryptoauthlib.h" #include "AES BASIC/aes_basic.h" #define ID_NODE 255 #define AES_KEY (uint8_t)9 ATCAIfaceCfg cfg; status ATCA_STATUS; radio RF24 (9, 10); const uint64_t masteraddresse = 0x1111111111; const uint64_t slaveaddresse = 0x11111111100; // Pakiet budzenia const int wake_packet[2] = {20, 02}; // watchdog przerwanie ISR(WDT_vect) { wdt_disable(); // wyłącz watchdog } void tryb uśpienia() { // wyłącz ADC ADCSRA = 0; // wyczyść różne flagi "resetu" MCUSR = 0; // zezwól na zmiany, wyłącz resetowanie WDTCSR = bit(WDCE) | bit(WDE); // ustaw tryb przerwania i interwał WDTCSR = bit(WDIE) | bit(WDP3) | bit(WDP0); // ustaw WDIE i 8 sekund opóźnienia wdt_reset(); // zresetuj watchdoga set_sleep_mode(SLEEP_MODE_PWR_DOWN); bez przerwań(); // sekwencja czasowa następuje po sleep_enable(); // wyłącz włączanie brown-out w oprogramowaniu MCUCR = bit(BODS) | bit (BODSE); MCUCR = bit (BODS); przerwania(); // gwarantuje wykonanie następnej instrukcji sleep_cpu(); // zapobiegawczo anuluj sen sleep_disable(); } void setup() { Serial.begin(9600); // Uruchom konstruktora biblioteki cfg.iface_type = ATCA_I2C_IFACE; // Rodzaj komunikacji -> tryb I2C cfg.devtype = ATECC608A; // Typ chipa cfg.atcai2c.slave_address = 0XC0; // adres I2C (wartość domyślna) cfg.atcai2c.bus = 1; cfg.atcai2c.baud = 100000; cfg.wake_delay = 1500; // Opóźnienie budzenia (1500 ms) cfg.rx_retries = 20; radio.początek(); radio.setDataRate(RF24_250KBPS); radio.maskIRQ(1, 1, 0); radio.enableAckPayload(); radio.setRetries(5, 5); radio.openWritingPipe(slaveaddresse); radio.openReadingPipe(1,adres główny); } void loop() { bool rslt; // Wyślij dane rslt = radio.write(&wake_packet, sizeof(wake_packet)); if (rslt) { // Rozpocznij słuchanie radio.startListening(); while (radio.available()) { uint8_t answer[32]; radio.read(&odpowiedź, sizeof(odpowiedź)); uint8_t id_węzła[3]; szyfr uint8_t[16]; memcpy(node_id, odpowiedź, 3); memcpy(cyfr, odpowiedź + 3, 16); if ((int)node_id == ID_NODE) { wyjście uint8_t[16]; ATCA_STATUS status = aes_basic_decrypt(&cfg, szyfr, 16, wyjście, AES_KEY); if (status == ATCA_SUCCESS) { Serial.println("Odszyfrowane dane: "); for (size_t i = 0; i < 16; i++) { Serial.print((char)output); } } } } } else{ Serial.println("Potwierdzenie braku odbioru pakietu Wakup"); } // Tryb uśpienia 8 sekund tryb uśpienia(); }

Jeśli masz pytanie, jestem tutaj, aby na nie odpowiedzieć

Krok 4: 4. Idź dalej

Ten przykład jest prosty, więc możesz ulepszyć ten projekt

Ulepszenia:

  • AES 128 jest podstawowym i możesz użyć innego algorytmu AES jako AES CBC, aby być bezpieczniejszym.
  • Zmień moduł bezprzewodowy (NRF24L01 jest ograniczony ładownością 23 bajtów)

Jeśli widzisz poprawę do zrobienia, wyjaśnij to w obszarze dyskusji

Krok 5: Wniosek

Mam nadzieję, że ten artykuł będzie dla Ciebie przydatny. Przepraszam, jeśli pomyliłem się w tekście, ale angielski nie jest moim głównym językiem i mówię lepiej niż piszę.

Dzięki za przeczytanie wszystkiego.

Ciesz się tym.

Zalecana: