logo
+7 (951) 999-89-94
428003, г. Чебоксары, ул. Федора Гладкова, д.9, оф.319

ATSHA204A — nRF24 аутентификация. Датчик

Это вторая статья о тестовой системе аутентификации удалённого контроллера в беспроводной nRF24 сети. В первой части мы подробно рассмотрели устройство и работу базового контроллера (т. н. nRF24 «базы»), в этой статье мы рассмотрим работу и устройство ответной части, т. н. «датчика».

Эта статья предполагает, что перед её чтением вы ознакомились с первой частью, где объясняется работа базы и основные принципы построения тестовой nRF24 крипто-системы.

Постановка задачи

Напомним, что нам нужно создать тестовую систему, состоящую из «базы» и «датчика», связанных по беспроводному nRF24 каналу. Задача состоит в том, что базе нужно связаться с датчиком и удостовериться, что это именно «легитимный» датчик нашей экосистемы, а не клонированный хакером (чужой) датчик.

Решается эта задача при помощи микросхем ATSHA204A, которые установлены на платах базы и датчика и соответствующим образом запрограммированы.

Оборудование

В качестве контроллеров для эксперимента (и для базы и для датчика) используются беспроводные контроллеры uniSensors nRF24, которые имеют на борту все необходимые компоненты.

  • Микроконтроллер ATmega328
  • Беспроводной модуль nRF24L01
  • Микросхему ATSHA204A

Примечание. Для работы с uniSensors nRF24 и компиляции скетчей в Arduino IDE в настройках нужно выбирать контроллер Arduino Pro Mini, Atmega328 (3.3V, 8MHz).

Алгоритм работы

Алгоритм работы, обеспечивающий аутентификацию датчика, следующий: на базе микросхемой ATSHA204A генерируется (RNG) случайное число, затем этой же микросхемой при помощи команды MAC (на основе случайного числа и секретного ключа в Data зоне EEPROM памяти ATSHA204A) вычисляется SHA-256 хеш (дайджест). Этот дайджест запоминается для последующего сравнения с ответом датчика.

Затем ранее сгенерированное случайное число по беспроводному nRF24 каналу отсылается датчику, который на его основе (при помощи идентично запрограммированной микросхемы ATSHA204A) также вычисляет SHA-256 хеш и отсылает его обратно базе для проверки и сравнения с заранее вычисленным на базе хешем.

Вот графическое представление работы алгоритма аутентификации:

Более подробно об этом алгоритме и реализации его работы микросхемой ATSHA204A вы можете прочитать в предыдущих статьях этого цикла.

Датчик

В этой статье мы подробно рассмотрим работу датчика («ответной части») как с криптографическими алгоритмами, так и работу с беспроводной системой nRF24. Работу базы мы подробно разобрали в предыдущей статье.

Как следует из условий задачи, датчик должен получить от базы случайное число, вычислить с его участием хеш и отослать этот хеш (дайджест) обратно базе. Это основной функционал датчика, теперь подробнее разберём создание и работу скетча.

Код криптоалгоритма датчика

Ниже приведён код криптоалгоритма датчика из одной из наших предыдущих статей (там же вы можете ознакомиться с подробным описанием его работы). Здесь наша задача будет состоять в интеграции этого кода со скетчем беспроводной nRF24 связи.

/* 
  ATSHA204A Project (Sensor)
*/

#include <sha204_library.h>

const int sha204Pin = A3;

byte rnd[MAC_CHALLENGE_SIZE] = {
  0x23, 0x47, 0x3B, 0x1D, 0x89, 0xEA, 0x07, 0x80,
  0x07, 0x5A, 0xEE, 0xD9, 0xEC, 0x8D, 0xF5, 0x68,
  0x88, 0xAC, 0x3B, 0x36, 0x50, 0xF4, 0x03, 0xA4,
  0xDF, 0xB3, 0x38, 0xA7, 0x16, 0xBA, 0x4A, 0xF5
};

byte challenge[MAC_CHALLENGE_SIZE];
byte hash[MAC_CHALLENGE_SIZE];

byte retCode = 0;

atsha204Class sha204(sha204Pin);


void setup() {
  Serial.begin(115200);
  Serial.println("ATSHA204 Project (Sensor) start...");
  
  getRandom();
  
  Serial.println("Random:");
  printArray(challenge, 32);
  Serial.println();
  
  macChallenge();
  Serial.println("Hash:");
  printArray(hash, 32);
  Serial.println();
}

// Print

void printArray(byte arr[], byte len) {
  for (byte i = 0; i < len; i++) {
    if (arr[i] < 16) {Serial.print('0');}
    Serial.print(arr[i], HEX); Serial.print(' ');
  }
}

// Random

void getRandom() {
  for (byte i = 0; i < 32; i++) {
    challenge[i] = rnd[i];
  }
}

// MAC

void macChallenge() {
  uint8_t command[MAC_COUNT_LONG];
  uint8_t response[MAC_RSP_SIZE];

  retCode = sha204.sha204m_execute(SHA204_MAC,
                                   0, 0,
                                   MAC_CHALLENGE_SIZE, (uint8_t *) challenge,
                                   0, NULL,
                                   0, NULL,
                                   sizeof(command),   &command[0],
                                   sizeof(response), &response[0]);

  for (byte i = 0; i < 32; i++) {
    hash[i] = response[i];
  }
}

void loop() {
  
}

Подсистема nRF24 датчика

Работа с беспроводной системой nRF24 является достаточно сложной и специфичной темой и подробное рассмотрение её выходит за рамки этой статьи, поэтому здесь мы только приведём готовый nRF24 скетч датчика (без крипто-функций), а затем создадим финальный код скетча, который будет сочетать в себе и крипто-функционал (датчика) и возможности беспроводной nRF24 связи.

Для работы этого скетча и вообще для работы с nRF24 подсистемой вам понадобится библиотека nRF24.

/*
  nrf24 Sensor
*/

#include <SPI.h>
#include "RF24.h"

#define RF_PIN A1

RF24 radio(6, 7);
byte addresses[][6] = {"1Node", "2Node"};

#define PACKET_MAX_BYTES 32
byte buffRx[PACKET_MAX_BYTES];

void setup() {
  Serial.begin(115200);
  Serial.println(F("RF24 Sensor start..."));

  pinMode(RF_PIN, OUTPUT);
  digitalWrite(RF_PIN, LOW);
  delay(500);
  
  radio.begin();
  radio.setPALevel(RF24_PA_MIN);

  radio.openWritingPipe(   addresses[0]);
  radio.openReadingPipe(1, addresses[1]);
  radio.startListening();
}

void printArray(byte arr[], byte len) {
  for (byte i = 0; i < len; i++) {
    if (arr[i] < 16) {Serial.print('0');}
    Serial.print(arr[i], HEX); Serial.print(' ');
  }
}

void loop() {
  
  if (radio.available()) {
    while (radio.available()) {
      radio.read(&buffRx, PACKET_MAX_BYTES);
    }
   
    radio.stopListening();
    radio.write(&buffRx, PACKET_MAX_BYTES);
    radio.startListening();     
    
    Serial.print(F("Send response: ")); printArray(buffRx, 32); Serial.println();
  }
}

Этот скетч выполняет простую функцию: принимает от базы тестовый 32-байтовый массив buffRx и отсылает его обратно на базу. Получается «беспроводное зеркало», которое отражает обратно принимаемые данные.

Вначале мы подключаем все необходимые библиотеки для работы с nRF24 частью.

#include <SPI.h>
#include "RF24.h"

Затем определяем пин включения питания радиомодуля на контроллерах uniSensors nRF24.

#define RF_PIN A1

Создаём объект для управления модулем nRF24L01 и указываем номера GPIO для подключения его CE и CSN выводов.

RF24 radio(6, 7);

Задаём адреса для связи базы и датчика.

byte addresses[][6] = {"1Node", "2Node"};

И тестовый 32-байтовый массив для получения и отсылки данных.

#define PACKET_MAX_BYTES 32
byte buffRx[PACKET_MAX_BYTES];

Затем, в функции setup(), подаём питание на радиомодуль uniSensors nRF24.

  pinMode(RF_PIN, OUTPUT);
  digitalWrite(RF_PIN, LOW);
  delay(500);

Включаем радиомодуль.

  radio.begin();

Устанавливаем минимальную мощность nRF24 передатчика (поскольку модули находятся на небольшом расстоянии друг от друга).

  radio.setPALevel(RF24_PA_MIN);

И настраиваем адреса для приёма и передачи данных. Обратите внимание, что адреса для чтения и записи у базы и датчика меняются местами.

  radio.openWritingPipe(   addresses[0]);
  radio.openReadingPipe(1, addresses[1]);

Затем включаем радиомодуль для прослушивания эфира.

  radio.startListening();

Далее в цикле loop() ждём данные от базы и принимаем их.

  if (radio.available()) {
    while (radio.available()) {
      radio.read(&buffRx, PACKET_MAX_BYTES);
    }

Передаём обратно принятые данные (32-байтовый массив).

    radio.stopListening();
    radio.write(&buffRx, PACKET_MAX_BYTES);
    radio.startListening();   

И выводим данные (массив) на печать.

Serial.print(F("Send response: ")); printArray(buffRx, 32); Serial.println();

Скетч рассчитан на работу с «базовой» частью (скетчем базы), который мы описали в предыдущей статье.

Далее мы создадим из этих двух (криптографического ATSHA204A и беспроводного nRF24) объединённый финальный скетч датчика и подробно разберём его работу.

Скетч nRF24 ATSHA204A Sensor

Ниже представлен полный код скетча nRF24 ATSHA204A Sensor, объединяющий в себе криптографическую, беспроводную и функциональную части.

/* 
  nRF24 ATSHA204A Sensor
*/

#include <SPI.h>
#include "RF24.h"
#include <sha204_library.h>

// nRF24

#define RF_PIN A1
RF24 radio(6, 7);
byte addresses[][6] = {"1Node", "2Node"};

#define PACKET_MAX_BYTES 32
byte buffRx[PACKET_MAX_BYTES];

// ATSHA204A

const int sha204Pin = A3;

byte challenge[MAC_CHALLENGE_SIZE];
byte hash[MAC_CHALLENGE_SIZE];

byte retCode = 0;

atsha204Class sha204(sha204Pin);


void setup() {
  Serial.begin(115200);
  Serial.println("nRF24 ATSHA204 (Sensor) start...");

  pinMode(RF_PIN, OUTPUT);
  digitalWrite(RF_PIN, LOW);
  delay(500);
  
  radio.begin();
  radio.setPALevel(RF24_PA_MIN);

  radio.openWritingPipe(   addresses[0]);
  radio.openReadingPipe(1, addresses[1]);
  radio.startListening();
}

// Print

void printArray(byte arr[], byte len) {
  for (byte i = 0; i < len; i++) {
    if (arr[i] < 16) {Serial.print('0');}
    Serial.print(arr[i], HEX); Serial.print(' ');
  }
}

// MAC

void macChallenge() {
  uint8_t command[MAC_COUNT_LONG];
  uint8_t response[MAC_RSP_SIZE];

  retCode = sha204.sha204m_execute(SHA204_MAC,
                                   0, 0,
                                   MAC_CHALLENGE_SIZE, (uint8_t *) buffRx,
                                   0, NULL,
                                   0, NULL,
                                   sizeof(command),   &command[0],
                                   sizeof(response), &response[0]);

  for (byte i = 0; i < 32; i++) {
    hash[i] = response[i + 1];
  }
}

void loop() {
  if (radio.available()) {
    while (radio.available()) {
      radio.read(&buffRx, PACKET_MAX_BYTES);
    }
   
    Serial.print(F("Receive:   ")); printArray(buffRx, 32); Serial.println();
    macChallenge();

    Serial.print(F("Send back: ")); printArray(hash,   32); Serial.println();
    Serial.println();

    radio.stopListening();
    radio.write(&hash, PACKET_MAX_BYTES);
    radio.startListening();
  }
}

Теперь разберём работу этого скетча. В финальной версии датчика мы объявляем 32-байтовый массив для приёма случайного числа от базы нашей IoT системы.

#define PACKET_MAX_BYTES 32
byte buffRx[PACKET_MAX_BYTES];

Объявляем 2 массива: для случайного числа (challenge) и вычисленного хеша SHA-256 (hash).

byte challenge[MAC_CHALLENGE_SIZE];
byte hash[MAC_CHALLENGE_SIZE];

Принимаем от базы случайное 32-байтовое число.

  if (radio.available()) {
    while (radio.available()) {
      radio.read(&buffRx, PACKET_MAX_BYTES);
    }

Выводим его на печать и вычисляем (при помощи ATSHA204A) 32-байтовый SHA-256 хеш (дайджест).

    Serial.print(F("Receive:   ")); printArray(buffRx, 32); Serial.println();
    macChallenge();

Выводим на печать вычисленный хеш.

    Serial.print(F("Send back: ")); printArray(hash,   32); Serial.println();
    Serial.println();

И отсылаем этот хеш на базу в ответ на присланное базой случайное число.

    radio.stopListening();
    radio.write(&hash, PACKET_MAX_BYTES);
    radio.startListening();

Вот результат работы финального объединённого скетча датчика:

Вы видите присланные случайные числа от базы и отправленный на базу вычисленный ответ (SHA-256 хеш).

Примечание: в этом эксперименте использовались микросхемы ATSHA204A (установленные на платах uniSensors) без дополнительной прошивки и блокировки зон памяти, поэтому вместо реальных случайных чисел вы видите тестовые последовательности FF FF 00 00 FF FF 00 00, выдаваемые микросхемой ATSHA204A в этом режиме. Если вы воспользуетесь методикой программирования микросхем ATSHA204A, описанной в статьях этого цикла, то сможете записать любой секретный ключ в нулевую (0) ячейку Data зоны вашей микросхемы и (без каких-либо переделок этого скетча) получить полнофункциональную аутентификацию при помощи ATSHA204A в вашей беспроводной nRF24 сети.

Заключение

Таким образом мы создали два скетча базы и датчика, которые при помощи микросхем ATSHA204A осуществляют криптографическую аутентификацию в nRF24 сети. В этой системе «хакер» уже не сможет включить в систему свой клонированный датчик и подделать показания вашего «легитимного» контроллера.

Правда тут нужно понимать, что это тестовый (хотя и функциональный) пример, а в реальных IoT проектах вышеописанный алгоритм аутентификации нужно дополнять различными мерами крипто-безопасности (такими как шифрование и т. п.).

 

Ссылки по теме

Работа с SHA-256

ATSHA204 - Обзор

ATSHA204 - Спецификации

ATSHA204 - Библиотека и примеры

ATSHA204A - Чтение зоны конфигурации 1

ATSHA204A - Чтение зоны конфигурации 2

ATSHA204A - Чтение зоны конфигурации 3

ATSHA204A - Запись конфигурации 1

ATSHA204A - Запись конфигурации 2

ATSHA204A - Запись конфигурации 3

ATSHA204A - Запись конфигурации 4

ATSHA204A - Config Lock

ATSHA204A - Работа в режиме Config Lock

ATSHA204A - Работа с зонами памяти

ATSHA204A - Запись зоны OTP

ATSHA204A - Data Lock

ATSHA204A - Чтение Data и OTP зон памяти

ATSHA204A - Команда MAC

ATSHA204A - Аутентификация. Базовый блок

ATSHA204A - Криптография и команды

ATSHA204A - Команда CheckMac

ATSHA204A - Команда Nonce

ATSHA204A - Команда GenDig

ATSHA204A - Команда HMAC

ATSHA204A - Команда DeriveKey

ATSHA204A - nRF24 аутентификация. База

ATSHA204A - nRF24 аутентификация. Датчик

ATSHA204A - LoRa аутентификация. База

ATSHA204A - LoRa аутентификация. Датчик