rweather / arduinolibs

Arduino Cryptography Library
439 stars 211 forks source link

Combining GCM and CTR mode #48

Open poojitha-sai opened 4 years ago

poojitha-sai commented 4 years ago

Hello,

Is is possible to combine multiple modes of AES encryption? I tried to combine GCM and CTR mode with HMAC in the same program and the program crashed. Please suggest how to implement it.

rweather commented 4 years ago

What kind of Arduino device are you using? If it is a Uno or some other device with a small amount of RAM, then that may account for the crashing.

The more algorithms you include, the greater the data space in RAM required. If it gets too large, the data space will overlap with the stack space at the top of memory and memory corruption will start happening. If you have lots of "..." strings or byte arrays in your codel, then that will increase data space usage too.

I saw this quite a bit when developing the the test programs on Uno, which is why some of them use program memory for the test vectors - I had to get the values out of data space or memory corruption would occur.

Try using an Arduino device with more RAM and see if that helps. If you have lots of RAM already, then there may be some other bug going on in your code that is causing memory corruption.

poojitha-sai commented 4 years ago

I'm using an Arduino UNO. My program does use a lot of strings and byte arrays too. Could you please tell me if there's a way to optimize this and make it work?

rweather commented 4 years ago

Without seeing your code, it is difficult to advise.

I do wonder why you need both GCM and CTR/HMAC mode? GCM is essentially CTR mode combined with GHASH authentication, a form of authenticated encryption. CTR/HMAC is another different form of authenticated encryption.

At a guess you currently have the following classes compiled into your sketch: AES, GHASH, SHA256, GCM, CTR, and HMAC. If you are also using my random number generator, then you also have RNG and ChaCha added to the memory burden.

If your application truly does call for all those algorithms, then you may have to consider upgrading to an Arduino with more memory.

I suggest that you pick just one authenticated encryption mode, either GCM or possibly ChaChaPoly so you can share the ChaCha code with the RNG.

poojitha-sai commented 4 years ago

I'm trying to test security for CAN communication using different modes of AES encryption. Individual modes work fine. But I wanted to see if different modes of encryption can be used for selected messages. Hence, I faced this problem. Below is the code for my CAN receiver:

`#include "CTR.h"

include

include

include

include

include

if defined(ESP8266) || defined(ESP32)

include

else

include <avr/pgmspace.h>

endif

include

include

GCM gcm; CTR ctr; SHA256 hash;

const uint8_t Num_IDs = 6; const uint8_t Num_Clusters = 2; uint8_t Num_Mirr = Num_IDs / Num_Clusters;

uint8_t key[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; uint8_t iv[Num_IDs][16] = {{0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3}, {1, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3}, {2, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3}, {3, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3}, {4, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3}}; uint8_t adata[16];

const int SPI_CS_PIN = 9;

MCP_CAN CAN(SPI_CS_PIN); // Set CS pin

void setup() { Serial.begin(9600);

while (CAN_OK != CAN.begin(CAN_500KBPS)) // init can bus : baudrate = 500k { Serial.println("CAN BUS Shield init fail"); Serial.println(" Init CAN BUS Shield again"); delay(100); } Serial.println("CAN BUS Shield init ok!"); gcm.setKey(key, sizeof(key)); gcm.addAuthData(adata, sizeof(adata)); }

void loop() {

uint8_t plaintext[Num_IDs][8]; uint8_t tag[Num_IDs][8]; uint8_t ciphertext[Num_IDs][16]; bool auth_result[Num_IDs]; uint8_t msgData[Num_IDs][8]; uint8_t msgTag[Num_IDs][8]; unsigned char len = 8; unsigned char buf[8]; static uint8_t recv[Num_IDs]; unsigned int canId; uint8_t RecvDelay[Num_IDs]; bool enable[Num_IDs];

if (CAN_MSGAVAIL == CAN.checkReceive()) // check if data coming { CAN.readMsgBuf(&len, buf); // read data, len: data length, buf: data buf

canId = CAN.getCanId();

/*
    Serial.println("-----------------------------");
    Serial.print("Get data from ID: ");
    Serial.println(canId, HEX);

    for (int i = 0; i < len; i++) // print the data
    {
      Serial.print(buf[i], HEX);
      Serial.print("\t");
    }
    Serial.println();
*/

/*Logic for filtering messages*/

for (int i = 1; i <= Num_Clusters; i++)
{
  for (int y = 1; y <= Num_Mirr; y++)
  {
    int z = 2 * Num_Mirr * (i - 1) + y - 1;
    int x = y + ((i - 1) * Num_Mirr) - 1;
    if (canId == z)
    {

      /*Copy message tag*/
      copy(buf, msgTag[x], 8);
      recv[x] |= 1;

    }
    else if (canId == (z + Num_Mirr))
    {

      /*Copy message data*/
      copy(buf, msgData[x], 8);
      recv[x] |= 2;

    }

    if (recv[x] == 3) //to check if both tag and data are received.
    {
      for (uint8_t j = 0; j < 8; j++)
      {

        ciphertext[x][j] = msgData[x][j];
        tag[x][j] = msgTag[x][j];

      }

      /*GCM decryption for selected messages*/
      if ((x + 1) % 3 == 0) {
        gcm.setKey(key, sizeof(key));
        gcm.setIV(iv[x], sizeof(iv[x]));
        gcm.decrypt(plaintext[x], ciphertext[x], 8);
        Serial.print((String)"plaintext[" + x + "]\n");
        for (int j = 0; j < 8; j++) {
          Serial.print(plaintext[x][j], DEC); //To plot data in MATLAB Simulink
          Serial.println("");
        }

        auth_result[x] = gcm.checkTag(tag[x], 8);

        if (auth_result[x] == 1)
        {
          Serial.println((String)"Message " + x + " authenticated");

        }

      }

      /*CTR decryption*/
      else {

        ctr.setKey(key, 16);
        ctr.setIV(iv[x], 16);

        ctr.decrypt(plaintext[x], ciphertext[x], 8);
        Serial.print((String)"Plaintext[" + x + "]\n");
        for (int j = 0; j < 8; j++) {
          Serial.print(plaintext[x][j]);
          Serial.println("");
        }

        hash.resetHMAC(key, sizeof(key));
        hash.update(ciphertext[x], 8);
        hash.finalizeHMAC(key, sizeof(key), tag[x], 8);
        for (int j = 0; j < 8; j++) {
          if (tag[x][j] == msgTag[x][j])
          {
            auth_result[x] |= 1;
          }
          else
          {
            auth_result[x] &= 0;
          }

        }

        if (auth_result[x] == 1)
        {
          Serial.println((String)"Message " + x + " authenticated");

        }
        recv[x] = 0;
      }
    }

  }
}

}

/Dyn switching ends/

}

void copy(uint8_t src, uint8_t dst, uint8_t len) { memcpy(dst, src, sizeof(src[0])*len); }`