Wireless Encrypted Communication Arduino

by Meph1st in Circuits > Arduino

5869 Views, 13 Favorites, 0 Comments

Wireless Encrypted Communication Arduino

Untitled Sketch_bb.png

Hello everyone,

In this second article, I will explain you how to use the chip Atecc608a to secure your wireless communication. For this, I will use the NRF24L01+ for the Wireless part and the Arduino UNO.

The micro chip ATECC608A has been designed by MicroChip and got multiple security tools. For example, this chip can store ECC Keys, AES Keys (for AES 128) and SHA2 Hash.

The article : NRF24L01 + Arduino UNO + ATECC608A

During a communication between two IoT Object, multiple attacks can be exist : Man Of the mild, Copy of information and more .. So my idea is very simple :

  1. Utilization of encrypted data between two or more IoT object.
  2. Low cost supplies
  3. Can work with an Arduino UNO

In my case, I use

  • the Atecc608a to store my AES Key and to encrypt/decrypt my data.
  • the Arduino Uno as Microcontroller
  • The NRF24L01 to send my data

You need to follow those steps for this project :

  1. Set up the chip ATECC608A
  2. Do the circuit (Master Node and Slave Node)
  3. Code part
  4. Go Further !

For the first steps "Set up the chip ATECC608A", I wrote an other article that explain each step in order. The link is here : https://www.instructables.com/id/Secure-Communication-Arduino/

Now start !

Supplies

For this project you need :

  • 2 Arduino UNO or Arduino NANO or Arduino Mega
  • Some wire
  • 2 Atecc608a (each cost less than 0.60$)
  • 2 NRF24L01+
  • 2 capacitor (10 μF)
  • Breadboards

Link to my article that explains how set up the chip ATECC608A -> How to set up Atecc608a

1. Set Up the Atecc608a

medium-ATECC608A-SOIC-8.png
F8AEN1JK9R2KBRV.jpg

I will not details every step to follow to set up an ATECC608A because I wrote an full article that explains every steps to do it. To set it up, you need to follow the "Step 4" of this article called "2. Configuration of the Chip (Atecc608a)"

The link is : How to set up an ATECC608A

Also, you need to put the same configuration for the Atecc608a, master side and slave side, otherwise you won't be able to decrypt your data.

Warning :

To set up this chip, you need to follow every steps of the article above in order. If one step is missing or the chip is not lock, you would not able to do this project.

Remainder :

Step to follow for this :

  • Create a configuration template
  • Write this template to the chip
  • Lock the Config Zone
  • Write your AES Key (128 Bits) in a slot
  • Lock the Data Zone

2. Design of the Circuit (Master and Slave)

FE3DGPBK9N922OD.LARGE.jpg
Capture1.PNG

In this project, you will have a Master Node and a Slave Node.

The master node will print the data send by the slave node in clear. It will request data from the slave node every X time.

The slave node will listen the "network" and when it receive a "Request data", it will generate it, encrypt it and send it to the master node.

For both side, master and slave the circuit are the same :

  • One arduino Nano
  • One ATECC608A
  • One NRF24L01

I attached the circuit to this step (cf picture above).

For the ATECC608A to the Arduino UNO, this is a soic 8 pin . I added the "top view" above :

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

For the NRF24L01 to the 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) -> only for Slave node, not used in Master mode

Why use the IRQ pin of the NRF24L01

The IRQ pin is very useful, this pin allows to say (LOW) when a packet is received by the NRF24L01, so we can attach an Interrupt to this pin to wake up the slave node.

3. the Code (Slave and Master)

Untitled Sketch_bb.png

Slave Node

I use power save for the slave Node because it does not need to listen all time.

How it works : the slave node listen and wait to receive a "Wake UP packet". This packet is send by the Master node to ask data from the slave.

In my case I use an array of two int :

// Wake UP packet
const int wake_packet[2] = {20, 02};

If my node receive a packet,

  1. it wake up, read this packet, if the packet is a "Wake UP",
  2. it generate the data,
  3. encrypt the data,
  4. send the data to the master, wait an ACK packet,
  5. sleep.

For the AES Encryption, I use a key in the slot number 9.

This is my code for the Slave node

#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; ATCA_STATUS status;

RF24 radio(9, 10);

const uint64_t masteraddresse = 0x1111111111; const uint64_t slaveaddresse = 0x1111111100;

/** * \brief Function executed when the interrupt is set (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; float hum = 16.4;

uint8_t data[16]; uint8_t cypherdata[16];

// Build a String to set all my Value // Each value is separated by a "|" and the "$" means the end of data // WARNING : Must be less than 11 length String tmp_str_data = String(ID_NODE) + "|" + String(temp, 1) + "|" + String(hum, 1) + "$"; //size of 11 Serial.println("tmp_str_data : " + tmp_str_data);

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

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

// generate an UUID based on the three first number = ID node String uuid = String(ID_NODE) + String(rand); // Size of 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)); // Stop listening radio.stopListening();

bool rslt; // Send Data rslt = radio.write(&data_to_send, sizeof(data_to_send)); // Start Listening radio.startListening(); if (rslt) { // End and sleep mode Serial.println(F("Done")); } } } } }

void setup() { Serial.begin(9600);

// Init the constuctor for the library cfg.iface_type = ATCA_I2C_IFACE; // Type of communication -> I2C mode cfg.devtype = ATECC608A; // Type of chip cfg.atcai2c.slave_address = 0XC0; // I2C addresse (default value) cfg.atcai2c.bus = 1; cfg.atcai2c.baud = 100000; cfg.wake_delay = 1500; // Delay of wake up (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); // Attach interrupt to the pin 3 // Modify 1 by O if you want the interrupt to the pin 2 // FALLING MODE = Pin at LOW attachInterrupt(1, wakeUpIRQ, FALLING); }

void loop() { // No need }


Master Node

The master node wake up every 8 secondes to ask data from the slave Node

How it works : The master node send a "WakeUP" packet to the slave and after wait an answer of the slave with data.

In my case I use an array of two int :

// Wake UP packet
const int wake_packet[2] = {20, 02};

If the slave node send a ACK packet after the master sent a WakeUp packet :

  1. Master set up in Listen mode and wait a communication
  2. If communication
  3. Extract the 8 first byte, loot the three first byte of the 8 bytes, if this is the ID node
  4. Extract the 16 byte of cypher
  5. Decrypt the data
  6. Print the data in Serial
  7. Sleep mode

For the AES Encryption, I use a key in the slot number 9.

This is my code for the Master node

#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;
ATCA_STATUS status;

RF24 radio(9, 10);
const uint64_t masteraddresse = 0x1111111111;
const uint64_t slaveaddresse = 0x1111111100;

// Wake UP packet
const int wake_packet[2] = {20, 02};

// watchdog interrupt
ISR(WDT_vect)
{
  wdt_disable(); // disable watchdog
}

void sleepmode()
{
  // disable ADC
  ADCSRA = 0;
  // clear various "reset" flags
  MCUSR = 0;
  // allow changes, disable reset
  WDTCSR = bit(WDCE) | bit(WDE);
  // set interrupt mode and an interval
  WDTCSR = bit(WDIE) | bit(WDP3) | bit(WDP0); // set WDIE, and 8 seconds delay
  wdt_reset();                                // reset the watchdog
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  noInterrupts(); // timed sequence follows
  sleep_enable();
  // turn off brown‐out enable in software
  MCUCR = bit(BODS) | bit(BODSE);
  MCUCR = bit(BODS);
  interrupts(); // guarantees next instruction executed
  sleep_cpu();
  // cancel sleep as a precaution
  sleep_disable();
}
void setup()
{
  Serial.begin(9600);

  // Init the constuctor for the library
  cfg.iface_type = ATCA_I2C_IFACE;  // Type of communication -> I2C mode
  cfg.devtype = ATECC608A;          // Type of chip
  cfg.atcai2c.slave_address = 0XC0; // I2C addresse (default value)
  cfg.atcai2c.bus = 1;
  cfg.atcai2c.baud = 100000;
  cfg.wake_delay = 1500; // Delay of wake up (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;
  // Send Data
  rslt = radio.write(&wake_packet, sizeof(wake_packet));

  if (rslt)
  {
    // Start Listening
    radio.startListening();
    while (radio.available())
    {
      uint8_t answer[32];
      radio.read(&answer, sizeof(answer));

      uint8_t node_id[3];
      uint8_t cypher[16];
      memcpy(node_id, answer, 3);
      memcpy(cypher, answer + 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("Decrypted Data : ");
          for (size_t i = 0; i < 16; i++)
          {
            Serial.print((char)output[i]);
          }
        }
      }
    }
  }
  else{
    Serial.println("Ack not receive for Wakup Packet");
  }
  // Sleep mode 8 secondes
  sleepmode();
}

If you have question, I am here to answer it !

4. Go Further !

This example is simple so you can improve this project

Improvements :

  • The AES 128 is basic and you can use an other algorithm of AES as AES CBC to be safer.
  • Change the wireless module (the NRF24L01 is limited by a payload of 23 Bytes)
  • ...

If you see improvement to do, explain it on the discussion area

Conclusion

I hope this article will be useful for you. Sorry if I did mistake in my text but English is not my main language and I speak better than I write.

Thanks for reading everything.

Enjoy it.