Need help with retrieving array from EEPROM

Hello, I have made a project to send lora packets with encryption. I use the Crypto library with AES128. The library expects a 16 byte key.

Everything works fine if I include my key in the sketch like this:

char encryptionKey[17] = "tEsj8Vg06dm58sF$";

I now need to store any random key on eeprom and everytime I boot my board, I will retrieve it.

I can store the char key inside the EEPROM as an array like this:


        readline(key, 17);  // a function that gets a 16 byte array from serial monitor (like "tEsj8Vg06dm58sF$")

        Serial.print(key);
         for (n = 0; n < 16; n++) {  
            EEPROM.update(n + 90, key[n]);
         }
 
   

At this moment everything works. I then retrieve it with this:

  for (n = 0; n < 16; n++) {   
    key[n] = (char)EEPROM.read(n + 90);
  }
  key[16] = '\0';

Now while i can print it on serial monitor, the library can't use it. It generates a false cypher.
I believe something goes wrong when retrieving the array from eeprom.
Any ideas?

What kind of Arduino or compatible platform are you using?

The easiest way to read or write music data in eeprom is usually to pack everything in a flat structure.

Would be good to see all the code or an example that reads and write from eeprom with your read line code

I'm using arduino mega. My sketch is super big (13k lines) so I'll try to post the specific parts needed.

Instead of specific part try to write a small example code where you can read the line, store and retrieve the data from eeprom. All using your functions

This will be easier to debug and then inject into the real code

Here is a sketch with the parts needing to recreate my problem.

#include <Crypto.h>  
#include <AES.h>

#include <EEPROM.h>

AES128 aes128;
//char key[17];                         
char key[17] = "tEsj8Vg06dm58sF$";  //if you choose this, it makes a different cypher than reading from eeprom with the above blank char
char getPass[17];

char text[20];  //plaintext[16] contain the text we need to encrypt
char cypher[20];

byte n;  
void setup() {

  Serial.begin(115200);
  aes128.setKey(key, 16);  // Setting Key for AES

  restoreSettings();
  
  Serial.print("key: ");
  Serial.println(key);

  memset(text, 0, sizeof(text));
  strcpy(text, "test12345");

  Serial.print(F("Before Encryption: "));
  Serial.println(text);

  aes128.encryptBlock(cypher, text);  //cypher->output block and plaintext->input block

  Serial.print(F("After Encryption: "));
  Serial.println(cypher);


  memset(text, 0, sizeof(text));

  aes128.decryptBlock(text, cypher);



  Serial.print(F("After Dencryption: "));
  Serial.println(text);
}

void loop() {

  Serial.println(F("Insert a 16-byte key and press Enter, or press \"-\" to continue: "));

  readline(getPass, 17, 5000);
  Serial.print(getPass);

  if (strcmp(getPass, "-") == 0) {
    Serial.println(F(" Key didn't stored"));
  } else {

    for (n = 0; n < 16; n++) {  //sizeof(RFcode)
      EEPROM.update(n + 90, getPass[n]);
    }

    Serial.println(F(" Key stored"));
  }


}



uint8_t readline(char *buff, uint8_t maxbuff, uint16_t timeout) {
  uint16_t buffidx = 0;
  boolean timeoutvalid = true;
  if (timeout == 0) timeoutvalid = false;

  while (true) {



    if (buffidx > maxbuff) {
      break;
    }

    while (Serial.available()) {
      char c = Serial.read();

      if (c == '\r') continue;
      if (c == 0xA) {
        if (buffidx == 0)  // the first 0x0A is ignored
          continue;

        timeout = 0;  // the second 0x0A is the end of the line
        timeoutvalid = true;
        break;
      }
      buff[buffidx] = c;
      buffidx++;
    }

    if (timeoutvalid && timeout == 0) {
      break;
    }
    delay(1);
  }
  buff[buffidx] = 0;  // null term
  return buffidx;
}

void restoreSettings() {
  byte n = 0;


  for (n = 0; n < 16; n++) {  //90-105           // Encryption key
    key[n] = (char)EEPROM.read(n + 90);
  }
  key[16] = '\0';
}

I'm using an array within my EEPROM data structure and its a simple put/get to write/retrieve the data.

this looks suspicious to me

key[16] = '\0';

Why is your key 17 bytes long?
Make it 16 and hand over 16bytes to your "library" ... or what ever it needs.

Provide a full compileable example. Link to the library you have included.

The example above works fine, I tested it.

You can get the library from here: GitHub - OperatorFoundation/Crypto: A fork of rweather's arduinolibs Crypto library, a cryptography library for Arduino

my key is 17 bytes because I think it needs a terminating null character.
When I try with 16bytes i get the same results.

That's why I can't understand what's going on.

As for key[16] = '\0'; , I saw someone suggesting this for easy serial printing.

Also, using reading function I get this cypher:

image

If I define it in sketch and not read it from eeprom, I get this result.

image

There are different cyphers, but they Serial.print the same thing.

where do I get that one?

Sorry, my mistake. Here: GitHub - OperatorFoundation/Crypto: A fork of rweather's arduinolibs Crypto library, a cryptography library for Arduino

your code does not store anything in EEPROM, so gets back whatever is there (likely zeros)

Are you sure? I can write in EEPROM succesfully. After a reset i can also read it back.

your demo code does this

and restoreSettings() then goes to modify the key with whatever is in EEPROM

void restoreSettings() {
  byte n = 0;
  for (n = 0; n < 16; n++) {  //90-105           // Encryption key
    key[n] = (char)EEPROM.read(n + 90);
  }
  key[16] = '\0';
}

which changes the key's content

You have to write first with this function.
image

Then reset the board to read it back.
Also uncomment the blank char key[17]; and comment the char key[17] = "tEsj8Vg06dm58sF$";

It works like that.

  1. You start the board first time and put a password
  2. The password is saved in the EEPROM.
  3. You reset the board in order to read the EEPROM and retreive the key
  4. The key gets cyphered with the crypto library

The thing is that if you use the char key[17] = "tEsj8Vg06dm58sF$"; and never read the EEPROM by commenting the restoreSettings, it gives you a different cypher.

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() {}
1 Like

Well, I used your code to make my problem fixed and also I used the encryption library you used. I still don't know what was the problem after all, but maybe the library I was using wanted some specific form of text for key.

Thank's!!!

Some libraries were bogus or cumbersome to use when I was looking for an AES implementation. I found this one to work to my satisfaction despite the padding / size thingy.

Glad it was helpful

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.