Browse Source

Add encryption via ESP-NOW

master
Riyyi 21 hours ago
parent
commit
224f22f23d
  1. 37
      README.org
  2. 105
      client/src/connect.cpp
  3. 18
      client/src/connect.h
  4. 74
      client/src/main.cpp
  5. 7
      client/src/secrets.h.example
  6. 0
      server/src/IPAddress.h
  7. 99
      server/src/connect.cpp
  8. 6
      server/src/connect.h
  9. 90
      server/src/main.cpp
  10. 7
      server/src/secrets.h.example

37
README.org

@ -15,3 +15,40 @@ platformio run --target upload
** Console
platformio device monitor
** Configuration
The following fields in =secrets.h= have to be configured:
- CLIENT_MAC
- SERVER_MAC
- PMK
- LMK
You have to configure the real STA MAC address of *both* the client and server.
It might be odd that the AP MAC of the receiver isn't used, but that's how
ESP-NOW works. You can find the MAC address with the following code.
#+BEGIN_SRC cpp
#include <esp_wifi.h>
void printMacAddress()
{
uint8_t mac[6];
esp_err_t ret = esp_wifi_get_mac(WIFI_IF_STA, mac);
if (ret == ESP_OK) {
Serial.printf("{ %#x, %#x, %#x, %#x, %#x, %#x }\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
else {
Serial.println("Failed to read MAC address");
}
}
#+END_SRC
PMK and LMK have to be 16 characters long and should be the same between the
client and server.
* References
- https://randomnerdtutorials.com/esp32-esp-now-encrypted-messages/

105
client/src/connect.cpp

@ -1,67 +1,118 @@
#include <cstdint>
#include <Arduino.h>
#include <IPAddress.h>
#include <WiFi.h>
#include <esp_now.h>
#include <esp_wifi.h>
#include "connect.h"
#include "esp32-hal.h"
#include "secrets.h"
uint64_t start;
uint8_t client_mac[6] = CLIENT_MAC;
uint8_t server_mac[6] = SERVER_MAC;
uint64_t connect = 0;
uint64_t is_connecting = 0;
IPAddress host;
uint64_t ack = 0;
uint8_t ack_speed = 50;
// -----------------------------------------
void wifiSetupEncryption();
void timerStart()
void timerStart(uint64_t* timer)
{
start = millis();
*timer = millis();
}
uint64_t timerElapsed()
uint64_t timerElapsed(uint64_t* timer)
{
auto now = millis();
uint64_t elapsed = now - start;
uint64_t elapsed = now - *timer;
return elapsed;
}
// -----------------------------------------
void wifiSetup()
{
WiFi.mode(WIFI_STA);
WiFi.setAutoReconnect(false);
WiFi.disconnect();
delay(100);
esp_wifi_set_channel(static_cast<uint8_t>(CHANNEL), WIFI_SECOND_CHAN_NONE);
wifiSetupEncryption();
}
void wifiConnect()
// -----------------------------------------
void onDataSent(const uint8_t* mac_addr, esp_now_send_status_t status)
{
if (WiFi.status() == WL_CONNECTED) {
if (is_connecting > 0) {
host = WiFi.gatewayIP();
Serial.println("Connected to AP!");
}
is_connecting = 0;
if (status != ESP_NOW_SEND_SUCCESS) {
return;
}
if (is_connecting == 0 || timerElapsed() > is_connecting * 1000) {
if (is_connecting == 0) {
is_connecting = 10; // start with a 10 second delay
Serial.println("Receive ACK");
// Flash PWR LED while still receiving acknowledgments
if (timerElapsed(&ack) > ack_speed * 2) {
timerStart(&ack);
digitalWrite(POWER_LED_PIN, HIGH);
delay(ack_speed);
digitalWrite(POWER_LED_PIN, LOW);
}
else {
is_connecting *= 2; // exponential backoff
}
timerStart();
Serial.println("Connecting");
WiFi.begin(SSID, PASSWORD);
void onDataRecv(const uint8_t* mac_addr, const uint8_t* data, int data_len)
{
Serial.print("Received: ");
Serial.write(data, data_len);
Serial.println();
auto msg = String((const char*)data, data_len);
if (msg == "power_released_ack") {
need_power_ack = false;
wait_power_ack = false;
}
if (msg == "reset_released_ack") {
need_reset_ack = false;
wait_reset_ack = false;
}
}
IPAddress wifiHost()
void wifiSetupEncryption()
{
return host;
esp_now_deinit();
if (esp_now_init() != ESP_OK) {
Serial.println("Failed to init ESP-NOW");
return;
}
if (esp_now_set_pmk((const uint8_t*)PMK) != ESP_OK) {
Serial.println("Failed to set PMK");
return;
}
auto peerInfo = esp_now_peer_info_t {
.channel = static_cast<uint8_t>(CHANNEL),
.encrypt = true,
};
memcpy(peerInfo.peer_addr, server_mac, 6);
memcpy(peerInfo.lmk, LMK, 16);
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
Serial.println("Failed to add peer");
return;
}
esp_now_register_send_cb(onDataSent);
esp_now_register_recv_cb(onDataRecv);
Serial.println("Configured encryption!");
}
// https://docs.espressif.com/projects/arduino-esp32/en/latest/api/wifi.html

18
client/src/connect.h

@ -1,5 +1,17 @@
#include "IPAddress.h"
#include <cstdint>
#define CHANNEL 11
#define POWER_LED_PIN 3
#define RESET_LED_PIN 1
extern bool need_power_ack;
extern bool need_reset_ack;
extern bool wait_power_ack;
extern bool wait_reset_ack;
extern uint8_t client_mac[6];
extern uint8_t server_mac[6];
void wifiSetup();
void wifiConnect();
IPAddress wifiHost();

74
client/src/main.cpp

@ -1,21 +1,19 @@
#include <Arduino.h>
#include <WiFiClient.h>
#include <esp_now.h>
#include "connect.h"
#define PORT 1234
#define POWER_BUTTON_PIN 10
#define RESET_BUTTON_PIN 2
#define POWER_LED_PIN 3
#define RESET_LED_PIN 1
WiFiClient client;
int previousPowerButtonState = HIGH;
int previousResetButtonState = HIGH;
void ack();
bool need_power_ack = false;
bool need_reset_ack = false;
bool wait_power_ack = false;
bool wait_reset_ack = false;
void setup()
{
@ -28,19 +26,17 @@ void setup()
pinMode(POWER_LED_PIN, OUTPUT);
pinMode(RESET_LED_PIN, OUTPUT);
wifiSetup();
delay(3000);
Serial.println("Client booted!");
wifiSetup();
}
void loop()
{
delay(20); // used for button debounce
wifiConnect();
digitalWrite(POWER_LED_PIN, LOW);
// digitalWrite(POWER_LED_PIN, LOW);
digitalWrite(RESET_LED_PIN, LOW);
int powerButtonState = digitalRead(POWER_BUTTON_PIN);
@ -50,9 +46,6 @@ void loop()
if (powerButtonState == LOW && resetButtonState == LOW) {
previousPowerButtonState = HIGH;
previousResetButtonState = HIGH;
if (client.connected()) {
client.stop();
}
return;
}
@ -68,46 +61,31 @@ void loop()
Serial.println("Pressed " + button + " button!");
if (!client.connected() && !client.connect(wifiHost(), PORT)) {
Serial.println("Connection failed");
return;
}
client.print(button + "_pressed\n");
String msg = button + "_pressed";
esp_now_send(server_mac, (const uint8_t*)msg.c_str(), msg.length());
Serial.println("Sent " + button + " button press");
ack();
}
else {
if (!client.connected()) {
need_power_ack = true;
need_reset_ack = true;
wait_power_ack = false;
wait_reset_ack = false;
return;
}
client.print("power_released\n");
if (need_power_ack && !wait_power_ack) {
String msg = "power_released";
esp_now_send(server_mac, (const uint8_t*)msg.c_str(), msg.length());
Serial.println("Sent power button release");
ack();
client.print("reset_released\n");
Serial.println("Sent reset button release");
ack();
client.stop();
}
wait_power_ack = true;
}
if (need_reset_ack && !wait_reset_ack) {
String msg = "reset_released";
esp_now_send(server_mac, (const uint8_t*)msg.c_str(), msg.length());
Serial.println("Sent reset button release");
// -----------------------------------------
void ack()
{
while (client.connected()) {
if (client.available()) {
// Wait for acknowledgment from the receiver
String response = client.readStringUntil('\n');
if (response == "ACK") {
digitalWrite(POWER_LED_PIN, HIGH);
Serial.println("Received ACK");
return;
}
}
wait_reset_ack = true;
}
}

7
client/src/secrets.h.example

@ -1,4 +1,7 @@
#pragma once
#define SSID "EXAMPLE"
#define PASSWORD "12345678"
#define CLIENT_MAC { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
#define SERVER_MAC { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
#define PMK "MASTERKEY1234567" // ESP_NOW_KEY_LEN = 16
#define LMK "1234567890ABCDEF" // ESP_NOW_KEY_LEN = 16

0
server/src/IPAddress.h

99
server/src/connect.cpp

@ -0,0 +1,99 @@
#include <cstdint>
#include <Arduino.h>
#include <WiFi.h>
#include <esp_now.h>
#include <esp_wifi.h>
#include "connect.h"
#include "secrets.h"
uint8_t client_mac[6] = CLIENT_MAC;
uint8_t server_mac[6] = SERVER_MAC;
bool powerRemotePressed = false;
bool resetRemotePressed = false;
// -----------------------------------------
void wifiSetupEncryption();
void onDataSent(const uint8_t* mac_addr, esp_now_send_status_t status)
{
}
void onDataRecv(const uint8_t* mac_addr, const uint8_t* data, int data_len)
{
Serial.print("Received: ");
Serial.write(data, data_len);
Serial.println();
auto msg = String((const char*)data, data_len);
if (msg == "power_pressed") {
powerRemotePressed = true;
}
else if (msg == "power_released") {
powerRemotePressed = false;
}
else if (msg == "reset_pressed") {
resetRemotePressed = true;
}
else if (msg == "reset_released") {
resetRemotePressed = false;
}
else {
return;
}
String reply = msg + "_ack";
esp_now_send(client_mac, (const uint8_t*)reply.c_str(), reply.length());
}
void wifiSetup()
{
WiFi.mode(WIFI_STA);
WiFi.setAutoReconnect(false);
WiFi.disconnect();
delay(100);
esp_wifi_set_channel(static_cast<uint8_t>(CHANNEL), WIFI_SECOND_CHAN_NONE);
wifiSetupEncryption();
}
void wifiSetupEncryption()
{
esp_now_deinit();
if (esp_now_init() != ESP_OK) {
Serial.println("Failed to init ESP-NOW");
return;
}
if (esp_now_set_pmk((const uint8_t*)PMK) != ESP_OK) {
Serial.println("Failed to set PMK");
return;
}
auto peerInfo = esp_now_peer_info_t {
.channel = static_cast<uint8_t>(CHANNEL),
.encrypt = true,
};
memcpy(peerInfo.peer_addr, client_mac, 6);
memcpy(peerInfo.lmk, LMK, 16);
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
Serial.println("Failed to add peer");
return;
}
esp_now_register_send_cb(onDataSent);
esp_now_register_recv_cb(onDataRecv);
Serial.println("Configured encryption!");
}
// https://docs.espressif.com/projects/arduino-esp32/en/latest/api/wifi.html
// https://docs.arduino.cc/libraries/wifi/ (old)

6
server/src/connect.h

@ -0,0 +1,6 @@
#define CHANNEL 11
extern bool powerRemotePressed;
extern bool resetRemotePressed;
void wifiSetup();

90
server/src/main.cpp

@ -1,30 +1,21 @@
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <WiFiServer.h>
#include "secrets.h"
// Default gateway = 192.168.4.1
// Default IP address = 192.168.4.2
#define PORT 1234
#define CHANNEL 11
#define HIDDEN true
#define MAX_CONNECTION 1
#include "connect.h"
#define POWER_BUTTON_PIN 10
#define RESET_BUTTON_PIN 2
#define POWER_LED_PIN 3
#define RESET_LED_PIN 1
#define POWER_GATE_PIN 6
#define RESET_GATE_PIN 7
WiFiServer server(PORT, MAX_CONNECTION);
int previousPowerButtonState = HIGH;
int previousResetButtonState = HIGH;
bool powerPressed = false;
bool resetPressed = false;
bool powerButtonPressed = false;
bool resetButtonPressed = false;
void processButtons();
void setPowerPin(bool enable);
@ -35,6 +26,9 @@ void setup()
Serial.begin(9600);
Serial.setDebugOutput(true);
pinMode(POWER_BUTTON_PIN, INPUT_PULLUP);
pinMode(RESET_BUTTON_PIN, INPUT_PULLUP);
pinMode(POWER_GATE_PIN, OUTPUT);
pinMode(POWER_LED_PIN, OUTPUT);
pinMode(RESET_GATE_PIN, OUTPUT);
@ -43,85 +37,55 @@ void setup()
delay(3000);
Serial.println("Server booted!");
// Start button server
WiFi.softAP(SSID, PASSWORD, CHANNEL, HIDDEN, MAX_CONNECTION);
Serial.println("AP Started");
server.begin();
wifiSetup();
}
void loop()
{
WiFiClient client = server.available();
if (client) {
Serial.println("Client connected");
unsigned long start = 0;
while (client.connected()) {
if (client.available()) {
String msg = client.readStringUntil('\n');
Serial.print("Received: ");
Serial.println(msg);
if (msg == "power_pressed") {
powerPressed = true;
}
else if (msg == "power_released") {
powerPressed = false;
}
else if (msg == "reset_pressed") {
resetPressed = true;
}
else if (msg == "reset_released") {
resetPressed = false;
}
delay(20); // used for button debounce
client.print("ACK\n");
Serial.println("Sent ACK");
start = millis();
}
int powerButtonState = digitalRead(POWER_BUTTON_PIN);
int resetButtonState = digitalRead(RESET_BUTTON_PIN);
// Kill lingering connections
if (start != 0 && millis() - start > 200) {
Serial.println("Client kill..");
break;
}
processButtons();
// Unsupported usecase
if (powerButtonState == LOW && resetButtonState == LOW) {
previousPowerButtonState = HIGH;
previousResetButtonState = HIGH;
powerButtonPressed = false;
resetButtonPressed = false;
return;
}
setPowerPin(false);
setResetPin(false);
powerButtonPressed = powerButtonState == LOW;
resetButtonPressed = resetButtonState == LOW;
client.stop();
Serial.println("Client disconnected");
}
processButtons();
}
// -----------------------------------------
void processButtons()
{
if (powerPressed && resetPressed) {
if ((powerRemotePressed && resetRemotePressed)
|| (powerButtonPressed && resetButtonPressed)) {
Serial.println("Double input..");
setPowerPin(false);
setResetPin(false);
return;
}
setPowerPin(powerPressed);
setResetPin(resetPressed);
setPowerPin(powerRemotePressed || powerButtonPressed);
setResetPin(resetRemotePressed || resetButtonPressed);
}
void setPowerPin(bool enable)
{
powerPressed = enable;
// digitalWrite(POWER_GATE_PIN, (enable) ? HIGH : LOW);
digitalWrite(POWER_LED_PIN, (enable) ? HIGH : LOW);
}
void setResetPin(bool enable)
{
resetPressed = enable;
// digitalWrite(RESET_GATE_PIN, (enable) ? HIGH : LOW);
digitalWrite(RESET_LED_PIN, (enable) ? HIGH : LOW);
}

7
server/src/secrets.h.example

@ -1,4 +1,7 @@
#pragma once
#define SSID "EXAMPLE"
#define PASSWORD "12345678"
#define CLIENT_MAC { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
#define SERVER_MAC { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
#define PMK "MASTERKEY1234567" // ESP_NOW_KEY_LEN = 16
#define LMK "1234567890ABCDEF" // ESP_NOW_KEY_LEN = 16

Loading…
Cancel
Save