Cryptage communication Lora MKR1310

Bonjour, dans le cadre de mon stage je cherche a creer un reseau LoRa fermé qui a pour but de recuperer la temperature et l 'humidite dans un local et en fonction de celle-ci allumer ou non le chauffage. Pour cela j'utilise des Arduino MKR1310. Dans le systeme, il y en a une (ou plus potentielleemnt) comme emettrice qui va envoyer la temperature et l'humidite et l autre comme receptrice.
La communication se fait comme suit:
E: envoie la temperature et l humidite et attend une reponse
R: Recoit le paquet puis renvoie celui ci comme reponse
R: Transmet via le port serie les donnees a un script python
Le script python analyse les donnees et renvoie une commande ON/OFF
R: Renvoi la commande
E: La recupere et active ou non l'actionneur (dans le code juste une led pour l'instant)

Toute cette partie fonctionnait très bien quand je n'avais pas encore implenté le cryptage.

Après j'ai via la bibliotheque AESLib crypter toutes les communications LoRa et cela fonctionne bien dans l'ensemble à un détail qui me fait m'arracher les cheveux depuis une semaine: au bout d'un certains temps la boucle de l'un des deux codes s'arrete. Parfois c'est l'emetteur et parfois le recepteur, ça prend parfois des dizaines d'iterations et parfois des centaines mais ça le fait à chaque fois. De plus j'ai placé plusieurs print dans le programme pour savoir ou est ce qu'il s'arrete mais ce n'est pas toujours la meme chose. De ce que j'ai compris ce genre d'erreur peuvent etre dues a des depassements de memoire, des boucles infines (probablement pas le cas ici) ou peut etre un probleme au niveau de la librairie (A noter que j'ai supprimer une ligne du fichier AESlib.h qui contenait une fonction qui bloqué la compilation c'est peut etre stupide mais c'est le seul moyen que j'ai trouvé pour pouvoir compiler).Merci d'avance pour votre aide !


// --- Emetteur LoRa ---
#include <SPI.h>
#include <LoRa.h>
#include "DHT.h"
#include <AESLib.h>

AESLib aesLib;

byte aes_key[] = {
  0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
  0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81
};

byte aes_iv[] = {
  0x00, 0x01, 0x02, 0x03,
  0x04, 0x05, 0x06, 0x07,
  0x08, 0x09, 0x0A, 0x0B,
  0x0C, 0x0D, 0x0E, 0x0F
};


// Fonction pour ajouter du padding pour le cryptage
int addPadding(byte *data, int len) {
  int padLen = 16 - (len % 16);
  for (int i = 0; i < padLen; i++) {
    data[len + i] = padLen;
  }
  return len + padLen;
}

// Fonction pour retirer le padding apres le decryptage
int removePadding(byte* data, int len) {
  int padLen = data[len - 1];
  return len - padLen;
}
#define LED_Chauffage 6
#define LORA_BAND 868E6  // Frequenza LoRa
#define SYSTEM_ID 1234    // ID del sistema impostato dall'utente
#define NUM 2              // Numero of the Node

int counter = 0;
#define DHTPIN 2
#define DHTTYPE  DHT11

DHT dht(DHTPIN, DHTTYPE);
int compt=0;
void setup() {
    Serial.begin(115200);
    dht.begin();
    //while (!Serial);
    pinMode(LED_Chauffage, OUTPUT);
    Serial.println("LoRa Sender");
    Serial.println("0");
    if (!LoRa.begin(LORA_BAND)) {
        Serial.println("Starting LoRa failed!");
        while (1);
    }
}

void loop() {
  LoRa.flush(); // vider le buffer Lora
  Serial.println("0");
  //lire la temperature et l'humidite du capteur DHT
    int h = dht.readHumidity();
    Serial.println("01");
    int t = dht.readTemperature();
    Serial.println("02");
    bool ackReceived = false;
    
    String expectedResponse = String(SYSTEM_ID) + "," + String(t)+ "," + String(h)+"," + String(NUM);
    Serial.println(compt);
    compt++;

    
    

Serial.println("03");
    while (!ackReceived) {
      Serial.println("02");
        Serial.print("Valore trasmesso: ");
        Serial.print(t);
        Serial.print(",");
        Serial.print(h);
        Serial.print(",");
        Serial.println(NUM);
        

        //Recuperation des donnees sous forme de char, puis on place cette chaine de caractere dans un tableau de Byte 
        
        String capteur=expectedResponse;
        byte capteur_plain[64];
        byte capteur_encrypted[64];
        Serial.println("erreur2");
        int msgLen = capteur.length();
        memcpy(capteur_plain, capteur.c_str(), msgLen);

        // On ajoute du padding au cas ou la chaine de caractere n'a pas une longueur multiple de 16
        //puis on crypte le message avant de l'envoyer en lora
        int paddedLen = addPadding(capteur_plain, msgLen);
        aesLib.encrypt(capteur_plain, paddedLen,capteur_encrypted, aes_key, 128, aes_iv);
        LoRa.beginPacket();
        LoRa.write(capteur_encrypted, paddedLen);
        LoRa.endPacket();
        Serial.println("Pacchetto inviato, in attesa di conferma...");
        Serial.println("erreur3");

        // Une fois envoye on attend la reponse du receiver
        LoRa.receive();
        long startWait = millis();
        String receivedData = "";
        Serial.println("erreur4");

        // On attend la reponse pdt 2 secondes et on decrypte le message de la meme maniere que poiur l encryption
        //Si la reponse est equivalente a ce qu'on a envoye on peut passer au renvoi de la commande

        while (millis() - startWait < 2000) {  // Timeout de 2 secondes
            int packetSize = LoRa.parsePacket();
            if (packetSize) {
              Serial.println("erreur6");
                byte rep_encrypted[64];
                byte rep_decrypted[64];
                int len = 0;
                while (LoRa.available() && len < 64) {
                    rep_encrypted[len++] = LoRa.read();
                }
                aesLib.decrypt(rep_encrypted, len, rep_decrypted, aes_key, 128, aes_iv);
                int realLen = removePadding(rep_decrypted, len);
                rep_decrypted[realLen] = '\0'; // Fin de chaîne

                Serial.print("Risposta ricevuta: ");
                Serial.println("erreur7");
                Serial.println((char*)rep_decrypted);
                receivedData = String((char*)rep_decrypted);
                if (receivedData == expectedResponse) {
                    Serial.println("Conferma ricevuta!");
                    ackReceived = true;
                    break;
                } else {
                    Serial.println("Errore! Ritrasmissione...");
                    break;
                }
            }
          }
        }


        //On passe en mode reception pour recuperer la commande
        Serial.println("04");
        LoRa.flush();
        Serial.println("erreur8");
        long startWait = millis();
        String command="";
        while (millis() - startWait < 2000) { 
        int packetSize = LoRa.parsePacket();
        if (packetSize) {
          byte command_encrypted[64];
          byte command_decrypted[64];
          int len = 0;
          Serial.println("erreur9");

          while (LoRa.available() && len < 64) {
            command_encrypted[len++] = LoRa.read();
          }
          Serial.println("erreur10");
          aesLib.decrypt(command_encrypted, len, command_decrypted, aes_key, 128, aes_iv);
          int realLen = removePadding(command_decrypted, len);
          command_decrypted[realLen] = '\0'; // Fin de chaîne
          command = String((char*)command_decrypted);

           Serial.print("Message reçu (déchiffré) : ");
            Serial.println(command);
            Serial.println("erreur11");

          // on recupere chaque element de la commnde separement
          // Si "l etat" de la commande est sur ON la led s'allume sinon elle s'eteint
          int commaIndex = command.indexOf(',');
          int commaIndex2 = command.indexOf(',',commaIndex+1);
          if (commaIndex != -1) {
            Serial.println("erreur12");
              int Com_ID = command.substring(0, commaIndex).toInt();
              String Com_state = command.substring(commaIndex + 1,commaIndex2);
              int Com_Num = command.substring(commaIndex2+1).toInt();
     Serial.println("erreur121");
              if(Com_state=="ON" && Com_Num==NUM && Com_ID==SYSTEM_ID){
                digitalWrite(LED_BUILTIN, HIGH);
                Serial.println("LIGHT ON");
                
              }
              else if(Com_state=="OFF"){
                Serial.println("erreur123");
                digitalWrite(LED_BUILTIN, LOW);
                Serial.println("Light OFF");
              }
              else{
                Serial.println("erreur122");
                digitalWrite(LED_BUILTIN, LOW);
                Serial.println("Error command");
              }
          }
        }
        }
    
  
    Serial.println("erreur13");
    delay(7000);
   
}


// --- Recepteur LoRa ---
#include <SPI.h>
#include <LoRa.h>
#include  <AESLib.h>

#define LORA_BAND  868E6  // Frequenza LoRa
#define SYSTEM_ID 1234    // ID del sistema impostato dall'utente
#define NUM 1

AESLib aesLib;

byte aes_key[] = {
  0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
  0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81
};

byte aes_iv[] = {
  0x00, 0x01, 0x02, 0x03,
  0x04, 0x05, 0x06, 0x07,
  0x08, 0x09, 0x0A, 0x0B,
  0x0C, 0x0D, 0x0E, 0x0F
};


int removePadding(byte* data, int len) {
  int padLen = data[len - 1];
  return len - padLen;
}


int addPadding(byte *data, int len) {
  int padLen = 16 - (len % 16);
  for (int i = 0; i < padLen; i++) {
    data[len + i] = padLen;
  }
  return len + padLen;
}

int counter = 0;
void setup() {
    Serial.begin(115200);
   // while (!Serial);
    //Serial.println("LoRa Receiver");
    if (!LoRa.begin(LORA_BAND)) {
        //Serial.println("Starting LoRa failed!");
        while (1);
    }
    LoRa.receive();  // Mette subito il ricevitore in ascolto
}

void loop() {
  LoRa.flush();
 
    int packetSize = LoRa.parsePacket();
    if (packetSize) {
        byte receivedData_encrypted[64];
        byte receivedData_decrypted[64];
        int len = 0;
        String receivedData = "";
        while (LoRa.available() && len < 64) {
            receivedData_encrypted[len++] = LoRa.read();
        }

        aesLib.decrypt(receivedData_encrypted, len, receivedData_decrypted, aes_key, 128, aes_iv);
        int realLen = removePadding(receivedData_decrypted, len);
        receivedData_decrypted[realLen] = '\0'; // Fin de chaîne
        receivedData = String((char*)receivedData_decrypted);

         //Serial.println("données reçues: ");


        

        // Parsing ID e valore
        int commaIndex = receivedData.indexOf(',');
        int commaIndex2 = receivedData.indexOf(',',commaIndex+1);
        int commaIndex3 = receivedData.indexOf(',',commaIndex2+1);
        if (commaIndex != -1) {
            int receivedID = receivedData.substring(0, commaIndex).toInt();
            int receivedValueTemp = receivedData.substring(commaIndex + 1,commaIndex2).toInt();
            int receivedValueHum = receivedData.substring(commaIndex2+1,commaIndex3).toInt();
            int receivedNum = receivedData.substring(commaIndex3+1).toInt();
           
            //Serial.print(receivedID);
            //Serial.print("Valeur T: ");
            //Serial.print(receivedValueTemp);
            //Serial.print("Valeur Humidity: ");
            //Serial.print(receivedValueHum);
            //Serial.print("Numero sender: ");
            //Serial.println(receivedNum);
            
            if (receivedID == SYSTEM_ID) {
             Serial.println(counter);
             counter++;
                 Serial.println(receivedData);
                //Serial.print("Valore valido ricevuto: ");
                //Serial.println(receivedValue);
                
                // Ritenta l'invio della risposta fino a conferma
                bool responseSent = false;
                for (int i = 0; i < 3 && !responseSent; i++) {  // Fino a 3 tentativi
                  String reponse=String(SYSTEM_ID)+","+String(receivedValueTemp)+","+String(receivedValueHum)+","+String(receivedNum);
                  byte plain[64]; 
                  byte reponse_encrypted[64];
                  int msgLen = reponse.length();
                  memcpy(plain, reponse.c_str(), msgLen);
                  int paddedLen = addPadding(plain, msgLen);
                  aesLib.encrypt(plain, paddedLen, reponse_encrypted, aes_key, 128, aes_iv);

                  //Serial.print("Reponse envoyée: ");
                  //Serial.println(reponse);
                  

                  
                  delay(200);  // Attende prima di rispondere
                  LoRa.beginPacket();
                  LoRa.write(reponse_encrypted, paddedLen);
                  LoRa.endPacket();
                  //Serial.println("Risposta inviata");
                  responseSent = true;
                 
                }

                


                LoRa.receive();
                 delay(1000);
                 String command="";
                 if (Serial.available()) {
                    String command = Serial.readStringUntil('\n');
                    Serial.print("je le recois");
                    byte command_plain[64];
                    byte command_encrypted[64];
                    int msgLen = command.length();
                    memcpy(command_plain, command.c_str(), msgLen);
                    int paddedLen = addPadding(command_plain, msgLen);
                     aesLib.encrypt(command_plain, paddedLen, command_encrypted, aes_key, 128, aes_iv);
                
                    LoRa.beginPacket();
                    LoRa.write(command_encrypted, paddedLen);
                    LoRa.endPacket();
                    Serial.println("message envoyé");

                    
                
                      
                    }
                    else{
                      LoRa.beginPacket();
                      LoRa.print("ERROR_COMMAND");
                      LoRa.endPacket();
      
                      delay(10);
                    }
                   }
         
                 }
                 
                LoRa.receive();
                //else {
                //Serial.println("ID errato, pacchetto ignorato");
            //}
        }
 }

Vous devriez réinitialiser le vecteur d’initialisation IV avant chaque chiffrement et déchiffrement, car AESLib modifie l’IV en interne et sa réutilisation peut provoquer des blocages.

Virez aussi les flush() ça peut avoir des effets indésirables (bloquer le SPi).

Vous pourriez également définir tous les buffers comme variables globales pour limiter l’usage de la pile (au cas ou vous seriez un peu juste)

C’est mauvais signe pour la compatibilité avec votre carte. passez à une version compatible. Vous avez regardé sinon la bibliothèque GitHub - arduino-libraries/ArduinoECCX08 qui est prévue pour votre chip de cryptage embarqué sur votre carte?

Merci pour votre réponse. Je vais essayer cela. Juste comment faire pour reinitialiser l'IV. De ce que j'ai compris il faut qu'il soit partager par les deux codes donc si je le change ça doit etre le meme. Est-ce que je devrais envoyer l'IV dans le message pour l'utiliser directement après l'avoir reçu ou existe t'il une autre manière ?

conservez une copie du vecteur initial et recopiez le avant chaque usage. Par exemple :

const byte aes_iv_init[] = {
  0x00, 0x01, 0x02, 0x03,
  0x04, 0x05, 0x06, 0x07,
  0x08, 0x09, 0x0A, 0x0B,
  0x0C, 0x0D, 0x0E, 0x0F
};

byte aes_key[sizeof aes_key_init];

void resetIV() {
  memcpy(aes_iv, aes_iv_init, sizeof aes_iv);
}

Ensuite, vous appellez resetIV() juste avant chaque aesLib.encrypt() et aesLib.decrypt().

C'est bon ça marche il a tourné toute la nuit merci beaucoup !

Super !