Arduino de comunicação criptografada sem fio: 5 etapas
Arduino de comunicação criptografada sem fio: 5 etapas
Anonim
Arduino de comunicação criptografada sem fio
Arduino de comunicação criptografada sem fio

Olá pessoal, Neste segundo artigo, explicarei como usar o chip Atecc608a para proteger sua comunicação sem fio. Para isso utilizarei o NRF24L01 + para a parte Wireless e o Arduino UNO.

O micro chip ATECC608A foi projetado pela MicroChip e tem várias ferramentas de segurança. Por exemplo, este chip pode armazenar chaves ECC, chaves AES (para AES 128) e SHA2 Hash.

O artigo: NRF24L01 + Arduino UNO + ATECC608A

Durante uma comunicação entre dois objetos IoT, vários ataques podem ocorrer: Man Of the light, Cópia de informações e muito mais. Minha ideia é muito simples:

  1. Utilização de dados criptografados entre dois ou mais objetos IoT.
  2. Suprimentos de baixo custo
  3. Pode funcionar com um Arduino UNO

No meu caso, eu uso

  • o Atecc608a para armazenar minha chave AES e para criptografar / descriptografar meus dados.
  • o Arduino Uno como microcontrolador
  • O NRF24L01 para enviar meus dados

Você precisa seguir estas etapas para este projeto:

  1. Configure o chip ATECC608A
  2. Faça o circuito (nó mestre e nó escravo)
  3. Parte do código
  4. Ir além !

Para as primeiras etapas "Configurar o chip ATECC608A", escrevi um outro artigo que explica cada etapa na ordem. O link está aqui:

Agora comece!

Suprimentos

Para este projeto, você precisa de:

  • 2 Arduino UNO ou Arduino NANO ou Arduino Mega
  • Algum fio
  • 2 Atecc608a (cada custo inferior a 0,60 $)
  • 2 NRF24L01 +
  • 2 capacitores (10 μF)
  • Tábuas de pão

Link para o meu artigo que explica como configurar o chip ATECC608A -> Como configurar o Atecc608a

Etapa 1: 1. Configure o Atecc608a

1. Configure o Atecc608a
1. Configure o Atecc608a
1. Configure o Atecc608a
1. Configure o Atecc608a

Não detalharei todas as etapas a seguir para configurar um ATECC608A porque escrevi um artigo completo que explica todas as etapas para fazê-lo. Para configurá-lo, você precisa seguir o "Passo 4" deste artigo denominado "2. Configuração do Chip (Atecc608a)"

O link é: Como configurar um ATECC608A

Além disso, você precisa colocar a mesma configuração para o Atecc608a, lado mestre e lado escravo, caso contrário você não será capaz de descriptografar seus dados

Aviso:

Para configurar este chip, você precisa seguir todas as etapas do artigo acima na ordem. Se uma etapa estiver faltando ou o chip não estiver travado, você não conseguirá realizar este projeto

Restante:

Passo a seguir para isso:

  • Crie um modelo de configuração
  • Escreva este modelo no chip
  • Bloquear a zona de configuração
  • Escreva sua chave AES (128 bits) em um slot
  • Bloqueie a zona de dados

Etapa 2: 2. Projeto do circuito (mestre e escravo)

2. Projeto do circuito (mestre e escravo)
2. Projeto do circuito (mestre e escravo)
2. Projeto do circuito (mestre e escravo)
2. Projeto do circuito (mestre e escravo)

Neste projeto, você terá um nó mestre e um nó escravo.

O nó mestre imprimirá os dados enviados pelo nó escravo em claro. Ele solicitará dados do nó escravo a cada X vez.

O nó escravo ouvirá a "rede" e quando receber um "Pedido de dados", irá gerá-lo, criptografá-lo e enviá-lo ao nó mestre.

Para ambos os lados, mestre e escravo, o circuito é o mesmo:

  • Um Arduino Nano
  • Um ATECC608A
  • Um NRF24L01

Anexei o circuito a esta etapa (veja a imagem acima).

Para o ATECC608A para o Arduino UNO, este é um pino soic de 8. Eu adicionei a "vista de cima" acima:

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

Para o NRF24L01 para o 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) -> apenas para nó Slave, não usado no modo Master

Por que usar o pino IRQ do NRF24L01

O pino IRQ é muito útil, este pino permite dizer (BAIXO) quando um pacote é recebido pelo NRF24L01, então podemos anexar uma interrupção a este pino para despertar o nó escravo.

Etapa 3: 3. o código (escravo e mestre)

3. o código (escravo e mestre)
3. o código (escravo e mestre)

Nó Escravo

Eu uso economia de energia para o nó escravo porque ele não precisa ouvir o tempo todo.

Como funciona: o nó escravo escuta e espera para receber um "pacote Wake UP". Este pacote é enviado pelo nó mestre para solicitar dados do escravo.

No meu caso, uso uma matriz de dois int:

// Pacote Wake UP

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

Se meu nó receber um pacote,

  1. acorde, leia este pacote, se o pacote for um "Wake UP",
  2. ele gera os dados,
  3. criptografar os dados,
  4. envie os dados para o mestre, aguarde um pacote ACK,
  5. dormir.

Para a criptografia AES, uso uma chave no slot número 9.

Este é o meu código para o nó Slave

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

#include "SPI.h"

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

#include "Wire.h"

// biblioteca 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;

Rádio RF24 (9, 10);

const uint64_t masteraddresse = 0x1111111111;

const uint64_t slaveaddresse = 0x1111111100;

/**

* / brief Função executada quando a interrupção é definida (IRQ LOW) * * * / void wakeUpIRQ () {while (radio.available ()) {int data [32]; radio.read (& data, 32); if (dados [0] == 20 && dados [1] == 02) {float temp = 17,6; flutuador zumbido = 16,4;

dados uint8_t [16];

uint8_t cypherdata [16];

// Construir uma string para definir todos os meus valores

// Cada valor é separado por um "|" e o "$" significa o fim dos dados // AVISO: Deve ter menos de 11 comprimento String tmp_str_data = String (ID_NODE) + "|" + String (temp, 1) + "|" + Corda (hum, 1) + "$"; // tamanho de 11 Serial.println ("tmp_str_data:" + tmp_str_data);

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

// Criptografar os dados

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

// gera um UUID com base nos três primeiros números = nó de ID

String uuid = String (ID_NODE) + String (rand); // Tamanho de 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)); // Pare de ouvir radio.stopListening ();

bool rslt;

// Enviar dados rslt = radio.write (& data_to_send, sizeof (data_to_send)); // Comece a ouvir radio.startListening (); if (rslt) {// Fim e modo de espera Serial.println (F ("Concluído")); }}}}}

void setup ()

{Serial.begin (9600);

// Inicie o construtor para a biblioteca

cfg.iface_type = ATCA_I2C_IFACE; // Tipo de comunicação -> modo I2C cfg.devtype = ATECC608A; // Tipo de chip cfg.atcai2c.slave_address = 0XC0; // Endereço I2C (valor padrão) cfg.atcai2c.bus = 1; cfg.atcai2c.baud = 100000; cfg.wake_delay = 1500; // Atraso de ativação (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); // Anexe a interrupção ao pino 3 // Modifique 1 por O se quiser a interrupção ao pino 2 // FALLING MODE = Pino em LOW attachInterrupt (1, wakeUpIRQ, FALLING); }

void loop ()

{ // Não há necessidade }

Nó Mestre

O nó mestre acorda a cada 8 segundos para solicitar dados do nó escravo

Como funciona: O nó mestre envia um pacote "WakeUP" para o escravo e após espera uma resposta do escravo com os dados.

No meu caso, uso uma matriz de dois int:

// Pacote Wake UP

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

Se o nó escravo enviar um pacote ACK após o mestre enviar um pacote WakeUp:

  1. Master configurado no modo de escuta e aguarde uma comunicação
  2. Se comunicação
  3. Extraia os 8 primeiros bytes, saqueie os três primeiros bytes dos 8 bytes, se este for o nó de ID
  4. Extraia os 16 bytes de cifra
  5. Descriptografar os dados
  6. Imprima os dados em série
  7. Modo dormir

Para a criptografia AES, uso uma chave no slot número 9.

Este é o meu código para o nó mestre

#include "Arduino.h"

#include "avr / sleep.h" #include "avr / wdt.h" #include "SPI.h" #include "nRF24L01.h" #include "RF24.h" #include "Wire.h" // ATECC608A library #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; Rádio RF24 (9, 10); const uint64_t masteraddresse = 0x1111111111; const uint64_t slaveaddresse = 0x1111111100; // Pacote Wake UP const int wake_packet [2] = {20, 02}; // interrupção do watchdog ISR (WDT_vect) {wdt_disable (); // desabilita watchdog} void sleepmode () {// desabilita ADC ADCSRA = 0; // limpa vários sinalizadores de "redefinição" MCUSR = 0; // permitir mudanças, desabilitar reset WDTCSR = bit (WDCE) | bit (WDE); // define o modo de interrupção e um intervalo WDTCSR = bit (WDIE) | bit (WDP3) | bit (WDP0); // define WDIE e retardo de 8 segundos wdt_reset (); // redefine o watchdog set_sleep_mode (SLEEP_MODE_PWR_DOWN); noInterrupts (); // sequência cronometrada segue sleep_enable (); // desativa a ativação de brown-out no software MCUCR = bit (BODS) | bit (BODSE); MCUCR = bit (BODS); interrupções (); // garante a próxima instrução executada sleep_cpu (); // cancela o sono como precaução sleep_disable (); } void setup () {Serial.begin (9600); // Inicie o construtor para a biblioteca cfg.iface_type = ATCA_I2C_IFACE; // Tipo de comunicação -> modo I2C cfg.devtype = ATECC608A; // Tipo de chip cfg.atcai2c.slave_address = 0XC0; // Endereço I2C (valor padrão) cfg.atcai2c.bus = 1; cfg.atcai2c.baud = 100000; cfg.wake_delay = 1500; // Atraso de ativação (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; // Enviar dados rslt = radio.write (& wake_packet, sizeof (wake_packet)); if (rslt) {// Começar a ouvir radio.startListening (); while (radio.available ()) {uint8_t answer [32]; radio.read (& answer, sizeof (answer)); uint8_t node_id [3]; cifra uint8_t [16]; memcpy (node_id, resposta, 3); memcpy (cifra, resposta + 3, 16); if ((int) node_id == ID_NODE) {uint8_t output [16]; ATCA_STATUS status = aes_basic_decrypt (& cfg, cypher, 16, saída, AES_KEY); if (status == ATCA_SUCCESS) {Serial.println ("Dados descriptografados:"); para (size_t i = 0; i <16; i ++) {Serial.print ((char) output ); }}}}} else {Serial.println ("Ack não recebido para pacote Wakup"); } // Modo de espera 8 segundos sleepmode (); }

Se você tiver alguma dúvida, estou aqui para respondê-la

Etapa 4: 4. Vá mais longe

Este exemplo é simples para que você possa melhorar este projeto

Melhorias:

  • O AES 128 é básico e você pode usar um outro algoritmo do AES como AES CBC para ficar mais seguro.
  • Mude o módulo sem fio (o NRF24L01 é limitado por uma carga útil de 23 bytes)

Se você vir melhorias a serem feitas, explique-as na área de discussão

Etapa 5: Conclusão

Espero que este artigo seja útil para você. Desculpe se me enganei no texto, mas o inglês não é a minha língua principal e falo melhor do que escrevo.

Obrigado por ler tudo.

Aproveite.