Funksicherheit mit 2,4 GHz nRF24L01+ Transceiver

In meinem Projekt Gesicherte Funkbefehle habe ich gezeigt, wie ich das Ausführen von nicht autorisierten Funkbefehlen über eine Funkverbindung mittels nRF24L01+ Transceiver, z.B. zu einer Alarmanlage oder einer Torsteuerung, verhindern möchte. Um das dort vorgestellte Testprogramm in einer Anwendung leichter einbinden zu können, habe ich eine Library geschrieben, die ich hier nun vorstelle.

Wie ich die Ausführung von nicht autorisierten Funkbefehlen verhindern möchte oder wie die benötigten EEPROMs zu programmieren sind, etc. ist im genannten Projekt nachzulesen.


Testaufbau:

Der Testaufbau gleicht beinahe dem Testaufbau aus dem genannten Projekt, nur der Sender wurde um 2 Taster und der Empfänger um eine zweite LED erweitert.


Verbindung des RF-Moduls mit dem Arduino Nano:

nRF24L01+ PIN     Arduino Nano-Pin

   1   GND         ->       GND

   2   VCC          ->       3,3 V

   3   CE            ->        D9   (im Programm konfigurierbar)

   4   CSN          ->        D10 (im Programm konfigurierbar)

   5   SCK          ->        D13 (nicht konfigurierbar - SPI-Schnittstelle des Arduino)           

   6   MOSI        ->        D11 (nicht konfigurierbar - SPI-Schnittstelle des Arduino)    

   7   MISO        ->        D12 (nicht konfigurierbar - SPI-Schnittstelle des Arduino)    

   8   IRQ          ->        im Testaufbau nicht benutzt

Anschlussbelegung des Moduls siehe: Gesicherte Funkbefehle


Verwendete Bauteile je für Sender und Empfänger:

  • 1 Arudino Nano
  • 1 nRF24L01+ (2,4 GHz Transceiver Modul)
  • 1 EEPROM 24LC512 (512 kBit, I2C-Schnittstelle und mit Zufallszahlen programmiert)
  • 2 Widerstände 10 kOhm
  • 1 Elko 10 uF
  • 1 LED 3 mm rot
  • 1 Widerstand 470 Ohm

Zusätzliche Bauteile für den Sender:

  • 2 Taster
  • 2 Widerstände 10 kOhm

Zusätzliche Bauteile für den Empfänger:

  • 1 LED 3 mm grün
  • 1 Widerstand 470 Ohm


Aufbau zweimal (mit oben genannten Abweichungen zwischen Sender und Empfänger):

Library MySecureSend:

Die Library MySecureSend wird sowohl vom Senderprogramm, als auch vom Empfängerprogramm verwendet.

Folgende Funktionen stehen derzeit zur Verfügung:


  • Öffnen eines Sendekanals
  • Öffnen eines Empfangskanals
  • Setzen der Senderleistung
  • Setzen der Anzahl der Bytes pro Telegramm
  • Setzen der Sendefrequenz
  • Senden eines gesicherten Telegramms
  • Prüfen ob Telegramm verfügbar (nur Empfänger)
  • Empfangen eines gesicherten Telegramms
  • Statusanzeige über LED


Verwendete Libraries:

Neben der Standard-Library SPI und Wire werden für MySecureSend noch folgende Libraries benötigt:

  • RF24: Zur Steuerung der nRF24L01+ Transceiver-Module. Einen Link zu RF24-Library und zu ihrer Beschreibung findet ihr hier: Fremd-Libraries
  • MyEEPROM_I2C: Zur Kommunikation mit den EEPROMs. Meine Library kann hier heruntergeladen werden: I2C-EEPROM

 

Die Library kann hier heruntergeladen werden:

Sollte die Library jemand verwenden oder testen, würde ich mich über eine Rückmeldung sehr freuen!

Version 1.4

MySecureSend.cpp.txt

MySecureSend.h.txt

keywords.txt

Leider kann ich hier keine "cpp"- oder "h"-Files hochladen, daher zum Verwenden der Library ".txt" aus den Dateinamen entfernen und in einem neuen Verzeichnis mit dem Namen "MySecureSend" dort speichern, wo eure anderen Libraries gespeichert sind.


Zur Auflistung der Funktionen der Library: Funktionen


Testprogramme:

Nachfolgend die beiden Testprogramme für Sender und Empfänger.


Funktionen:

Sender und Empfänger prüfen beim Starten ob das jeweilige EEPROM ansprechbar ist. Das Ergebnis wird durch die rote LED angezeigt. Leuchten bedeutet ok, blinken bedeutet EEPROM-Fehler.

Danach kann mit den Tasten des Senders die grüne LED des Empfängers ein- und ausgeschaltet werden. Die Befehlsübertragung erfolgt dabei mit der im Projekt Gesicherte Funkbefehle  vorgestellten "sicheren" Befehlsübertragung. Schlägt die Übertragung fehl (Prüfung auf Zeitüberschreitung und Prüfsummenfehler) blinkt die rote LED des Senders und/oder des Empfängers, bei erfolgreicher Übertragung leuchten die roten LEDs.


Verwendete Libraries:

Neben der zu testenden Library MySecureSend verwende ich für die Testprogramme noch folgende Library:

  • Metro: Mit Metro steuere ich die zyklische Wiederholung von Vorgängen. Einen Link zu Metro findet ihr hier: Fremd-Libraries


Unbedingt zu beachten: Damit die Testprogramme lauffähig sind, müssen die EEPROMs mit Zufallszahlen (Werte von 1 bis 255), z.B. mit Hilfe meines EEPROM-Monitor beschrieben und die Library RF24 installiert und gepatcht sein (siehe Gesicherte Funkbefehle). Außerdem müssen die Libraries Metro (siehe Fremd-Libraries) und meine Library MyEEPROM_I2C (siehe I2C-EEPROM) installiert sein!


Testprogramm Sender:

//Testprogramm MySecureSend-Library Sender
//Code fuer Arduino
//Author Retian
//Version 1.2


#include <MySecureSend.h>
#include <Metro.h>


MySecureSend SecureSend;
Metro tastAbfrage = Metro(150); //Metro-Zyklus 150 ms


#define ledPin1 4 //Status-LED auf Pin4
#define tastPin1 2 //Taster 1 auf Pin2
#define tastPin2 3 //Taster 2 auf Pin3


byte mySecureSend_CE = 9; //CE-Pin des RF-Moduls
byte mySecureSend_CSN = 10; //CSN-Pin des RF-Moduls


char befehl[20]; //Befehls-Array
bool tastWert1, tastWert2;


void setup() {
  pinMode(ledPin1, OUTPUT);
  digitalWrite(ledPin1, LOW);

  pinMode(tastPin1, INPUT);
  pinMode(tastPin2, INPUT);

  //SecureSend intialisieren und Status mit LED anzeigen
  bool initStatus = SecureSend.init(512, 0x50, 0);
  SecureSend.indicateOnLed(initStatus, ledPin1, 500, 2000);
 
  SecureSend.openReadingPipe(1, 0xFEFEFEFEF1LL);
  SecureSend.openWritingPipe(0xFEFEFEFEF1LL);
}


void loop() {
  //Tastenabfrage alle 150 ms (Metro)
  if (tastAbfrage.check())
  {
    tastWert1 = digitalRead(tastPin1);
    tastWert2 = digitalRead(tastPin2);
    befehl[0] = '\0'; //Befehls-Array loeschen
    //Wenn Taste1 oder Taste2 gedrueckt, Zeichenfolge ins Befehls-Array kopieren
    if (tastWert1 == 1) strcpy(befehl, "LED EIN");
    else if (tastWert2 == 1) strcpy(befehl, "LED AUS");
    //Wenn befehl ungleich NULL, sende gesichert und zeige Status mit LED an
    if (befehl[0] != '\0')
    {
      bool txAckn = SecureSend.transmit(befehl, sizeof(befehl));
      SecureSend.indicateOnLed(txAckn, ledPin1, 500, 2000);
    }
  }
}


//Pruefsummenbildung (wird von der MySecureSend-Library aufgerufen)
//Formeln muessen im Sender und Empfaenger identisch sein
unsigned long MySecureSend_Pruefsumme(byte* eeWert, byte auswahl)
{
  unsigned long sum1;
  unsigned long sum2;
  unsigned long sum3;
  unsigned long pruefSumme;
  //Pruefsumme1
  if (auswahl == 1)
  {
    sum1 = eeWert[0] + eeWert[1];
    sum2 = eeWert[1] + eeWert[2];
    sum3 = eeWert[2] + eeWert[3];
    pruefSumme = (unsigned long)(sum1 * sum2);
    pruefSumme = pruefSumme * sum3;
  }
  //Pruefsumme2
  else if (auswahl == 2)
  {
    sum1 = eeWert[0] + eeWert[3];
    sum2 = eeWert[1] + eeWert[4];
    sum3 = eeWert[2] + eeWert[5];
    pruefSumme = (unsigned long)(sum1 * sum3);
    pruefSumme = pruefSumme * sum2;
  }

  return pruefSumme;
}


Testprogramm Empfänger:

//Testprogramm MySecureSend-Library Empfaenger
//Code fuer Arduino
//Author Retian
//Version 1.4


#include <MySecureSend.h>
#include <Metro.h>


MySecureSend SecureSend;
Metro empfaengerAbfrage = Metro(50); //Metro-Zyklus 50 ms


#define ledPin1 4 //Status-LED1
#define ledPin2 5 //LED2 auf Pin5 (simuliert Ein-/Ausschalten eines Geraetes)


byte mySecureSend_CE = 9; //CE-Pin des RF-Moduls
byte mySecureSend_CSN = 10; //CSN-Pin des RF-Moduls

char befehl[20]; //Befehls-Array
byte befCode;


void setup() {
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);

  //SecureSend intialisieren und Status mit LED anzeigen
  bool initStatus = SecureSend.init(512, 0x50, 0);
  SecureSend.indicateOnLed(initStatus, ledPin1, 1000, 2000);

  SecureSend.openReadingPipe(1, 0xFEFEFEFEF1LL);
  SecureSend.openWritingPipe(0xFEFEFEFEF1LL);
}


void loop() {
  //Empfaengerabfrage alle 50 ms (Metro)
  if (empfaengerAbfrage.check())
  {
    //Abfrage, ob Befehl bereitsteht, wenn ja, dann gesichert empfangen
    if (SecureSend.checkReceive())
    {
      bool rxAckn = SecureSend.receive(befehl, sizeof(befehl));
      SecureSend.indicateOnLed(rxAckn, ledPin1, 500, 2000);
    }
  }
  //
  //Hier koennen Programm-Anweisungen stehen,
  //die der Empaenger sonst noch zu tun hat!
  //
}


//Befehlstextpruefung (wird von der MySecureSend-Library aufgerufen)
bool MySecureSend_CheckBefehl(char* bef)
{
  if (strcmp(bef, "LED EIN") == 0)
  {
    befCode = 1;
    return true;
  }
  else if (strcmp(bef, "LED AUS") == 0)
  {
    befCode = 2;
    return true;
  }
  else return false;
}


//Befehlsausfuehrung (wird von der MySecureSend-Library aufgerufen)
void MySecureSend_ExecuteBefehl(char* bef)
{
  switch (befCode)
  {
    //LED2 EIN
    case 1:
      digitalWrite(ledPin2, HIGH);
      break;
    //LED2 AUS
    case 2:
      digitalWrite(ledPin2, LOW);
      break;
  }
}


//Pruefsummenbildung (wird von der MySecureSend-Library aufgerufen)
//Formeln muessen im Sender und Empfaenger identisch sein
unsigned long MySecureSend_Pruefsumme(byte* eeWert, byte auswahl)
{
  unsigned long sum1;
  unsigned long sum2;
  unsigned long sum3;
  unsigned long pruefSumme;
  //Pruefsumme1
  if (auswahl == 1)
  {
    sum1 = eeWert[0] + eeWert[1];
    sum2 = eeWert[1] + eeWert[2];
    sum3 = eeWert[2] + eeWert[3];
    pruefSumme = (unsigned long)(sum1 * sum2);
    pruefSumme = pruefSumme * sum3;
  }
  //Pruefsumme2
  else if (auswahl == 2)
  {
    sum1 = eeWert[0] + eeWert[3];
    sum2 = eeWert[1] + eeWert[4];
    sum3 = eeWert[2] + eeWert[5];
    pruefSumme = (unsigned long)(sum1 * sum3);
    pruefSumme = pruefSumme * sum2;
  }

  return pruefSumme;
}