AES Encryption / Decryption

Hello!

I am using my arduino UNO to generate location data. This will be transferred to my raspberry PI but this data needs to be send encrypted.

I already managed to encrypt my data, by using the AESLib.h library. But how do I know what my IV is?
This is needed to decrypt the data later on in my webserver. I do not have any experience at all in using arduino etc. so any help would be very helpful! (in the example the GPS is not used yet, but just a distance sensor).

#include "AESLib.h" //biblotheek import

#define BAUD 9600

char ID[] = "HY08V21234567865"; //ID of container

AESLib aesLib;

#define INPUT_BUFFER_LIMIT (128+1) // designed for Arduino UNO, not stress-tested anymore (this works with readBuffer[129])
#define trigPin 8 
#define echoPin 10

long duration;
float longitude;
float latitude;

unsigned char cleartext[INPUT_BUFFER_LIMIT] = {0}; // THIS IS INPUT BUFFER (FOR TEXT)
unsigned char ciphertext[2*INPUT_BUFFER_LIMIT] = {0}; // THIS IS OUTPUT BUFFER (FOR BASE64-ENCODED ENCRYPTED DATA)
unsigned char readBuffer [18] = {0}; //Waarde 0 er achter gezet omdat het nog toegekend moet worden. 

// AES Encryption Key (same as in node-js example)
byte aes_key[] = {  57, 36, 24, 25, 28, 86, 32, 41, 31, 36, 91, 36, 51, 74, 63, 89 };

// General initialization vector (same as in node-js example) (you must use your own IV's in production for full security!!!)
byte aes_iv[16] = { 0x79, 0x4E, 0x98, 0x21, 0xAE, 0xD8, 0xA6, 0xAA, 0xD7, 0x97, 0x44, 0x14, 0xAB, 0xDD, 0x9F, 0x2C };

// Generate IV (once)
void aes_init() {
  aesLib.gen_iv(aes_iv);
  aesLib.set_paddingmode((paddingMode)0);
}

uint16_t encrypt_to_ciphertext(char * msg, uint16_t msgLen, byte iv[]) {
  Serial.println("Calling encrypt (string)...");
  // aesLib.get_cipher64_length(msgLen);
  int cipherlength = aesLib.encrypt((byte*)msg, msgLen, (char*)ciphertext, aes_key, sizeof(aes_key), iv);
                   // uint16_t encrypt(byte input[], uint16_t input_length, char * output, byte key[],int bits, byte my_iv[]);
  return cipherlength;
}

uint16_t decrypt_to_cleartext(byte msg[], uint16_t msgLen, byte iv[]) {
  Serial.print("Calling decrypt...; ");
  uint16_t dec_bytes = aesLib.decrypt(msg, msgLen, (char*)cleartext, aes_key, sizeof(aes_key), iv);
  Serial.print("Decrypted bytes: "); Serial.println(dec_bytes);
  return dec_bytes;
}

void setup() {
   // Define inputs and outputs:
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  Serial.begin(BAUD);
  Serial.setTimeout(60000);
  delay(2000);

  aes_init(); // generate random IV, should be called only once? causes crash if repeated...

}

/* non-blocking wait function */
void wait(unsigned long milliseconds) {
  unsigned long timeout = millis() + milliseconds;
  while (millis() < timeout) {
    yield();
  }
}

unsigned long loopcount = 0;

// Working IV buffer: Will be updated after encryption to follow up on next block.
// But we don't want/need that in this test, so we'll copy this over with enc_iv_to/enc_iv_from
// in each loop to keep the test at IV iteration 1. We could go further, but we'll get back to that later when needed.

// General initialization vector (same as in node-js example) (you must use your own IV's in production for full security!!!)
byte enc_iv[16] =      { 0x79, 0x4E, 0x98, 0x21, 0xAE, 0xD8, 0xA6, 0xAA, 0xD7, 0x97, 0x44, 0x14, 0xAB, 0xDD, 0x9F, 0x2C };
byte enc_iv_to[16]   = { 0x79, 0x4E, 0x98, 0x21, 0xAE, 0xD8, 0xA6, 0xAA, 0xD7, 0x97, 0x44, 0x14, 0xAB, 0xDD, 0x9F, 0x2C };
byte enc_iv_from[16] = { 0x79, 0x4E, 0x98, 0x21, 0xAE, 0xD8, 0xA6, 0xAA, 0xD7, 0x97, 0x44, 0x14, 0xAB, 0xDD, 0x9F, 0x2C };

void loop() {
   // Clear the trigPin by setting it LOW:
  digitalWrite(trigPin, LOW);
  delayMicroseconds(5);
  // Trigger the sensor by setting the trigPin high for 10 microseconds:
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  // Read the echoPin, pulseIn() returns the duration (length of the pulse) in microseconds:
  duration = pulseIn(echoPin, HIGH);
  // Calculate the distance:
  longitude = (duration * 0.034 / 2)+40.365491;
  latitude = (duration * 0.034 / 2)+ 50.3654;
  Serial.println((longitude),6);
  dtostrf(longitude, 3, 6, readBuffer); //6 is number after decimal, daarvoor is aantal daarvor inclusief de punt


  
  //Serial.print("readBuffer length: "); Serial.println(sizeof(readBuffer)); wel weer activeren!

   // must not exceed INPUT_BUFFER_LIMIT bytes; may contain a newline
  sprintf((char*)cleartext, "%s", readBuffer);

  // Encrypt
  // iv_block gets written to, provide own fresh copy... so each iteration of encryption will be the same.
  uint16_t msgLen = sizeof(readBuffer);
  memcpy(enc_iv, enc_iv_to, sizeof(enc_iv_to));
  uint16_t encLen = encrypt_to_ciphertext((char*)cleartext, msgLen, enc_iv);
  //Serial.print("Encrypted length = "); Serial.println(encLen); NOG WEL WEER AANZETTEN
  Serial.println((char*)ciphertext); //Nu laat hij de ciphertekst zien!! Dit is wat je naar Raspberry PI stuurt


  Serial.println("Encrypted. Decrypting..."); //Serial.println(encLen ); Serial.flush();
  memcpy(enc_iv, enc_iv_from, sizeof(enc_iv_from));
  uint16_t decLen = decrypt_to_cleartext(ciphertext, encLen , enc_iv);
  //Serial.print("Decrypted cleartext of length: "); Serial.println(decLen);
  Serial.print("Decrypted cleartext:\n"); Serial.println((char*)cleartext);

  if (strcmp((char*)readBuffer, (char*)cleartext) == 0) {
    Serial.println("Decrypted correctly.");
  } else {
    Serial.println("Decryption test failed.");
  }

  Serial.println("---");
  delay(8000);

}

An initialization vector (or IV ) is used to ensure that the same value encrypted multiple times, even with the same secret key, will not always result in the same encrypted value.

--> You can pick what you want for your IV (there might be constraints depending on the AES library you use. Seems here you need 16 bytes)

Thank you for your very fast and clear reply! Made a lot clear for me already.

Sorry for another question, I am very new in this field.

If I want someone else to decrypt my encrypted text. Does he / she need to same AES Key and IV?

Yes if you are using CBC, whoever is decoding needs to know both the key and the IV

which library did you pick? (can you share a link as there are many options?)

I found this code: thinx-aes-lib/simple.ino at master · suculent/thinx-aes-lib · GitHub

Makes use of the AESLib.h library

1 Like

OK that should work.

you'll notice the decrypt function requires both the KEY and the IV

aesLib.decrypt(msg, msgLen, (char*)cleartext, aes_key, sizeof(aes_key), iv);

Note that the IV is messed up through encryption so if you want to write a small test with encrypt/decrypt on the same ESP, when you want to decrypt you need to re-initialize the IV to what it was to start with.

memcpy() will be useful to copy the IV in one go

Thank you!! You helped me a lot.

have fun

This is where as asymmetric cryptography come into play. You used it once to create an encrypted channel (using public key cryptography) to exchange symmetric AES key and IV.

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