AES Encryption & Decryption on Teensy 4.x

VictorFS

Well-known member
I am currently adapting a huge application which was originally developed on Teensy 3.5 to the newer Teensy 4.1 platform. So far, I was able to find a replacement for almost all the libraries which I used and were exclusive for Teensy 3.x. Unfortunately, I couldn't find an substitute to the CryptoAccel lib yet, as it seems to be incompatible with Teensy 4.1.

I was using the functions mmcau_aes_set_key , mmcau_aes_encrypt and mmcau_aes_decrypt only. I tried to search GitHub and Google for possible alternative libraries, but so far I only found hardware-specific libs (example:for Arduino AVR MCUs).

Do anyone knows a library which could be used to perform those AES encrypt/decrypt tasks ?
 
I think https://github.com/manitou48/teensy4/blob/master/dcptst.ino was just a test that manitou48 performed, but it is not yet developed into a functional library. With time, I think that I might me able to convert this code to an easy to use lib. However, my use for the cryptography functions is very simple right now. I basically use it only one time during the program runtime to encrypt a password and decrypt later on. I do not require the speed of the hardware accelerated DCP, nor the many options provided. So in this case my wish was to use some hardware-independent Arduino compatible ready-to-use library and move on with the rest of the Teensy 3.5 -> Teensy 4.1 migration.

Do you happen to know any such library? If not, I may have to invest the time converting manitou's test to a lib. Thanks!
 
@manitou the most likely to know about that. Those posts 3.5 years back when T_4.0 was in Beta. Not sure if any progress beyond this note 4 months later noting the path to a library as it was seen:

here is an earlier post https://forum.pjrc.com/threads/54711-Teensy-4-0-First-Beta-Test?p=197722&viewfull=1#post197722
that describes using the T4 crypto accelerators for AES and SHA. The low level block operations are accelerated, so one would need to add code to do blocking etc to get a full library-like implementation. The NXP SDK has modified the mbedtls and wolfssl crypto libs to incorporate the T4 acceleration and T4 TRNG. You could study those libraries to see how you might make an accelerated Teensy lib. (the "unaccelerated" versions of mbedtls and wolfssl work on the Teensy 3/4)

some comparisons of AES and SHA256 on various MCUs in perf.txt

That came up with forum search: DCP
there were a few other hits - not sure if any better

To find the p#2 notes it was a forum search: mmcau then on that BETA thread a 'Search Thread' again for 'mmcau', to get that post.

Don't expect to find a complete solution - but that would get to confirming that.
 
While I can't talk much about the DCP (officially its documentation is covered by NDA), the dcptst.ino code looks like a copy of stuff from NXP's SDK with everything you need to use if for hardware accelerated AES128, SHA256, and CRC32.

Of course, the big caveat for dcptst.ino is the AES secret key is stored in RAM which gets initialized from a copy in non-volatile flash. This code only gives access to the encryption engine but not any sort of specialized hardware for managing the secret key. Likewise for the IV used for CBC mode. The only way for this to offer any hope of strong security is to use Lockable Teensy, of course locked in secure mode. With standard Teensy the flash memory isn't encrypted and JTAG is enabled, which gives a resourceful attacker plenty of opportunity to obtain the secret key. Like all symmetric encryption, the hard part of achieving strong security is managing the secret key.
 
I think https://github.com/manitou48/teensy4/blob/master/dcptst.ino was just a test that manitou48 performed, but it is not yet developed into a functional library. With time, I think that I might me able to convert this code to an easy to use lib. However, my use for the cryptography functions is very simple right now. I basically use it only one time during the program runtime to encrypt a password and decrypt later on. I do not require the speed of the hardware accelerated DCP, nor the many options provided. So in this case my wish was to use some hardware-independent Arduino compatible ready-to-use library and move on with the rest of the Teensy 3.5 -> Teensy 4.1 migration.

Do you happen to know any such library? If not, I may have to invest the time converting manitou's test to a lib. Thanks!

if you don't need the hardware accelerators then you can use wolfssl or mbedtls library -- google "arduino wolfssl" or "arduino mbedtls", or search the PJRC forums

AES demo for mbedtls
Code:
void aes_demo() {
  // just for timing purposes  128-bit key 64 bytes cbc
  unsigned char iv[16], key[32], nonce_counter[16], stream_block[16], buff[64], out[64];
  size_t length = 64, nc_off = 0;
  uint32_t t;
  mbedtls_aes_context ctx;

  mbedtls_aes_init( &ctx );
  t = micros();
  mbedtls_aes_setkey_enc( &ctx, key, 128 );
  t = micros() - t;
  Serial.print("aes setkey "); Serial.println(t);

  t = micros();
  mbedtls_aes_crypt_cbc( &ctx, MBEDTLS_AES_ENCRYPT, 64, iv, buff, buff );
  t = micros() - t;
  Serial.print("encrypt "); Serial.println(t);

  mbedtls_aes_setkey_dec( &ctx, key, 128 );
  t = micros();
  mbedtls_aes_crypt_cbc( &ctx, MBEDTLS_AES_DECRYPT, 64, iv, buff, buff );
  t = micros() - t;
  Serial.print("decrypt "); Serial.println(t);

  t = micros();
  mbedtls_aes_crypt_ctr( &ctx, length, &nc_off, nonce_counter, stream_block, buff, out );
  t = micros() - t;
  Serial.print("ctr "); Serial.println(t);
}

and a wolfssl AES test
Code:
  wc_AesSetKey(&aesenc, (byte *)buff, 16, (byte *)buff, AES_ENCRYPTION);
  t = micros();
  wc_AesCbcEncrypt(&aesenc, (byte *)buff, (byte *)buff, sizeof(buff));
  t = micros() - t;
  sprintf(str, "AESCBC 1024 %lu us %lu KBs", t, 1000 * sizeof(buff) / t);
  Serial.println(str);

or you could look for standalone AES lib -- google "arduino aes" or search for AES in PJRC forums

AES benchmarks and DCP tests and mbedtls vs wolfssl benchmarks

See arduino crypto lib
 
Last edited:
Thanks a lot defragster, Paul and manitol for the help!

Of course, the big caveat for dcptst.ino is the AES secret key is stored in RAM which gets initialized from a copy in non-volatile flash. This code only gives access to the encryption engine but not any sort of specialized hardware for managing the secret key. Likewise for the IV used for CBC mode. The only way for this to offer any hope of strong security is to use Lockable Teensy, of course locked in secure mode. With standard Teensy the flash memory isn't encrypted and JTAG is enabled, which gives a resourceful attacker plenty of opportunity to obtain the secret key. Like all symmetric encryption, the hard part of achieving strong security is managing the secret key.

Paul, without a lockable Teensy (which is my case), would any encryption library be vulnerable to an attacker with a JTAG and access to the non-encrypted flash memory or it is just the case of dcptst.ino?
The reason why I am using AES is to try to somehow lock (or at least make it harder for an invader) to steal the firmware running in one Teensy and make it run in another Teensy. I currently use hardware values which are unique to each Teensy such as the UID and MAC address as part of the secret key to encrypt a string and store that encrypted string in the EEPROM. When the Teensy boots, it encrypts the String and check the output against what is stored in the EEPROM. If the output is the same, that means that the same secret key was used (same UID, MAC, etc) so it is the same authorized Teensy. I know that it doesn't offer strong security. Do you have any idea on how this could be improved without the need of some external hardware ou a lockable Teensy?

if you don't need the hardware accelerators then you can use wolfssl or mbedtls library -- google "arduino wolfssl" or "arduino mbedtls", or search the PJRC forums

Thanks manitou! I will take a look at those libraries.
 
You need lockable Teensy. You can't possibly hope to build this with strong security on standard Teensy.

Software libraries like mbedtls will not be enough for strong security against a resourceful attacker with physical access to the hardware. Those libraries are meant to give secure internet communication, but the security model only protects against eavesdropping or manipulation by people who can intercept the communication. They don't provide security against physical access tampering (as lockable Teensy does).


The reason why I am using AES is to try to somehow lock (or at least make it harder for an invader) to steal the firmware running in one Teensy and make it run in another Teensy.

The important question is what you mean by "another Teensy". If the threat is merely a thief extracting your code and programming it onto another Teensy they buy from PJRC or a distributor (which doesn't have your key written into the fuse memory) then lockable Teensy is enough.

If "another Teensy" means a lockable Teensy which came from you and has your private key, then you need to add code or use different keys. For background, read "Firmware Cloning Between Boards" on the code security page (scroll down past a lot of other stuff)

https://www.pjrc.com/teensy/td_code_security.html

You can build anti-cloning (between Teensy boards you provide pre-programmed with your key) on top of lockable Teensy. The recommended way is to burn data into the fuse memory and have your code check it.

But if you only need to prevent your code from running on other Teensy boards you didn't provide, that's exactly the target usage for lockable Teensy.
 
Thanks again, Paul! I've read the Teensy Code Security page some months ago and found the information really useful. I agree that a lockable Teensy would be the best option for me in this use case. Unfortunately, I already have a stock of standard non-lockable Teensy 4.1 bought in high quantity due to the risk of running out of stock during the shortage times or having to deal with an Teensy board without the Ethernet chip. I was unable to find Teensies anywhere in stock, so when it reentered stock in Digikey with the Ethernet Phy chip I bought many. In the future I will buy the lockable version.
 
Standard Teensy can't offer strong protection.

But you can at least get weak protection by using Tools > Teensy 4 Security "Fuse Write Sketch" to write your key so encrypted code can run, and then program with EHEX (which happens automatically if the Teensy has your key). If you were to use Teensy Loader without Arduino, you'd want to copy only the .EHEX file and not have the .HEX file on the machine doing the programming, so you don't risk accidentally writing the plaintext code.

At the start of your program, you can use this code to check the authentication info. It does cost 8K of RAM, but you could reuse that buffer after running this test.

Code:
__attribute__ ((section(".hab_log"), used)) volatile uint8_t HAB_logfile[8192];

void setup() {
  const uint32_t hab_version = (*(uint32_t (**)())0x00200330)();
  const uint32_t hab_status = (*(int (**)(int *, int *))0x00200324)(NULL, NULL);
  HAB_logfile[sizeof(HAB_logfile)-1]; // do not delete this line!

  Serial.begin(9600);
  Serial.print("Authentication: ");
  if (hab_version == 0x40307) {
    if (hab_status == 0xF0) {
      Serial.println("Pass");
    } else {
      Serial.println("Fail (status)");
      while (1) ;
    }
  } else {
    Serial.println("Fail (version)");
    while (1) ;
  }
}

void loop() {
}

Maybe you would want to handle the fail cases differently, but obviously you wouldn't want to allow your program to run.

Again, this isn't strong protection like you would get with lockable Teensy. But maybe it's better than nothing, and it follows the same steps you'll take when you eventually use up your supply of standard Teensy and switch to lockable. Hopefully the semiconductor market will return to normal by then and we'll have lockable Teensy continuously in stock without quantity limits.

Of course you can also try to build other tests into your code, like range of serial numbers. If you check for specific data you've written, better to put it into the fuse memory than using EEPROM.
 
Hello guys, it's been a while...

Of course, the big caveat for dcptst.ino is the AES secret key is stored in RAM which gets initialized from a copy in non-volatile flash. This code only gives access to the encryption engine but not any sort of specialized hardware for managing the secret key.
If I used the OTP key or Unique key options, which are factory defined, stored inside the processor, unchangeable and unreadable from software as far as I know (I do not have access to the security manual of the processor), would it be more secure?

I ended up using manitou's dcptst.ino example code and modify it a little to create some hardware accelerated AES-128 functions on Teensy 4.1. When setting my own key and placing it in a key slot (m_handle.keySlot = kDCP_KeySlot0) for example, everything works fine. However, I am not having the same luck when using the other key options of the enum _dcp_key_slot, such as OTP or Unique Key. When I use this, the produced cipher text is the same as if it was produced with an all zero 128 bits key.

Information about the DCP of the i.MX RT1060 is very scarce, as most of it seems to be under a NDA. However I did found a example driver code for the DCP where it seems that using the OTP key requires some extra steps before dcp initialization, such as using the function DCP_OTPKeySelect(kDCP_OTPMKKeyLow) to set the OTP key type in IOMUX registers. I have implemented this step in my code, however it still did not work :(

Manitou, do you know any way to get the OTP key to work on Teensy? What would I have to add to the example code dcptst.ino to make this possible?

Thanks a lot!
 
Hi there,

Manitou, do you know any way to get the OTP key to work on Teensy? What would I have to add to the example code dcptst.ino to make this possible?

not Manitou, but used to i.MXs ... in case of the Teensy 4 there are two things worth to mention:

1) You could use a "standard Teensy" (an "old" serial no. 610374 does this here as well) and fuse a public key hash and an encryption key.
You can write the hash and encryption key only once. While you can read and compare the hash later, you'll not be able to read the key
directly (ARM core returns 0xBADABADA = "bad address"). Afterwards you can configure the OTP key with DCP using:

Code:
	DCP_OTPKeySelect(kDCP_OCOTPKeyLow); // OCOTP
	dcp_init();
	m_handle1.channel = kDCP_Channel0;
	m_handle1.swapConfig = kDCP_NoSwap;
	m_handle1.keySlot = kDCP_OtpKey;

Please note: other programs could still use DCP with your key inside the Teensy, if the boards are in other hands.
If the encrytion key is not fused the CPU just returns zeros for the key. That's why you get the encryption results
as you described before.

2.) For the SNVS key to work you need a lockable Teensy in locked mode, so the following code could use it:

Code:
	DCP_OTPKeySelect(kDCP_OTPMKKeyLow); // SNVS
	dcp_init();
	m_handle1.channel = kDCP_Channel0;
	m_handle1.swapConfig = kDCP_NoSwap;
	m_handle1.keySlot = kDCP_OtpUniqueKey;

SNVS is not available if the CPU is not locked, so you get the same result as with the OTP key if no OTP key is fused.

I can tell for sure that all this works with the Teensy 4.x. We'll be sending another bunch of Teensys with this configuration
to space in February. Came here to check back the HAB auth code if we were missing something. BTW: it's easy to tell
Teensys apart from each other using the information above.

Best,
CK
 
Hi Paul,

No, not really.

depends on the security model. The SNVS key is only available if the Teensy is locked and could only be used by
code passing the HAB authentication. So, if you need to export and import critical data from/to the very same Teensy
the SNVS key could be used - that's why the name. The key isn't shared with other chips and doesn't need to be
deployed. So this is the safest option from a key management and distribution perspective.

The OTP key needs to be written only once and can be shared between multiple boards. If the key is fused, it doesn't
need to be distributed in the code. You could split development and production authorization, so the key management
is done by limited amount of authorized and trusted staff.
Of course, as mentioned above non-locked / standard Teensys can be misused to use the OTP key with DCP to decrypt
ehex files.

Both keys can not be read out (and cloned) directly - this diffentiates them from SRAM / flash based keys.

Best and thanks a lot for the lockable Teensys! :),
CK
 
I need to speak carefully. PJRC signed a NDA with NXP. The finer details of the IMXRT security are NXP confidential.

1) You could use a "standard Teensy"
...you'll not be able to read the key directly (ARM core returns 0xBADABADA = "bad address").

This capability might not actually work on standard Teensy, because of the way the lock bits are configured. Maybe...

Really, the main point I want to emphasize is the PJRC's official position is to use lockable Teensy properly locked into secure mode. Use of standard Teensy, or lockable Teensy not yet locked into secure mode, as a general rule does not offer good security.

Sorry, I really can't comment on the details.

But I will mention as showed people at NXP the 3 sketches and other details of lockable Teensy and they gave us the green light to publish.
 
I need to speak carefully. PJRC signed a NDA with NXP. The finer details of the IMXRT security are NXP confidential.

You're not alone, that's why I stick to what can be learned i.e. from
https://github.com/ARMmbed/mbed-os/blob/master/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/drivers/fsl_dcp.c in public discussions.

This capability might not actually work on standard Teensy, because of the way the lock bits are configured. Maybe...

Well, SNVS can't and definitely will not work.

Really, the main point I want to emphasize is the PJRC's official position is to use lockable Teensy properly locked into secure mode. Use of standard Teensy, or lockable Teensy not yet locked into secure mode, as a general rule does not offer good security.

I couldn't emphasize this more. That's why I said "thank you for the lockable Teensys" in my second reply ;-)

Sorry, I really can't comment on the details.

No problem, there's no need to. I'm under NDA as well.

But I will mention as showed people at NXP the 3 sketches and other details of lockable Teensy and they gave us the green light to publish.

And that's quite fine and fully sufficient to work with the Teensys.

Best,
CK
 
@ckahlo (and any others that may know): Would you happen to know how to use the payload key (AES) with the DCP?

More information: in the interests of understanding how things work, I like to go through any information I can find and implement functional libraries for myself and my projects. Even if there’s something better out there and I don’t end up using my own code, I’m better for it.

I’ve recently implemented my own DCP interface library, along with unit tests for all the NIST block cipher and hash tests. (Not to test NXP’s DCP implementations, but to verify I’ve done things correctly.) When I change the key type to “payload”, none of the encryption/decryption tests pass; I see incorrect results. However, when I change to using one of the SRAM key locations, the cipher works.

I was thinking that maybe one has to set some register value, similar to what you have to do to access the OTP keys, in order to use the payload key, but so far I haven’t found anything. Perhaps it’s as simple as setting some additional register value somewhere, or maybe reordering the payload bytes (containing the key and possibly the IV). I’m stuck.

What I’m doing now is setting the payload to a concatenation of the key and IV, and, of course, setting the “payload key type” in control0 of the work packet. This is how the SDK does it.

If anyone has any tips for using a payload key beyond what the SDK does, I’d love to hear them.
 
I figured it out. I was missing a cache flush before the work was scheduled. Now things seem to work. Unless I'm not understanding the reference code (which is probably the case), I'm not sure why it doesn't do a cache flush before scheduling AES work.

Now if I could just get those darn CBC mode Monte Carlo tests working...
 
Last edited:
Hello you all!
I have somewhat of a strange and interesting issue with encryption. I got the example above working very nicely (https://github.com/manitou48/teensy4/blob/master/dcptst.ino).

But in my case, I have two Teensies that work over the NRF24 radio. They send Encrypted messages between eachother. Both have batteries because they're obviously wireless.
When connected to the same Ground source (because that's what I think is the issue here) it works flawlessly. But if one or the other isn't connected, it doesn't work. Oh well it keeps working until you restart the device.
When I say "It doesn't work" I mean that it does send data ofc, but the 16 or 32 bytes (I've tried both) are distorted. Aka the full message is not even close to what it should be.

The only logical explanation I can think of is that it has to do with ground. Shame if I can't use this lovely code example since it seems to work very well otherwise.
Perhaps @PaulStoffregen has any idea.

Thanks all!
 
Any chance the NRF24 modules you're using have a simple antenna, like a zig-zag trace on the PCB, which only works if the module's ground is connected to a relatively large piece of metal?
 
Could you please observe the Forum Rule:
Forum Rule: Always post complete source code & details to reproduce any issue!
In this case your circuit and any photos will/may help someone help you solve your problem.
Without more information all I could suggest is add a ground spike at each location.
 
Any chance the NRF24 modules you're using have a simple antenna, like a zig-zag trace on the PCB, which only works if the module's ground is connected to a relatively large piece of metal?

I managed to solve this super weird issue. I first try to set the encryption key and ive as a static array (hardcoded) and that made it work. Strangely enough!
And now I've remade the code that sets the key and ive. It all works.

I still have no idea how the common power/ground source made it work before. True mystery!

Big thanks for quick replies. Appreciate it big time!
 
Back
Top