The authentication is a fundamental process in any communication system, including those we make with an ESP32.
It consists of verifying the identity of a user, device, or entity before allowing access to a resource or service.
In any project that we intend to expose to the public, authentication is essential to protect our communications, data, and systems against unauthorized access.
So let’s look at the different methods we have available to implement it on a device like the ESP32.
Authentication is often combined with other security mechanisms, such as encryption, to ensure the integrity and confidentiality of the data.
Types of authentication on the ESP32
On the ESP32, we can implement several authentication methods, depending on the system requirements and our project:
- Password-based authentication: The most common method, where a user or device provides a password to verify their identity.
- Token-based authentication: Uses temporary tokens (like JWT) to validate identity.
- Device authentication via certificates: Employs digital certificates to verify the identity of a device.
- Message authentication: Ensures that messages come from a trusted source through digital signatures.
Next, we’ll see how to implement each of these methods on the ESP32.
Password-based authentication
Password-based authentication is the simplest and most widely used method. It consists of comparing a password provided by the user with one stored in the system.
To implement this method, we can store a password in the memory of the ESP32 (for example, in EEPROM or flash memory) and compare it with the user input.
#include <WiFi.h>
const char* ssid = "YourWiFiNetwork";
const char* password = "YourWiFiPassword";
String storedPassword = "secret123"; // Stored password
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
}
void loop() {
if (Serial.available()) {
String enteredPassword = Serial.readString(); // Read the entered password
enteredPassword.trim(); // Remove whitespace
if (enteredPassword == storedPassword) {
Serial.println("Authentication successful");
} else {
Serial.println("Authentication failed");
}
}
}
- Secure storage: Never store passwords in plain text. Use hash functions like SHA-256 to store only the hash of the password.
- Protection against brute force attacks: Limit the number of failed attempts to prevent brute force attacks.
Token-based authentication (JWT)
JWT (JSON Web Tokens) are a secure way to authenticate users or devices. A JWT is an encoded token that contains information about the user’s identity and permissions.
To use JWT on the ESP32, we need a library like ArduinoJson to handle the JSON format and a function to verify the token’s signature.
#include <WiFi.h>
#include <ArduinoJson.h>
#include <base64.h>
const char* ssid = "YourWiFiNetwork";
const char* password = "YourWiFiPassword";
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
}
bool verifyJWT(String token) {
// Decode the JWT token
int dot1 = token.indexOf('.');
int dot2 = token.indexOf('.', dot1 + 1);
String header = token.substring(0, dot1);
String payload = token.substring(dot1 + 1, dot2);
String signature = token.substring(dot2 + 1);
// Verify the signature (simplified)
// In a real case, you would use a cryptography library to verify the signature.
return true; // Simulated successful verification
}
void loop() {
if (Serial.available()) {
String token = Serial.readString(); // Read the JWT token
token.trim(); // Remove whitespace
if (verifyJWT(token)) {
Serial.println("Authentication successful with JWT");
} else {
Serial.println("Authentication failed with JWT");
}
}
}
Advantages of JWT
- Stateless: Does not require storing information on the server.
- Security: Tokens can be signed and encrypted to ensure their integrity.
Device authentication via certificates
Certificate-based authentication is a more secure method that uses digital certificates to verify the identity of a device. This method is common in IoT applications where security is critical.
The ESP32 supports TLS/SSL, allowing the use of certificates to authenticate devices in secure connections.
#include <WiFi.h>
#include <WiFiClientSecure.h>
const char* ssid = "YourWiFiNetwork";
const char* password = "YourWiFiPassword";
const char* server = "yourserver.com";
const char* certificate = "-----BEGIN CERTIFICATE-----\n"
"YOUR_CERTIFICATE_HERE\n"
"-----END CERTIFICATE-----\n";
WiFiClientSecure client;
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
client.setCACert(certificate); // Configure the certificate
}
void loop() {
if (!client.connected()) {
if (client.connect(server, 443)) {
Serial.println("Secure connection established");
client.println("GET / HTTP/1.1");
client.println("Host: " + String(server));
client.println("Connection: close");
client.println();
} else {
Serial.println("Connection error");
}
}
while (client.available()) {
String line = client.readStringUntil('\n');
Serial.println(line);
}
}
Advantages of certificates
- High security: Certificates are difficult to forge.
- Integration with PKI infrastructures: Compatible with enterprise certificate management systems.
Message authentication
Message authentication ensures that the received messages come from a trusted source and have not been altered. This is achieved through digital signatures or message authentication codes (MAC).
We can use algorithms like HMAC-SHA256 to authenticate messages.
#include <WiFi.h>
#include <mbedtls/md.h>
const char* ssid = "YourWiFiNetwork";
const char* password = "YourWiFiPassword";
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
}
String calculateHMAC(String message, String key) {
byte hmacResult[32];
mbedtls_md_context_t ctx;
mbedtls_md_init(&ctx);
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1);
mbedtls_md_hmac_starts(&ctx, (const unsigned char*)key.c_str(), key.length());
mbedtls_md_hmac_update(&ctx, (const unsigned char*)message.c_str(), message.length());
mbedtls_md_hmac_finish(&ctx, hmacResult);
mbedtls_md_free(&ctx);
String result;
for (int i = 0; i < 32; i++) {
char str[3];
sprintf(str, "%02x", (int)hmacResult[i]);
result += str;
}
return result;
}
void loop() {
if (Serial.available()) {
String message = Serial.readString(); // Read the message
message.trim(); // Remove whitespace
String key = "secretKey";
String hmac = calculateHMAC(message, key);
Serial.println("Calculated HMAC: " + hmac);
}
}
Advantages of message authentication
- Integrity: Ensures that messages have not been altered.
- Authenticity: Verifies that messages come from a trusted source.
- Efficiency: Algorithms like HMAC are fast and suitable for embedded systems.