Hi,
I am trying to use the AES accelerator module of CC430F5137 and having some difficulties. I have been following theusers guide to set registers/flags etc., but wanted to know if there are any examples that I can refer to. I dont see any in the CC430x513x Code Examples folder.
Please help.
Thanks
Fahad
Bumping old post and cannot even help, but I'm interested in same thing: is there AES Acceleration example available somewhere? I would like to find one too. Or am I forced to write my own from scrach?
Thanks.
Edit: Ok, took the User Guide and did it already. Still wondering how there isn't any example to find...
Veikko, could you share it with us? That would help some people starting in MSP430.
Folks,
we have written the DriverLib APIs for the AES module, available here: http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430ware/latest/exports/driverlib/html/aes_8h.html
The MSP430 DriverLib is part of the MSP430Ware, available either as stand-alone or integrated in CCS: http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430ware/latest/index_FDS.html
If you're only interested in only the DriverLib portion of the MSP430Ware, here's the download link for the open-source DriverLib package:
http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430ware/latest/exports/driverlib_1_20_01_00.zip
Hope this helps!
~Dung
I did it for our company, so unfortunately I can't share it...
On the other hand, nice to know about the MSP430Ware, downloading it now!
MSP430Ware only seems to implement non-block ciphers. In the cc430 user guide (slau259d.pdf, section 11.2.6) it says that block modes can be implemented:
"All block cipher modes can be implemented using the AES accelerator together with software. A separateapplication report describes the block cipher modes together with their implementation in software."
do you know where that report is, or if there are example implementations?
thanks,
Adam
Adam,
here's the app note that the UG section refers to AES128 – A C Implementation for Encryption and Decryption.
Regards,
Dung
Hi Dung,
Thanks for the reply, but I don't think that's what I'm after. The app note and examples you refer to are software implementation of AES. What I was looking for was block-mode (e.g. CBC/OFB) implementations using the AES accelerator. It's no problem to write one, but if it already exists I didn't want to re-invent the wheel, particularly as it requires switching to DMA mode which my app currently doesn't do so it's another whole layer to think about... :)
cheers,
BTW, the driverlib AES implementation in MSP430ware is subtly broken. If the examples AES_ex1 and AES_ex2 used FIPS-197 data instead of a repeating single byte value for it's test arrays this would be immediately obvious.
The problem is that you're loading a 16 bit register from a byte array, but you load the key with a different word alignment than the data. The FIPS example looks like this:
Key: 000102030405060708090a0b0c0d0e0f Plaintext: 00112233445566778899aabbccddeeff Ciphertext: 69c4e0d86a7b0430d8cdb78070b4c55aTo make this work with driverlib, you must load the arrays like this:unsigned char Data[16] = {0x11, 0x00, 0x33, 0x22, 0x55, 0x44, 0x77, 0x66, 0x99, 0x88, 0xbb, \ 0xaa, 0xdd, 0xcc, 0xff, 0xee};unsigned char CipherKey[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, \ 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};i.e. the Data is byte-swapped, but the CipherKey is not.The resulting Ciphertext will also be byte-swapped: c469d8e07b6a3004cdd880b7b4705ac5.The fix is simple - just swap the order bytes are loaded into "tempVariable" and "encryptedData"in AES_encryptData().I haven't tested any of the Decrypt functions, but I assume they will have similar issues.cheers,Adam
thank you for the critical feedback! This is really useful for us actually. We'll digest the examples and update them accordingly.
Regarding the Application Report, looks like the User's Guide, at the time it was written, refered to an App Note that it expected to be created. This effort might have gotten into a limbo state at some point, but we were hoping the introduction of DriverLib could somehow cover some of its use cases. As you found out, looks like we could use a few more examples :).
Once again, thanks for the feedback! If you ever get around to creating the block mode, feel free to post it up here and we can all take a look.
No problem, glad it was helpful.
I'll be happy to contribute my block mode implementation, but it will probably be only a hybrid software/accelerator version for now (i.e. non-DMA and software IV management) as I just don't have the time to do the whole DMA setup on this project.
As promised, here is a block mode implementation. Note that this assumes driverlib has been fixed as per my previous post.
[Edit: decryption routine added.]For all encryption Modes, load the key with AES_setCipherKey().
#define AES_AESCMX_ECB (0x00 << 5) // Electronic Codebook#define AES_AESCMX_CBC (0x01 << 5) // Cipher-block Chaining#define AES_AESCMX_OFB (0x02 << 5) // Output Feedback#define AES_AESCMX_CFB (0x03 << 5) // Cipher Feedbackunsigned char AES_encryptDataBlock(unsigned int baseAddress, unsigned char * Data, unsigned char * encryptedData, unsigned char * IV, unsigned int Length, const unsigned char Mode){ // crypto operations must be carried out locally in case we are encrypting in-place unsigned char inbuff[16], outbuff[16]; char i; if(Length % 16) return STATUS_FAIL; while(Length) { // apply IV to input data for(i= 0 ; i < 16 ; ++i) switch(Mode) { case AES_AESCMX_CBC: inbuff[i]= Data[i] ^ IV[i]; break; case AES_AESCMX_OFB: case AES_AESCMX_CFB: inbuff[i]= IV[i]; break; case AES_AESCMX_ECB: default: inbuff[i]= Data[i]; break; } // do the encryption AES_encryptData(baseAddress, inbuff, outbuff); // maintain IV & feedback for(i= 0 ; i < 16 ; ++i) switch(Mode) { case AES_AESCMX_CBC: IV[i]= outbuff[i]; break; case AES_AESCMX_OFB: IV[i]= outbuff[i]; outbuff[i] ^= Data[i]; break; case AES_AESCMX_CFB: outbuff[i] ^= Data[i]; IV[i]= outbuff[i]; break; case AES_AESCMX_ECB: default: break; } // copy encrypted data to final output for(i= 0 ; i < 16 ; ++i) encryptedData[i]= outbuff[i]; Data += 16; encryptedData += 16; Length -= 16; } return STATUS_SUCCESS;}
Here is the corresponding decryption routine. This also assumes that AES_decryptData() has been fixed as per Dung's post below..Also, note that unlike encryption, the key must be prepared differently according to Mode (due to the fact that CFB & OFB actually encrypt to 'decrypt'):For CFB, OFB: load the key with AES_setCipherKey()For ECB, CBC: load the key with AES_generateFirstRoundKey()(I personally think this is a nasty 'gotcha' and could possibly be masked by the AES_setCipherKey() routine by requiring Mode & function to be passed at that stage).unsigned char AES_decryptDataBlock(unsigned int baseAddress, unsigned char * Data, unsigned char * decryptedData, unsigned char * IV, unsigned int Length, const unsigned char Mode){ // crypto operations must be carried out locally in case we are encrypting in-place unsigned char inbuff[16], outbuff[16]; char i; if(Length % 16) return STATUS_FAIL; while(Length) { // apply IV to input data for(i= 0 ; i < 16 ; ++i) switch(Mode) { case AES_AESCMX_OFB: case AES_AESCMX_CFB: inbuff[i]= IV[i]; break; case AES_AESCMX_CBC: case AES_AESCMX_ECB: default: inbuff[i]= Data[i]; break; } // do the 'decryption' switch(Mode) { case AES_AESCMX_OFB: case AES_AESCMX_CFB: AES_encryptData(baseAddress, inbuff, outbuff); break; default: AES_decryptData(baseAddress, inbuff, outbuff); break; } // maintain IV & feedback for(i= 0 ; i < 16 ; ++i) switch(Mode) { case AES_AESCMX_CBC: outbuff[i] ^= IV[i]; IV[i]= Data[i]; break; case AES_AESCMX_OFB: IV[i]= outbuff[i]; outbuff[i] ^= Data[i]; break; case AES_AESCMX_CFB: outbuff[i] ^= Data[i]; IV[i]= Data[i]; break; case AES_AESCMX_ECB: default: break; } // copy decrypted data to final output for(i= 0 ; i < 16 ; ++i) decryptedData[i]= outbuff[i]; Data += 16; decryptedData += 16; Length -= 16; } return STATUS_SUCCESS;}
FYI, regarding your first feedback, I had some time today to look at the source code of the AES, and found the bug here:
AES_setCipherKey() loads byte-by-byte correctly (the 16-bit AESAKEY register's [High Byte][Low Byte] = [byte[n+1]][byte[n]])
aes.c for (i = 0; i < 16; i = i + 2) { //HWREG(baseAddress + OFS_AESAKEY) = ( unsigned int)(( unsigned int)CipherKey[i] | ( unsigned int) (CipherKey[i + 1] << 8)); tempVariable = (unsigned int)(CipherKey[i]); tempVariable = tempVariable | ((unsigned int)(CipherKey[i + 1]) << 8); HWREG(baseAddress + OFS_AESAKEY) = tempVariable; }
for (i = 0; i < 16; i = i + 2) { //HWREG(baseAddress + OFS_AESAKEY) = ( unsigned int)(( unsigned int)CipherKey[i] | ( unsigned int) (CipherKey[i + 1] << 8)); tempVariable = (unsigned int)(CipherKey[i]); tempVariable = tempVariable | ((unsigned int)(CipherKey[i + 1]) << 8); HWREG(baseAddress + OFS_AESAKEY) = tempVariable; }
This order (byte n = low byte, byte n+1 = high byte) is the same across all buffer registers
AES_encryptData() loads the high-byte/low-byte incorrectly, swapping them in the process
aes.c // Write data to encrypt to module for (i = 0; i < 16; i = i + 2) { //HWREG(baseAddress + OFS_AESADIN) = ( unsigned int)(( unsigned int)Data[i] | ( unsigned int) (Data[i + 1] << 8)); tempVariable = (unsigned int)(Data[i+1]); tempVariable = tempVariable | ((unsigned int)(Data[i]) << 8); HWREG(baseAddress + OFS_AESADIN) = tempVariable; }
// Write data to encrypt to module for (i = 0; i < 16; i = i + 2) { //HWREG(baseAddress + OFS_AESADIN) = ( unsigned int)(( unsigned int)Data[i] | ( unsigned int) (Data[i + 1] << 8)); tempVariable = (unsigned int)(Data[i+1]); tempVariable = tempVariable | ((unsigned int)(Data[i]) << 8); HWREG(baseAddress + OFS_AESADIN) = tempVariable; }
The decryption functions (with/without generation keys) also mix up the order of the bytes and need to be fixed as well. I filed a bug against this for DriverLib, and we should be able to roll the fix into the code soon.
Thanks again for the feedback!
I concur with your findings, but don't forget you also need to correct the byte order when copying the output to the encryptedData array or your output will still be byte-swapped.
BTW, I updated my block-mode implementation to be slightly more code efficient (edited post above).
Here is the corresponding decryption routine. [edit: code moved to original code posting above]
Any idea how long it will be before the fix is released?
I'm happy to incorporate the workaround myself in the meantime, but am hoping the fix will be released before our project is done.
Also, the documentation states that
"The AES accelerator module performs encryption and decryption of 128-bit data with 128-bit keys
according to the advanced encryption standard (AES) (FIPS PUB 197) in hardware."
Am I right to assume that if we decide to use it in 256 bit mode, that it would still conform to FIPS PUB 197?
Thanks,
Becky