Search code examples
aes-gcmesp32mbedtls

AES128-GCM using mbedtls on ESP32 decryption not working


I am currently working on a project to decrypt a stream of bytes coming from a smart meter using a ESP32 with the ESP-IDF toolchain. (Smart meter specification here for those interested: P1PortSpecification.pdf , chapter 2.6 page 9).

I am using a state machine to split the stream into the different parts as found in the documentation and when printing them to the terminal I get the results as expected, so I consider the input currently to be correct.

Getting to the final state of decrypting the payload I am unsure if I am using the mbedtls library right, as I can't get it to work properly. The encryption used is AES128-GCM, therefore I am using gcm.h. Here is my current function:

int decrypt_next_telegram(unsigned char *output) {
    //Run the state machine, and get pointers to the IV, cipher and length, GCM tag
    Encrypted_Data ed = get_next_telegram(); 

    //Key specific to my smart meter I use for testing purposes and the Auth data
    const unsigned char key[] = {0xD4, 0x91, 0x47, 0x0F, 0x47, 0x12, 0x63,
            0x32, 0xB0, 0x7D, 0x19, 0x23, 0xB3, 0x50, 0x41, 0x88};
    const unsigned char aad[] = {0x30, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
            0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}

    mbedtls_gcm_context ctx;
    mbedtls_gcm_init(&ctx);
    int err1 = mbedtls_gcm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key, 128);
    int err2 = mbedtls_gcm_auth_decrypt(&ctx, ed.payload_length, ed.initial_value, 12, aad, 17, ed.gcm_tag, 12, ed.payload, output);
    mbedtls_gcm_free(&ctx);
    return err1 + err2;
}

To give you the additional detail of what Encrypted_Data looks like:

typedef struct Encrypted_Data Encrypted_Data;

struct Encrypted_Data {
        unsigned char * initial_value;
        unsigned char * payload;
        unsigned int payload_length;
        unsigned char * gcm_tag;
};

When printing both errors to the terminal I see err1 = 0 and err2 = -0x0012, which is:

#define MBEDTLS_ERR_GCM_AUTH_FAILED -0x0012 /**< Authenticated decryption failed. */

So I digged into the gcm.c file and noticed there is only 1 spot where that define is used (here), however something else caught my attention. I doubt it is a mistake but I can't really understand the reasoning behind this part in

int mbedtls_gcm_setkey( mbedtls_gcm_context *ctx,
                    mbedtls_cipher_id_t cipher,
                    const unsigned char *key,
                    unsigned int keybits )
{
    int ret;
    const mbedtls_cipher_info_t *cipher_info;

    cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, MBEDTLS_MODE_ECB );
    ... 
}

found here. Why does it use that mode? If I am looking into the contents of cipher_info it tells me it is using MBEDTLS_CIPHER_AES_128_ECB as mbedtls_cipher_type_t, instead of what I would have expected at first MBEDTLS_CIPHER_AES_128_GCM. Is this a problem?

To sum up my main questions:

  • Is this unexpected mbedtls_cipher_type_t a problem?
  • Am I using the mbedtls functions correctly?
  • Open for suggestions to track down the problem, as I am still unexperienced with this platform.

Thanks for reading.


Solution

  • Well, I found the solution to my personal problem. I used pre-recorded telegrams, which I sent over USB to the UART pin. Unfortunately the USB controller of my PC is messing up a bit here and there.

    Hard coding the telegram into the code works perfectly well...