nRF9160: AES-128 CBC decryption does not work with MbedTLS (but encryption does work)

I am trying to get AES-128 CBC decryption to work on the nRF9160 using the MbedTLS library in my bare metal application. I am linking with the following libraries found in sdk-nrfxlib-2.2.0 in their cortex-m33, hard-float, no-interrupts versions:

libnrf_cc310_platform_0.9.16.a

libnrf_cc310_core_0.9.16.a

libnrf_cc310_legacy_crypto_0.9.16.a

I am executing the crypto-related code in secure mode.

After initializing an AES context, and setting the 128-bit key for the context, I am calling mbedtls_aes_crypt_cbc to encrypt and decrypt data, using a 128-bit initialization vector.

So, while encryption (with the mode parameter set to MBEDTLS_AES_ENCRYPT) works just fine, as long as the length is a multiple of the blocksize (16 bytes), decryption using the same function, but with mode set to MBEDTLS_AES_DECRYPT does not. It always returns error -34 (-0x022) which is the error code for MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH, even when the length is actually a multiple of 16 bytes. Only when the length is 0, it returns 0 (no error) - but then it does not decrypt anything, of course.

So, is there a bug in the AES-128 CBC decryption algorithm in the CC310 version of MbedTLS or am I missing something?

By the way, I have also tested SHA-256 digest and ECDSA secp256r1 sign and verify. The SHA-256 algorithm seems to produce wrong results when updating with more than 64 bytes at a time (why?). ECDSA seems to work just fine, but the functions for manipulating big numbers (mpi) are not compiled into any of the libraries listed above, which is irritating, since I then have to manually compile and link with individual .c files from the MbedTLS library.

Thanks in advance :-)

Parents
  • Hello,

    When Aes-CBC buffer encryption/decryptions is length of a multiple of the block size it should not show the error code for  MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH. Can you please send the error log and a code snippet from encryption part? I have asked team also if there is any bug in the algorithm? 

    Thanks.

    BR

    Kazi

  • Thanks, Kazi :-)

    I have made a test program that shows the error (see below). The output of the program is shown here:

    Hello world!
    
    Original text (445 bytes):
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    
    nrf_cc3xx_platform_init returned 0
    mbedtls_aes_setkey_enc returned 0
    
    Encrypting 448 bytes (28 blocks) of data
    mbedtls_aes_crypt_cbc returned 0
    Encrypted data:
    bd351e9b9a818b07178b678ff435d46339da9f0d361d6401a3f26e8cedf970297acffbbefef2eff79495fc62a9e33dbaacb6f6c1ae07c96e62b52b3d9e002fbaadcb27a0724c1c5260af0abd63ecf18c1580726e9f7d74fd7c14c9901c2ecaf0d1557b197f946d17db1de5309fb634f50a7ee2806eaf7e07515732f0b89d3673a42e63b6930d0cf0c32af0ad30c03e8dc670a183fbaf8cdff324a9d00fbf60fcd607209fba69ecf460dfafb0b95972b3ecf385d612edc8f0fd604385e4d8976a3e99dc9c94543e71a7e98ef1f57677db8e0d602a27886f406676d867093c0a427c5a42dd8fb0af66ea7aa18fe5348ffa16aa35b69bdd69005b2aa5f30c950ebf586084e377131d29c81ee47fe8021f5d98a4d7df43d2272c57506dea02728d7d02288cab17efd75a0b8c52e6edb9e893d4102508800e0e9f638fe6b8c486ff05c8caefe5c817e9f711ce708ea899809684302a5060ef497e927287411c605470a1bc94344c992125670e1749ceafeb05b7a4c4b57c744c21392cf0b4491b651af71f0fcb8327d3d15e0acc166e9dc0e5eeea014482b6e5101d68cb200e6e9688c8320f18faee6377e1c49d5063b305bc24cdb56a99eec4fdce9ec0f86da3ac6f
    
    
    Decrypting 448 bytes (28 blocks) of data
    mbedtls_aes_crypt_cbc returned -34
    Decrypted data:
    00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

    Here is the source code for the main.c file that produces the output. The decryption takes place at line 139:

    #include "nrfx.h"
    
    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdarg.h>
    
    #define MBEDTLS_CONFIG_FILE <nrf-config-cc310.h>
    #include <nrf_cc3xx_platform.h>
    #include <mbedtls/platform.h>
    #include <mbedtls/aes.h>
    
    // Initialize UARTE0 for the virtual COM port on the nRF9160 DK
    void uarte0_init()
    {
        // The primary virtual COM port on nRF9160 DK is using the following pins:
        // P0.26 CTS, P0.27 RTS, P0.28 RXD and P0.29 TXD
        
        // Configure the GPIOs
        NRF_P0_S->DIRCLR = (1<<28) | (1<<26); // Set RXD and CTS pins as inputs
        NRF_P0_S->DIRSET = (1<<29) | (1<<27); // Set TXD and RTS pins as outputs
        NRF_P0_S->OUTSET = (1<<29) | (1<<29); // Set TXD and RTS pins high
    
        
        // Route the UARTE0 pins to the above GPIOs
        NRF_UARTE0_S->PSEL.CTS = 26;
        NRF_UARTE0_S->PSEL.RTS = 27;
        NRF_UARTE0_S->PSEL.RXD = 28;
        NRF_UARTE0_S->PSEL.TXD = 29;
        
        // Configure the UART with no hardware flow control, no parity bit, one
        // stop bit and a baud rate of 115200.
        NRF_UARTE0_S->CONFIG = 0;
        NRF_UARTE0_S->BAUDRATE = 0x01D60000ul;
    
        // Enable the UART
        NRF_UARTE0_S->ENABLE = UARTE_ENABLE_ENABLE_Enabled 
            << UARTE_ENABLE_ENABLE_Pos;
    }
    
    // Quick and dirty function that transmits formatted string through UARTE0
    void uarte0_printf(const char* str, ...)
    {
        static char data[1024];
        
        va_list args;
        va_start (args, str);
        vsprintf (data, str, args);
        va_end (args);
        
        // Set up DMA parameters
        NRF_UARTE0_S->TXD.MAXCNT = (uint32_t)strlen(data);
        NRF_UARTE0_S->TXD.PTR = (uint32_t)data;
        
        // Transmit the string
        NRF_UARTE0_S->TASKS_STARTTX = 1;      // Start the transmission
        while (! NRF_UARTE0_S->EVENTS_ENDTX); // Wait for transmission to finish
        NRF_UARTE0_S->EVENTS_ENDTX = 0;       // Clear the ENDTX event
    }
    
    int main()
    {
        // Use the HFXO as the high frequency clock
        NRF_CLOCK_S->TASKS_HFCLKSTART = 1;
        while (! NRF_CLOCK_S->EVENTS_HFCLKSTARTED); // Wait for the clock to start
        NRF_CLOCK_S->EVENTS_HFCLKSTARTED = 0;
    
        // Initialize UARTE0 and transmit a test message!
        uarte0_init();
        uarte0_printf("Hello world!\r\n\r\n");
        
        // Initialize key and initialization vector
        const uint8_t key[] = { 0x40, 0x4E, 0x63, 0x52, 0x66, 0x55, 0x6A, 0x58, 
                                0x6E, 0x32, 0x72, 0x35, 0x75, 0x38, 0x78, 0x21 };    
        
        const uint8_t iv[] = { 0x5A, 0x71, 0x34, 0x74, 0x37, 0x77, 0x21, 0x7A,
                               0x25, 0x43, 0x2A, 0x46, 0x2D, 0x4A, 0x61, 0x4E };
           
        // Initialize input and output buffers
        uint8_t input[1024];
        uint8_t output[1024];
        memset(input, 0, 1024);
        memset(output, 0, 1024);
       
        // Define the text to encrypt
        const char* txt = "Lorem ipsum dolor sit amet, consectetur adipiscing "
                          "elit, sed do eiusmod tempor incididunt ut labore et "
                          "dolore magna aliqua. Ut enim ad minim veniam, quis "
                          "nostrud exercitation ullamco laboris nisi ut aliquip "
                          "ex ea commodo consequat. Duis aute irure dolor in "
                          "reprehenderit in voluptate velit esse cillum dolore eu "
                          "fugiat nulla pariatur. Excepteur sint occaecat "
                          "cupidatat non proident, sunt in culpa qui officia "
                          "deserunt mollit anim id est laborum.";
        
        // Copy the text to the input buffer
        sprintf((char*)input, "%s", txt);
        
        // Compute length in blocks of 16 bytes
        size_t len = strlen(txt);
        size_t len_orig = len;
        if (len % 16)
            len = (len/16 + 1)*16;
        
        uarte0_printf("Original text (%u bytes):\r\n%s\r\n\r\n", len_orig, txt);    
    
        // Initialize CC3XX platform
        int ret = nrf_cc3xx_platform_init();
        uarte0_printf("nrf_cc3xx_platform_init returned %i\r\n", ret);
        if (ret != 0)
            return -1;
        
        // Create AES context and initialize it with the key
        mbedtls_aes_context aes = {0};
        mbedtls_aes_init(&aes);
        ret = mbedtls_aes_setkey_enc(&aes, key, 128);    
        uarte0_printf("mbedtls_aes_setkey_enc returned %i\r\n", ret);
        
        // Encrypt the data (we make a copy of the IV first)
        uint8_t iv_copy[16];
        memcpy(iv_copy, iv, 16);
        uarte0_printf("\r\nEncrypting %u bytes (%u blocks) of data\r\n", len, 
            len/16);
        ret = mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, iv_copy, input, 
            output);
        uarte0_printf("mbedtls_aes_crypt_cbc returned %i\r\n", ret);
        
        // Print the encrypted data
        uarte0_printf("Encrypted data:\r\n");
        for (size_t i = 0; i < len; ++i)
            uarte0_printf("%02x", (unsigned int)(output[i]));
        uarte0_printf("\r\n\r\n");
        
        // Decrypt the data (we clear the input and uses that as output)
        memset(input, 0, 1024);
        memcpy(iv_copy, iv, 16);
        uarte0_printf("\r\nDecrypting %u bytes (%u blocks) of data\r\n", len, 
            len/16);
        ret = mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, len, iv_copy, output,
            input);
        uarte0_printf("mbedtls_aes_crypt_cbc returned %i\r\n", ret);
        
        // Print the decrypted data
        uarte0_printf("Decrypted data:\r\n");
        for (size_t i = 0; i < len_orig; ++i)
            uarte0_printf("%02x", (unsigned int)(input[i]));
        uarte0_printf("\r\n\r\n");
        
        // We can now free the context
        mbedtls_aes_free(&aes);
    
        // Main loop
        while (1)
        {
        
        }
    }
    

Reply
  • Thanks, Kazi :-)

    I have made a test program that shows the error (see below). The output of the program is shown here:

    Hello world!
    
    Original text (445 bytes):
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    
    nrf_cc3xx_platform_init returned 0
    mbedtls_aes_setkey_enc returned 0
    
    Encrypting 448 bytes (28 blocks) of data
    mbedtls_aes_crypt_cbc returned 0
    Encrypted data:
    bd351e9b9a818b07178b678ff435d46339da9f0d361d6401a3f26e8cedf970297acffbbefef2eff79495fc62a9e33dbaacb6f6c1ae07c96e62b52b3d9e002fbaadcb27a0724c1c5260af0abd63ecf18c1580726e9f7d74fd7c14c9901c2ecaf0d1557b197f946d17db1de5309fb634f50a7ee2806eaf7e07515732f0b89d3673a42e63b6930d0cf0c32af0ad30c03e8dc670a183fbaf8cdff324a9d00fbf60fcd607209fba69ecf460dfafb0b95972b3ecf385d612edc8f0fd604385e4d8976a3e99dc9c94543e71a7e98ef1f57677db8e0d602a27886f406676d867093c0a427c5a42dd8fb0af66ea7aa18fe5348ffa16aa35b69bdd69005b2aa5f30c950ebf586084e377131d29c81ee47fe8021f5d98a4d7df43d2272c57506dea02728d7d02288cab17efd75a0b8c52e6edb9e893d4102508800e0e9f638fe6b8c486ff05c8caefe5c817e9f711ce708ea899809684302a5060ef497e927287411c605470a1bc94344c992125670e1749ceafeb05b7a4c4b57c744c21392cf0b4491b651af71f0fcb8327d3d15e0acc166e9dc0e5eeea014482b6e5101d68cb200e6e9688c8320f18faee6377e1c49d5063b305bc24cdb56a99eec4fdce9ec0f86da3ac6f
    
    
    Decrypting 448 bytes (28 blocks) of data
    mbedtls_aes_crypt_cbc returned -34
    Decrypted data:
    00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

    Here is the source code for the main.c file that produces the output. The decryption takes place at line 139:

    #include "nrfx.h"
    
    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdarg.h>
    
    #define MBEDTLS_CONFIG_FILE <nrf-config-cc310.h>
    #include <nrf_cc3xx_platform.h>
    #include <mbedtls/platform.h>
    #include <mbedtls/aes.h>
    
    // Initialize UARTE0 for the virtual COM port on the nRF9160 DK
    void uarte0_init()
    {
        // The primary virtual COM port on nRF9160 DK is using the following pins:
        // P0.26 CTS, P0.27 RTS, P0.28 RXD and P0.29 TXD
        
        // Configure the GPIOs
        NRF_P0_S->DIRCLR = (1<<28) | (1<<26); // Set RXD and CTS pins as inputs
        NRF_P0_S->DIRSET = (1<<29) | (1<<27); // Set TXD and RTS pins as outputs
        NRF_P0_S->OUTSET = (1<<29) | (1<<29); // Set TXD and RTS pins high
    
        
        // Route the UARTE0 pins to the above GPIOs
        NRF_UARTE0_S->PSEL.CTS = 26;
        NRF_UARTE0_S->PSEL.RTS = 27;
        NRF_UARTE0_S->PSEL.RXD = 28;
        NRF_UARTE0_S->PSEL.TXD = 29;
        
        // Configure the UART with no hardware flow control, no parity bit, one
        // stop bit and a baud rate of 115200.
        NRF_UARTE0_S->CONFIG = 0;
        NRF_UARTE0_S->BAUDRATE = 0x01D60000ul;
    
        // Enable the UART
        NRF_UARTE0_S->ENABLE = UARTE_ENABLE_ENABLE_Enabled 
            << UARTE_ENABLE_ENABLE_Pos;
    }
    
    // Quick and dirty function that transmits formatted string through UARTE0
    void uarte0_printf(const char* str, ...)
    {
        static char data[1024];
        
        va_list args;
        va_start (args, str);
        vsprintf (data, str, args);
        va_end (args);
        
        // Set up DMA parameters
        NRF_UARTE0_S->TXD.MAXCNT = (uint32_t)strlen(data);
        NRF_UARTE0_S->TXD.PTR = (uint32_t)data;
        
        // Transmit the string
        NRF_UARTE0_S->TASKS_STARTTX = 1;      // Start the transmission
        while (! NRF_UARTE0_S->EVENTS_ENDTX); // Wait for transmission to finish
        NRF_UARTE0_S->EVENTS_ENDTX = 0;       // Clear the ENDTX event
    }
    
    int main()
    {
        // Use the HFXO as the high frequency clock
        NRF_CLOCK_S->TASKS_HFCLKSTART = 1;
        while (! NRF_CLOCK_S->EVENTS_HFCLKSTARTED); // Wait for the clock to start
        NRF_CLOCK_S->EVENTS_HFCLKSTARTED = 0;
    
        // Initialize UARTE0 and transmit a test message!
        uarte0_init();
        uarte0_printf("Hello world!\r\n\r\n");
        
        // Initialize key and initialization vector
        const uint8_t key[] = { 0x40, 0x4E, 0x63, 0x52, 0x66, 0x55, 0x6A, 0x58, 
                                0x6E, 0x32, 0x72, 0x35, 0x75, 0x38, 0x78, 0x21 };    
        
        const uint8_t iv[] = { 0x5A, 0x71, 0x34, 0x74, 0x37, 0x77, 0x21, 0x7A,
                               0x25, 0x43, 0x2A, 0x46, 0x2D, 0x4A, 0x61, 0x4E };
           
        // Initialize input and output buffers
        uint8_t input[1024];
        uint8_t output[1024];
        memset(input, 0, 1024);
        memset(output, 0, 1024);
       
        // Define the text to encrypt
        const char* txt = "Lorem ipsum dolor sit amet, consectetur adipiscing "
                          "elit, sed do eiusmod tempor incididunt ut labore et "
                          "dolore magna aliqua. Ut enim ad minim veniam, quis "
                          "nostrud exercitation ullamco laboris nisi ut aliquip "
                          "ex ea commodo consequat. Duis aute irure dolor in "
                          "reprehenderit in voluptate velit esse cillum dolore eu "
                          "fugiat nulla pariatur. Excepteur sint occaecat "
                          "cupidatat non proident, sunt in culpa qui officia "
                          "deserunt mollit anim id est laborum.";
        
        // Copy the text to the input buffer
        sprintf((char*)input, "%s", txt);
        
        // Compute length in blocks of 16 bytes
        size_t len = strlen(txt);
        size_t len_orig = len;
        if (len % 16)
            len = (len/16 + 1)*16;
        
        uarte0_printf("Original text (%u bytes):\r\n%s\r\n\r\n", len_orig, txt);    
    
        // Initialize CC3XX platform
        int ret = nrf_cc3xx_platform_init();
        uarte0_printf("nrf_cc3xx_platform_init returned %i\r\n", ret);
        if (ret != 0)
            return -1;
        
        // Create AES context and initialize it with the key
        mbedtls_aes_context aes = {0};
        mbedtls_aes_init(&aes);
        ret = mbedtls_aes_setkey_enc(&aes, key, 128);    
        uarte0_printf("mbedtls_aes_setkey_enc returned %i\r\n", ret);
        
        // Encrypt the data (we make a copy of the IV first)
        uint8_t iv_copy[16];
        memcpy(iv_copy, iv, 16);
        uarte0_printf("\r\nEncrypting %u bytes (%u blocks) of data\r\n", len, 
            len/16);
        ret = mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, iv_copy, input, 
            output);
        uarte0_printf("mbedtls_aes_crypt_cbc returned %i\r\n", ret);
        
        // Print the encrypted data
        uarte0_printf("Encrypted data:\r\n");
        for (size_t i = 0; i < len; ++i)
            uarte0_printf("%02x", (unsigned int)(output[i]));
        uarte0_printf("\r\n\r\n");
        
        // Decrypt the data (we clear the input and uses that as output)
        memset(input, 0, 1024);
        memcpy(iv_copy, iv, 16);
        uarte0_printf("\r\nDecrypting %u bytes (%u blocks) of data\r\n", len, 
            len/16);
        ret = mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, len, iv_copy, output,
            input);
        uarte0_printf("mbedtls_aes_crypt_cbc returned %i\r\n", ret);
        
        // Print the decrypted data
        uarte0_printf("Decrypted data:\r\n");
        for (size_t i = 0; i < len_orig; ++i)
            uarte0_printf("%02x", (unsigned int)(input[i]));
        uarte0_printf("\r\n\r\n");
        
        // We can now free the context
        mbedtls_aes_free(&aes);
    
        // Main loop
        while (1)
        {
        
        }
    }
    

Children
No Data
Related