ESP32 : Messages chiffrés ESP-NOW | Tutoriel

ESP32 : Messages chiffrés ESP-NOW |  Tutoriels Nerd aléatoires

Dans ce guide, vous apprendrez à chiffrer les messages ESP-NOW échangés entre les cartes ESP32. ESP-NOW utilise la méthode CCMP pour le chiffrement à l’aide d’une clé principale principale (PMK) et de clés principales locales (LMK).

Messages chiffrés ESP32 ESP-NOW IDE Arduino

Si vous débutez avec ESP-NOW, nous vous recommandons de lire d’abord le guide de démarrage suivant pour vous familiariser avec les concepts et fonctions ESP-NOW sur l’ESP32 :

Protocole de sécurité CCMP

CCMP signifie Counter Mode with Cipher Block Chaining Message Authentication Code Protocol. Il s’agit d’un protocole de cryptage conçu pour le LAN sans fil. ESP-NOW peut utiliser la méthode CCMP pour chiffrer les messages.

En conséquence à la Documentation:

« Utilisation ESP-NOW CCMP méthode qui peut être référencée dans IEEE Std. 802.11-2012 pour protéger le cadre d’action spécifique au fournisseur. »

L’appareil Wi-Fi maintient un Clé principale principale (PMK) et plusieurs Clés principales locales (LMK). La longueur des clés est de 16 octets.

Clé principale principale (PMK)

PMK est utilisé pour chiffrer LMK avec l’algorithme AES-128. Pour définir la clé PMK de l’appareil Wi-Fi, vous pouvez utiliser le esp_now_set_pmk() fonction pour régler PMK. Si PMK n’est pas défini, un PMK par défaut sera utilisé.

Clé principale locale (LMK)

Vous devez définir le LMK de l’appareil couplé pour chiffrer le cadre d’action spécifique au fournisseur avec la méthode CCMP. Le nombre maximum de LMK différents est de six. Le LMK est une propriété du pair, esp_now_peer_info_t objet, et peut être défini sur le lmk propriété comme nous le verrons plus tard.

ESP32 : Obtenir l’adresse MAC de la carte

Pour communiquer via ESP-NOW, vous devez connaître les adresses MAC des cartes afin de pouvoir vous ajouter en tant que pairs.

Chaque ESP32 a une adresse MAC unique et c’est ainsi que nous identifions chaque carte (apprenez comment obtenir et modifier l’adresse MAC ESP32).

Pour obtenir l’adresse MAC de votre carte, téléchargez le code suivant.

// Complete Instructions to Get and Change ESP MAC Address: https://Raspberryme.com/get-change-esp32-esp8266-mac-address-arduino/

#include "WiFi.h"
 
void setup(){
  Serial.begin(115200);
  WiFi.mode(WIFI_MODE_STA);
  Serial.println(WiFi.macAddress());
}
 
void loop(){

}

Afficher le code brut

Après avoir téléchargé le code, ouvrez le moniteur série à un débit en bauds de 115200 et appuyez sur le bouton ESP32 RST/EN. L’adresse MAC doit être imprimée comme suit :

ESP-NOW ESP32 Obtenir l'adresse MAC de la carte

Enregistrez l’adresse MAC de votre carte, car vous en aurez besoin dans les prochains exemples ESP-NOW.

Aperçu du projet

L’exemple que nous allons vous montrer est très simple afin que vous puissiez comprendre comment chiffrer vos messages ESP-NOW. L’expéditeur enverra une structure qui contient deux nombres aléatoires, X et yet un compteur variable (pour garder une trace du nombre de paquets envoyés).

Présentation du projet de messages chiffrés ESP32 ESP-NOW

Voici les principales étapes :

  1. L’expéditeur définit son PMK ;
  2. L’expéditeur ajoute le destinataire en tant que pair et définit son LMK ;
  3. Le récepteur définit sa PMK (devrait être la même que celle du récepteur) ;
  4. Le récepteur ajoute l’expéditeur en tant que pair et définit son LMK (devrait être le même que celui défini sur la carte de l’expéditeur) ;
  5. L’émetteur envoie la structure suivante à la carte réceptrice :
typedef struct struct_message {
    int counter;
    int x;
    int y;
} struct_message;
  1. Le destinataire reçoit le message.

Croquis de l’expéditeur ESP32 (chiffré ESP-NOW)

Voici le code de la carte ESP32 Sender. Copiez le code dans votre IDE Arduino, mais ne le téléchargez pas encore. Vous devez apporter quelques modifications pour que cela fonctionne pour vous.

/*
  Rui Santos
  Complete project details at https://Raspberryme.com/?s=esp-now
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/

#include <esp_now.h>
#include <WiFi.h>

// REPLACE WITH THE RECEIVER'S MAC Address
uint8_t receiverAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

// PMK and LMK keys
static const char* PMK_KEY_STR = "REPLACE_WITH_PMK_KEY";
static const char* LMK_KEY_STR = "REPLACE_WITH_LMK_KEY";

// Structure example to send data
// Must match the receiver structure
typedef struct struct_message {
    int counter;
    int x;
    int y;
} struct_message;

// Create a struct_message called myData
struct_message myData;

// Counter variable to keep track of number of sent packets
int counter;

// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("\r\nLast Packet Send Status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
 
void setup() {
  // Init Serial Monitor
  Serial.begin(115200);
 
  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);
  
  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("There was an error initializing ESP-NOW");
    return;
  }
  
  // Set PMK key
  esp_now_set_pmk((uint8_t *)PMK_KEY_STR);
  
  // Register the receiver board as peer
  esp_now_peer_info_t peerInfo;
  memcpy(peerInfo.peer_addr, receiverAddress, 6);
  peerInfo.channel = 0;
  //Set the receiver device LMK key
  for (uint8_t i = 0; i < 16; i++) {
    peerInfo.lmk[i] = LMK_KEY_STR[i];
  }
  // Set encryption to true
  peerInfo.encrypt = true;
  
  // Add receiver as peer        
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }

  // Once ESPNow is successfully Init, we will register for Send CB to
  // get the status of transmitted packet
  esp_now_register_send_cb(OnDataSent);
}
void loop() {
  static unsigned long lastEventTime = millis();
  static const unsigned long EVENT_INTERVAL_MS = 5000;
  if ((millis() - lastEventTime) > EVENT_INTERVAL_MS) {
    lastEventTime = millis();
    
    // Set values to send
    myData.counter = counter++;
    myData.x = random(0,50);
    myData.y = random(0,50);
  
    // Send message via ESP-NOW
    esp_err_t result = esp_now_send(receiverAddress, (uint8_t *) &myData, sizeof(myData));
    if (result == ESP_OK) {
      Serial.println("Sent with success");
    }
    else {
      Serial.println("Error sending the data");
    }  
  }
}

Afficher le code brut

N’oubliez pas que vous devez ajouter l’adresse MAC du récepteur dans le code. Dans mon cas, l’adresse MAC du récepteur est 30:AE:A4:07:0D:64. Ainsi, cela ressemblera à ceci sur le code:

// REPLACE WITH THE RECEIVER'S MAC Address
uint8_t receiverAddress[] = {0x30, 0xAE, 0xA4, 0x07, 0x0D, 0x64};

Examinons les parties de code pertinentes qui traitent du chiffrement.

Créez les clés PMK et LMK pour cet appareil sur les lignes suivantes. Il peut être composé de chiffres et de lettres et les clés sont de 16 octets (vous pouvez rechercher en ligne « compteur d’octets en ligne » pour vérifier la longueur de vos clés).

static const char* PMK_KEY_STR = "REPLACE_WITH_PMK_KEY";
static const char* LMK_KEY_STR = "REPLACE_WITH_LMK_KEY";

Par exemple, la clé peut être quelque chose comme ça 00XXmkwei/lpPÇf.

L’expéditeur et le destinataire doivent avoir les mêmes clés PMK et LMK.

Définissez la clé PMK de l’appareil à l’aide de esp_now_set_pmk() fonctionnent comme suit :

esp_now_set_pmk((uint8_t *)PMK_KEY_STR);

Le LMK est une propriété du périphérique pair, vous devez donc le définir lorsque vous enregistrez un périphérique en tant que pair. Vous définissez le LMK comme suit :

for (uint8_t i = 0; i < 16; i++) {
   peerInfo.lmk[i] = LMK_KEY_STR[i];
}

Vous devez également définir le Crypter propriété de pair comme vrai.

peerInfo.encrypt = true;

Et c’est tout. C’est tout ce que vous devez faire pour chiffrer les messages ESP-NOW. Maintenant, vous pouvez utiliser la fonction ESP-NOW pour échanger des données et les messages seront cryptés.

Croquis du récepteur ESP32 (messages cryptés ESP-NOW)

Voici le code de la carte récepteur ESP32. Copiez le code dans votre IDE Arduino, mais ne le téléchargez pas encore. Vous devez apporter quelques modifications pour que cela fonctionne pour vous.

/*
  Rui Santos
  Complete project details at https://Raspberryme.com/?s=esp-now
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/

#include <esp_now.h>
#include <WiFi.h>

// REPLACE WITH YOUR MASTER MAC Address
uint8_t masterMacAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

// PMK and LMK keys
static const char* PMK_KEY_STR = "REPLACE_WITH_PMK_KEY";
static const char* LMK_KEY_STR = "REPLACE_WITH_LMK_KEY";

// Structure example to send data
// Must match the sender structure
typedef struct struct_message {
    int counter; // must be unique for each sender board
    int x;
    int y;
} struct_message;

// Create a struct_message called myData
struct_message myData;

// Function to print MAC address on Serial Monitor
void printMAC(const uint8_t * mac_addr){
  char macStr[18];
  snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
           mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
  Serial.println(macStr);
}

// Callback function executed when data is received
void OnDataRecv(const uint8_t * mac_addr, const uint8_t *incomingData, int len) {
 
  Serial.print("Packet received from: ");
  printMAC(mac_addr);
  
  memcpy(&myData, incomingData, sizeof(myData));
  Serial.print("Bytes received: ");
  Serial.println(len);
  Serial.print("Packet number: ");
  Serial.println(myData.counter);
  Serial.print("X: ");
  Serial.println(myData.x);
  Serial.print("Y: ");
  Serial.println(myData.y);
}
void setup() {
  // Init Serial Monitor
  Serial.begin(115200);
 
  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);
  
  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("There was an error initializing ESP-NOW");
    return;
  }
  
  // Set the PMK key
  esp_now_set_pmk((uint8_t *)PMK_KEY_STR);
  
  // Register the master as peer
  esp_now_peer_info_t peerInfo;
  memcpy(peerInfo.peer_addr, masterMacAddress, 6);
  peerInfo.channel = 0;
  // Setting the master device LMK key
  for (uint8_t i = 0; i < 16; i++) {
    peerInfo.lmk[i] = LMK_KEY_STR[i];
  }
  // Set encryption to true
  peerInfo.encrypt = true;
  
  // Add master as peer       
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
  
  // Once ESPNow is successfully Init, we will register for recv CB to
  // get recv packer info
  esp_now_register_recv_cb(OnDataRecv);
}
void loop() {
  
}

Afficher le code brut

Vous devez ajouter la carte émettrice en tant qu’homologue. Donc, vous devez connaître son adresse MAC. Ajoutez l’adresse MAC de l’expéditeur dans la ligne suivante :

uint8_t masterMacAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

Définissez les clés PMK et LMK. Devrait être le même que l’autre carte.

static const char* PMK_KEY_STR = "REPLACE_WITH_PMK_KEY";
static const char* LMK_KEY_STR = "REPLACE_WITH_LMK_KEY";

Définissez la clé PMK de l’appareil à l’aide de esp_now_set_pmk() fonctionnent comme suit :

esp_now_set_pmk((uint8_t *)PMK_KEY_STR);

Le LMK est une propriété du périphérique pair, vous devez donc le définir lorsque vous enregistrez un périphérique en tant que pair. Vous définissez le LMK comme suit :

for (uint8_t i = 0; i < 16; i++) {
  peerInfo.lmk[i] = LMK_KEY_STR[i];}

Vous devez également définir le Crypter propriété de pair comme vrai.

peerInfo.encrypt = true;

Et voilà, maintenant la carte réceptrice peut recevoir et décrypter les messages cryptés envoyés par l’expéditeur.

Manifestation

Téléchargez les codes sur les tableaux correspondants.

Ouvrez le moniteur série pour vérifier ce qui se passe. Vous pouvez utiliser PuTTY pour pouvoir voir les messages sur les deux tableaux simultanément.

Voici ce que vous devriez obtenir sur la carte du récepteur :

Messages chiffrés du récepteur ESP-NOW PUTTY

Sur le tableau des expéditeurs, vous devriez recevoir des messages « Delivery Success ».

ESP-NOW Sender Messages chiffrés Delivery Success Serial Monitor

Conclusion

Dans ce didacticiel, vous avez appris à chiffrer les messages ESP-NOW à l’aide des clés PMK et LMK.

J’ai testé le cryptage dans différents scénarios et voici les résultats :

  • Expéditeur et destinataire cryptés avec les mêmes clés: la carte réceptrice reçoit les messages avec succès ;
  • L’expéditeur envoie des messages cryptés, mais le destinataire n’a pas les clés ou a des clés différentes : le destinataire ne reçoit pas les messages ;
  • Le destinataire a le code pour le cryptage mais l’expéditeur ne l’a pas: le destinataire reçoit quand même les messages. Je ne pense pas que ce soit le comportement auquel nous nous attendions. Puisque nous ajoutons le code de cryptage sur les deux cartes, on s’attendrait à ce que si la carte réceptrice recevait un message non crypté, elle l’ignorerait. Mais ce n’est pas ce qui se passe. Il reçoit tous les messages, cryptés et non cryptés. Pour le moment, il n’y a aucun moyen de savoir si le message reçu est crypté ou non, ce qui semble être une limitation pour le moment.

Nous espérons que vous avez trouvé ce tutoriel utile. Nous avons plus d’exemples ESP-NOW que vous pourriez aimer :

Si vous souhaitez en savoir plus sur la carte ESP32 et l’IoT, assurez-vous de consulter nos ressources :

Merci d’avoir lu.