I dug up an example I had where the key was stored in EEPROM. it uses AESLib.h with AES128 and added EEPROM reading/saving use get and update.
when you run the code it checks in setup for an existing known keyword (the sentinel) to be present at some place (0 here) in EEPROM.
➜ if it finds it, it knows there is a safe to read the key from another location in EEPROM.
➜ if it does not find it, it writes a default key there, the sentinel for the next time and then tries to read that back. If you can't find the sentinel this time, it means the EEPROM is defective and you get an error message, if not it reads the key
(it assumes that somewhere else in the real code you have a way to store a new key and the sentinel)
Once this is done, I run a encode/decode with that key using AES128
may be that will be useful to you?
#include <AESLib.h> // https://github.com/DavyLandman/AESLib
// you can verify the result using https://cryptii.com/pipes/aes-encryption
#include <EEPROM.h>
const uint32_t sentinel = 0XDEADBEEF;
const uint16_t sentinelAddress = 0;
const uint16_t keyAddress = sentinelAddress + sizeof sentinel;
uint8_t defaultKey128bits[] = "@McQfTjWnZr4u7x!"; // KEEP SECRET !
uint8_t key128bits[17]; // KEEP SECRET !
uint8_t iv128bits[] = "0124356789ABCDEF"; // NO NEED TO KEEP SECRET
const uint16_t maxMessageSize = 16u * 16u; // message size + 1 needs to be a multiple of 16
char message[maxMessageSize];
static_assert(maxMessageSize % 16 == 0, "message size + 1 needs to be a multiple of 16");
void printHex(uint8_t aByte)
{
if (aByte < 0x10) Serial.write('0');
Serial.print(aByte, HEX);
}
void hexDump(const void* payload, uint16_t payloadSize, bool eightCols = true, bool printASCII = false)
{
for (uint16_t i = 0; i < payloadSize; i++) {
if (printASCII && (isprint((uint8_t) * (((const uint8_t *) payload) + i)))) {
Serial.write('*');
Serial.write((uint8_t) * (((const uint8_t *) payload) + i));
} else printHex((uint8_t) * (((const uint8_t *) payload) + i));
Serial.write(((eightCols && (i + 1) % 8 == 0)) ? '\n' : ' ');
}
Serial.println();
}
void encodePayload(void* payload, uint16_t payloadSize)
{
aes128_cbc_enc(key128bits, iv128bits, payload, payloadSize);
}
void decodePayload(void* payload, uint16_t payloadSize)
{
aes128_cbc_dec(key128bits, iv128bits, payload, payloadSize);
}
void establishDefaults() {
uint32_t check;
EEPROM.get(sentinelAddress, check);
if (check != sentinel) {
Serial.println(F("Memory was not initialized. Setting defaults"));
EEPROM.put(keyAddress, defaultKey128bits);
EEPROM.put(sentinelAddress, sentinel);
}
// now read from EEPROM
EEPROM.get(sentinelAddress, check);
if (check == sentinel) {
EEPROM.get(keyAddress, key128bits);
Serial.println(F("key128bits read from EEPROM"));
} else {
Serial.println(F("EEPROM is deficient. Could not find sentinel"));
}
}
void setup() {
Serial.begin(115200);
Serial.println();
establishDefaults();
Serial.print(F("Key:\t")); hexDump(key128bits, 16, false, true);
Serial.print(F("IV:\t")); hexDump(iv128bits, 16, false, true);
Serial.println();
// reset the buffer to full 0 (just to ensure we have a clean slate)
memset(message, 0, sizeof(message));
// copy payload into the message
strncpy((char*) message, "A Secret Message that willl need to be encoded, including UTF8 chars éàçöê€", maxMessageSize - 1); // -1 to keep a trailing NULL char and thus a cString
// calculate the size of the payload, needs to be a multiple of 16
uint16_t messageSize = strlen(message) + 1; // +1 to grab the trailing '\0'
if ((messageSize % 16) != 0) messageSize = 16 * ((messageSize / 16) + 1);
if (messageSize > maxMessageSize) Serial.println("Message too long.");
else {
Serial.print(F("Message to encode: ["));
Serial.print(message);
Serial.println(F("]\n"));
encodePayload(message, messageSize);
Serial.println(F("Hex dump of coded Message: "));
hexDump(message, messageSize);
decodePayload(message, messageSize);
Serial.print(F("Decoded Message: ["));
Serial.print(message);
Serial.println(F("]\n"));
}
}
void loop() {}