cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 and crypto question

davhak
Associate II
Posted on October 14, 2016 at 00:41

Dear All,

I successfully could integrate the AES GCM algorithms (firmware variant, no hardware acceleration) of STM32 cryptographic library v2.0.6 into the project. It encrypts and decrypts the plaintext correctly without any error.

Simultaneously, there is another crypto project in the PC side using the Crypto++ library with the same AES GCM encrypt/decrypt parts. Here, too, everything works.

However, the problem is that when using the same AES256 key, IV array (size 12), plaintext, header (AAD), the STM32F4 and the PC generates different ciphers and tags. Their lengths are the same across the platforms but the content is totally different.

So it becomes impossible to encrypt in PC and try to decrypt the cipher in STM32F4. I have tried to supply the cipher and the tag generated in STM32F4 to the PC decrypted but it breaks with the error:

Caught HashVerificationFailed...

 

HashVerificationFilter: message hash or MAC not valid

 

So my question what might be the problem that they generate different ciphers?

Thanks a lot for any suggestion.

#!stm32 #help-thyself
13 REPLIES 13
mark239955_stm1
Associate II
Posted on October 14, 2016 at 05:31

My first suspect would be mismatched byte ordering between the PC and MCU.

davhak
Associate II
Posted on October 14, 2016 at 08:07

Both STM32F4 and the Crypto++ libraries are compiled to be little endian.

Or is there another way for byte ordering?

Thanks again for the help.

davhak
Associate II
Posted on October 14, 2016 at 09:38

The relevant parts of the codes are as follows:

*** STM32F4 part ***

    AESGCMctx_stt GCMctx_st;

    int32_t retval, outSize, outSize2;

    uint8_t key[CRL_AES256_KEY]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,

                                                                      0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15

                                                                     };

    uint8_t iv[12]={0,1,2,3,4,5,6,7,8,9,10,11};

    uint8_t plaintext[7]={0x01, 0x02, 0x03, 0x04, 0xFA, 0xCC, 0xB7};

    uint8_t header[13]={12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};

    uint8_t tag[16];

    uint8_t ciphertext[1024];

    GCMctx_st.mFlags = E_SK_DEFAULT;

    GCMctx_st.mTagSize = 16;

    GCMctx_st.mIvSize=12;

    GCMctx_st.mKeySize=CRL_AES256_KEY;

    retval = AES_GCM_Encrypt_Init(&GCMctx_st, key, iv);

    retval = AES_GCM_Header_Append(&GCMctx_st, header, sizeof(header));

    retval = AES_GCM_Encrypt_Append(&GCMctx_st, plaintext, 7, ciphertext, &outSize);

    retval =  AES_GCM_Encrypt_Finish(&GCMctx_st, tag, &outSize2);

    // OK, lets now decrypt the cipher

    GCMctx_st.mFlags = E_SK_DONT_PERFORM_KEY_SCHEDULE;

    GCMctx_st.pmTag = tag;

    retval = AES_GCM_Decrypt_Init(&GCMctx_st, key, iv);

    retval |= AES_GCM_Header_Append(&GCMctx_st, header, sizeof(header));

    retval |= AES_GCM_Decrypt_Append(&GCMctx_st, ciphertext, outSize, plaintext, &outSize);

    retval = AES_GCM_Decrypt_Finish(&GCMctx_st, NULL, &outSize);

    if ( retval == AUTHENTICATION_SUCCESSFUL )

      {return 1;} //printf(''Decryption/Authentication OK!'');

    else

      {return 0;} //printf(''ERROR!'');

*******************

*** PC Crypto++ part ***

    uint8_t key[32]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,

                                   0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};

    uint8_t iv[12]={0,1,2,3,4,5,6,7,8,9,10,11};

    uint8_t plaintext[7]={0x01, 0x02, 0x03, 0x04, 0xFA, 0xCC, 0xB7};

    uint8_t header[13]={12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};

    uint8_t tag[16];

    const int TAG_SIZE = sizeof(tag);

    string cipher;

    try

    {

        GCM< AES >::Encryption e;

        e.SetKeyWithIV( key, sizeof(key), iv, sizeof(iv) );

        AuthenticatedEncryptionFilter ef( e,

            new StringSink( cipher ), false, TAG_SIZE

        ); // AuthenticatedEncryptionFilter

        ef.ChannelPut( ''AAD'', (const byte*)header, sizeof(header) );

        ef.ChannelMessageEnd(''AAD'');

        ef.ChannelPut( '''', (const byte*)plaintext, sizeof(plaintext) );

        ef.ChannelMessageEnd('''');

    }

    catch (...) {}

    // OK, lets not decrypt

    try

    {

        GCM< AES >::Decryption d;

        d.SetKeyWithIV( key, sizeof(key), iv, sizeof(iv) );

       string enc = cipher.substr( 0, cipher.length()-TAG_SIZE );

       string mac = cipher.substr( cipher.length()-TAG_SIZE);

        AuthenticatedDecryptionFilter df( d, NULL,

            AuthenticatedDecryptionFilter::MAC_AT_BEGIN |

            AuthenticatedDecryptionFilter::THROW_EXCEPTION, TAG_SIZE );

        // The order of the following calls are important

        df.ChannelPut( '''', (const byte*)mac.data(), mac.size() );

        df.ChannelPut( ''AAD'', (const byte*)header, sizeof(header) );

        df.ChannelPut( '''', (const byte*)enc.data(), enc.size() );

        df.ChannelMessageEnd( ''AAD'' );

        df.ChannelMessageEnd( '''' );

        // and so on...

    }

    catch (...) {}

*********************

So the cipher and the tag fields after the encryption of  both libraries are different.

Probably I am missing something simple...

Thanks again for any help.

davhak
Associate II
Posted on October 15, 2016 at 21:23

Some more information.

To check whether it is STM32F4 that makes a ''wrong'' encryption or the PC, I compiled another crypto library i.e. wolfssl which gave the same result as the Crypto++ encryption.

So the suspect is the STM32 crypto library.

Does anybody know whether there are some tuning parameters that could affect the AES GCM encryption other than setting the endianness to little endian?

Thanks for any help.

Posted on October 16, 2016 at 20:16

Check that you have an adequate stack allocation.

Zero the context structure before use, don't assume all fields are clear.

AESGCMctx_stt GCMctx_st = { 0 }; // or memset()

Check that the crypt/decrypt operation actually gets you back to the original plaintext, not just that it doesn't error.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
davhak
Associate II
Posted on October 17, 2016 at 05:05

Thank you very much for the suggestion.

Initializing the variable to 0 does not help. I have found that the AES GCM in STM32F4 does not produce the correct cipher and the consequent decryption fails. I could not see this previously, because the plaintext size was only 7 bytes and the 7 bytes cipher was strangely getting successfully decrypted. But if I use a longer plaintext like 32 bytes in length the decryption fails at function AES_GCM_Encrypt_Finish. The memory map for the cipher text shows that only the first 7 bytes have different values all the rest byte values are A5.

Using ArmGCC as a compiler gives the following warning when linking against the STM32 crypto library:

warning: lib\crypto\M4_CryptoFW_RngHW_2_0_6.a(crypto.o) uses 2-byte wchar_t yet the output is to use 4-byte wchar_t; use of wchar_t values across objects may fail

This is because the GCC is supplied with 4-bytes wchar. Hopefully, this is not the cause of the problem. Is there an easy way to check this?

Thanks a lot again for any other suggestion.

davhak
Associate II
Posted on October 17, 2016 at 08:57

In the previous post I should have written that the decryption fails at AES_GCM_Decrypt_Finish and not AES_GCM_Encrypt_Finish.

davhak
Associate II
Posted on October 19, 2016 at 15:46

Dear All,

As I still struggle and don't find the problem, I post my problem again. After getting a wrong cipher and tag in AES GCM mode with 256bit AES key in GCC compiler I tried it also on Keil Lite version with just exactly the same outcome. So the complete function is as follows:

uint8_t test_enc_dec()

{

  uint8_t ciphertext[64];

  AESGCMctx_stt GCMctx_st = {0};

  int32_t retval, outSize, outSize2;

  uint8_t key_128[32]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,

                       0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15

                      };

    uint8_t iv[12]={0,1,2,3,4,5,6,7,8,9,10,11};

    uint8_t plaintext[32]={0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF,

                           0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF

                              };

    uint8_t header[13]={12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};

    uint8_t tag[16];

  // Set default value for Flag

  GCMctx_st.mFlags = E_SK_DEFAULT;

  // Set Tag Size to 16 bytes

  GCMctx_st.mTagSize = 16;

  //Set Iv size to 12 ( the standard for GCM )

  GCMctx_st.mIvSize=12;

  //Set Key Size to 16

  GCMctx_st.mKeySize=/*CRL_AES128_KEY*/CRL_AES256_KEY;

  // Initialize the context

  retval = AES_GCM_Encrypt_Init(&GCMctx_st, /*key_orig*/key_128, iv);

  if (retval != AES_SUCCESS)

  { return 0; }

  // Process Header (data to be authenticated but NOT encrypted)

  retval = AES_GCM_Header_Append(&GCMctx_st, header, sizeof(header));

  if (retval != AES_SUCCESS)

  { return 0; }

  // Process payload (data to be authenticated and encrypted)

  retval = AES_GCM_Encrypt_Append(&GCMctx_st, plaintext, sizeof(plaintext), ciphertext, &outSize);

  if (retval != AES_SUCCESS)

  { return 0; }

  // Generate the authentication TAG

  retval =  AES_GCM_Encrypt_Finish(&GCMctx_st, tag, &outSize2);

  if (retval != AES_SUCCESS)

  { return 0; }

  // Now reprocess the data in decryption and verify the tag we just generated

  // First set context flag to E_SK_DONT_PERFORM_KEY_SCHEDULE. This will avoid to spend time to reperform

  // The AES GCM key schedule, that has already be done previously

  // (GCM has the same Key Schedule for encryption and decryption)

  GCMctx_st.mFlags = E_SK_DONT_PERFORM_KEY_SCHEDULE;

  //Then we have to set the pointer to the tag to be verified

  GCMctx_st.pmTag = tag;

  // Init

  retval = AES_GCM_Decrypt_Init(&GCMctx_st, key_128, iv);

  // Process Header

  retval |= AES_GCM_Header_Append(&GCMctx_st, header, sizeof(header));

  // Decrypt Payload

  retval |= AES_GCM_Decrypt_Append(&GCMctx_st, ciphertext, outSize, plaintext, &outSize);

  if (retval != AES_SUCCESS) // (AES_SUCCESS is defined to 0)

  { return 0; }

  retval = AES_GCM_Decrypt_Finish(&GCMctx_st, NULL, &outSize);

  if ( retval == AUTHENTICATION_SUCCESSFUL )

    {return 1;} //printf(''Decryption/Authentication OK!'');

  else

    {return 0;} //printf(''ERROR!'');

}

In the startup*.s file the stack size as well as the heap size is set to 0xB000 which I guess is large enough to have no problem on this side. No OS is used. The project is linked against M4_CryptoFW_RngHW_2_0_6.lib library. The am testing on STM32F415VG but I deliberately use the FW version to not depend on the HW.

The question is: Has anyone ever tested the The STM32 Crypto library in AES GCM mode with 256bit key?

Thanks a lot for any insight.

Posted on October 19, 2016 at 16:46

Ok, which STM32F4 part are you using? Are you enabling the CRC peripheral? Is the PLL running?

Code still doesn't check the data integrity at either step. This is just the routine, none of the surrounding code, and not compilable as a stand-alone test case. I can build my own framework but that takes time and effort for a problem that's not mine. I've used the crypto/hash hardware in other contexts, mainly AES-128 and MD5/SHA.

If you think AES-256 isn't working, run the FIPS test cases.

Try the ST examples and test cases.

STM32F4xx_DSP_StdPeriph_Lib_V1.6.1\Project\STM32F4xx_StdPeriph_Examples\CRYP\CRYP_AES_GCM

Engage with your FAE, try an Online Support case

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..