When using the LTC in a KL82 for AES encryption and decryption I found strange results when setting the AES for decryption.
For the test I encrypt and decrypt a single block of 32 bytes.
When entering the AES 256 key for encryption I set the mode to
LTC0_MD = (LTC_MD_ALG_AES | LTC_MD_AAI_CBC); // AES key for encryption [0x00100100]
(although 0 also works)
The encryption is then OK.
When entering the AES 256 key for decryption I set the mode to
LTC0_MD = (LTC_MD_ALG_AES | LTC_MD_AAI_CBC | LTC_MD_AAI_DK); // AES key for decryption [0x00101100]
This is accepted - but the decryption fails.
If I then remove the LTC_MD_ALG_AES flag (0x00100000) and set the key the LTC sets its error interrupt (with error saying that there is an AES mode error). The only way to clear this error is to reset the LTC.
However now the AES256 decryption of the block works.
In fact previously I was just setting the DK bit (which I think is what the SDK examples do) when setting the key for decryption and it had worked. Only when I realised that it was causing the error interrupt to be set, and stopped this by presumably setting the algorithm correctly, did the decryption start failing.
Can anyone explain this?
P.S. I am posting a second question about AES CBC across multiple block so data in a second post, which is related to this too.
Solved! Go to Solution.
I think maybe there is some thinking set or mind-set when we read these lengthy and uncommon sense words. Let us describe the keynote when do a decrypting.
Is the key encrypt key?(yes) --> We should derive a decrypt key！--> Keep DK zero --> AES derive a decrypt key
Yes, set DK to 1 means skipping the derive step.
But there is no word say what decrypt key looks like.
The decryption key is derived from the encryption key and needs to be performed as a step before usage. For example in the embedTLS library it is performed by calling aes_setkey_dec().
The LTC does this step as an integral part of its decryption function (if DK is 0) and the derived decryption key can be seen in the module's key registers after the step.
When DK is set to 1 it essentially tells the module that it should skip this step because the decryption key (and not the encrypt key) is (already) in place.
I don't think that the decrpt key is usually of general interest (that is, how it looks) but I suspect that in both cases it could be read back and saved. Then it could be directly loaded (in case of the LTC to its key registers and in the case of the SW implementation to its key buffer in its instance) and thus the conversion step be saved when it is used again -> speed improvement against need to backup the values. Whether there is great interest in this (slight) optimisation is another question. I will measure the LTC decryption speed with a primed decrypt key against its speed when it needs to do the conversion at some point and let you know....
Some measurement results for the record. KL82 running at 72MHz core (24MHz bus and Flash):
Register encrypt key in LTC 3.6us [SW based 18.9us]
Encrypt 64 bytes of plain text to ciphertext 19.5us [SW based 240us]
Register decrypt key in LTC 3.6us (this is the encrypt key again for the LTC method) [SW based 90.9us]
Decrypt the first 32 bytes (first block operation) from cipher buffer to plain text buffer 15.95us [SW based 120us]
Decrypt the second 32 bytes (second block operation) from cipher buffer to plain text buffer 12.83us [SW based 128us]
As predicted, the second block decryption is faster than the first which suggests that the LTC requires about 3us to derive the decrypt key from the encrypt key as a part of the first block decryption.
Apart from the speed advantage of the LTC the code size is up to 10k Bytes smaller than a SW implementation too!
I have comparisons with a 120MHz K64 using mmCAN or SW for the same operations:
Register encrypt key in mmCAU 5.04us [SW based 11.1us]
Encrypt 64 bytes of plain text to ciphertext 15.6us [SW based 182us]
Register decrypt key in mmCAU 5.23us [SW based 52us]
Decrypt the first 32 bytes (first block operation) from cipher buffer to plain text buffer 8.09us [SW based 56us]
Decrypt the second 32 bytes (second block operation) from cipher buffer to plain text buffer 8.28us [SW based 56us]
I think the best way is to use SDK demo and driver directly. I guess there is some sequence issue. For example, the driver set DK at the beginning of LTC_AES_DecryptCbc(). But when it set all control bit in MD
modeReg = (uint32_t)alg | (uint32_t)enc | (uint32_t)as | (uint32_t)mode;
I modified the code, do not set DK at the beginning, but
modeReg = (uint32_t)alg | (uint32_t)enc | (uint32_t)as | (uint32_t)mode | (uint32_t)(1U<< kLTC_ModeRegBitShiftDK);
The result was error.
DK must be set "before" (or while) the key is entered otherwise the module will think it is an encrypt key and so it will fail when decrypting.
At the moment I can't get the SDK working because MCUXpresso fails to import the project. I'll be doing a complete MCUXpresso update / reinstall shortly to see whether I can resolve it and test the SDK code directly.
I know that SDK does
base->MD |= (1U << kLTC_ModeRegBitShiftDK);
before entering the key but in my experience this causes the error interrupt flag to be set (when DK is set and the other algorithm bits are not appropriate). The fact that the interrupt error is set doesn't cause operational failure but seems strange to me....
When it works do you also see the error interrupt flag set?
No, I don't see it.
If the key is same as encryption, you should not set DK.
status = LTC_AES_DecryptCbc(base, cipher, output, g_length, ive, key128, AES128_KEY_SIZE, kLTC_EncryptKey);
And in LTC_AES_DecryptCbc()
if (keyType == kLTC_DecryptKey)
base->MD |= (1U << kLTC_ModeRegBitShiftDK);
I finally managed to run the SDK tests (I woudln't get MCUXpressor to work with the FRDM board so I had to first had to spend some time porting it to IAR). Only after stepping the code did I realise that the reference never actually sets the DK.
Also I re-read the description for about the 6th time and finally it starts to make sense:
Basically, if DK is set it means one is passing the decrypt key (and not the encrypt key). The LTC can work with the encrypt key by doing a decrypt conversion when needed (takes longer than if the decrypt key is supplied directly).
Interestingly in another post I was finding that the second decrypted block was successful when using the DK setting (setting encryption key and informing that it were the decrypt key) which suggest that after the first block decryption (failed) it was internally converting the key to a decrypt key (presumably as a part of the normal decrypt operation...).....
The remaining problem is that decrypting a stream of data in a number of block call (rather than one large block) is failing after the first block. See https://community.nxp.com/thread/488542
The KDS reference only tests a single block so I am wondering whether it can handle a stream or not?