Sunday 15 May 2016

How ECC-SHA-llent!

About a year ago, shortly after TI released the CC26xx family of chips, I published a rant about the differences between those chips and the CC2538. Among the things I discussed was the fact that TI have apparently removed advanced cryptographic hardware acceleration from the CC26xx (and subsequently CC13xx) products.

No SHA2, no ECC, only good-old AES...

It was not making sense! Why remove such a desirable feature???

CC26xxware to the rescue


At roughly the same time as the first CC26xx chips were released, TI also released a set of supporting libraries code-named CC26xxware. The Contiki OS has supported CC26xx-based boards since pretty-much day one and it pulls CC26xxware in as a git sub-module. At the time of release, CC26xxware was at revision 2.21.01.15600.

Come CC26xxware version 2.21.03.15980 and suddenly two new files appear: rom_crypto.h and rom_crypto.c. Uh-oh...

For the CC13xx family of chips, the respective support bundle is called CC13xxware and it features the same two files. TI originally distributed CC26xxware and CC13xxware as stand-alone downloads, but at some point they decided to stop doing so and they are now bundling them inside TI-RTOS.

Both xxwares are distributed under the terms of the 3-clause BSD license, which is an excellent choice!

Back to the point: So perhaps the chips do have crypto capability, only TI is not very forthcoming about it.

Let's have a closer look!

The ROM crypto API


If we look inside rom_crypto.h, we see the following function prototypes (Taken from CC26xxware version 2.23.01.16780, distributed with TI RTOS 2.16.00.08 - 25 Feb 2016):

extern void AES_ECB_EncryptData(uint8_t *text, uint16_t textLen, uint8_t *aesKey);
extern void AES_ECB_DecryptData(uint8_t *text, uint16_t textLen, uint8_t *aesKey);
extern int8_t AES_CCM_EncryptData(uint8_t encryptFlag, uint8_t MACLen, uint8_t *nonce,
                                  uint8_t *plainText, uint16_t textLen,
                                  uint8_t *addDataBuf, uint16_t addBufLen,
                                  uint8_t *aesKey, uint8_t *MAC, uint8_t ccmLVal);
extern int8_t AES_CCM_DecryptData(uint8_t decryptFlag, uint8_t MACLen, uint8_t *nonce,
                                  uint8_t *cipherText, uint16_t textLen,
                                  uint8_t *addDataBuf, uint16_t addBufLen,
                                  uint8_t *aesKey, uint8_t *MAC, uint8_t ccmLVal);
extern uint8_t AES_CTR_EncryptData(uint8_t *plainText, uint16_t textLen,
                                   uint8_t *aesKey, uint8_t *nonce,
                                   uint8_t *initVector);
extern uint8_t AES_CTR_DecryptData(uint8_t *cipherText, uint16_t textLen,
                                   uint8_t *aesKey, uint8_t *nonce,
                                   uint8_t *initVector);
extern void ECC_initialize(uint32_t *pWorkzone);
extern uint8_t ECC_generateKey(uint32_t *randString, uint32_t *privateKey,
extern uint8_t ECC_ECDSA_sign(uint32_t *secretKey, uint32_t *text, uint32_t *randString,
                              uint32_t *sign1, uint32_t *sign2);
extern uint8_t ECC_ECDSA_verify(uint32_t *publicKey_x, uint32_t *publicKey_y,
                                uint32_t *text, uint32_t *sign1, uint32_t *sign2);
extern uint8_t ECC_ECDH_computeSharedSecret(uint32_t *privateKey,
                                            uint32_t *publicKey_x,
                                            uint32_t *publicKey_y,
                                            uint32_t *sharedSecret_x,
                                            uint32_t *sharedSecret_y);
extern uint8_t SHA256_runFullAlgorithm(SHA256_memory_t *memory, uint8_t *pBufIn,
                                       uint32_t bufLen, uint8_t *pBufOut);
extern uint8_t SHA256_initialize(SHA256_memory_t *workZone);
extern uint8_t SHA256_execute(SHA256_memory_t *config, uint8_t *pBufIn,
                              uint32_t bufLen);
extern uint8_t SHA256_output(SHA256_memory_t *memory, uint8_t *pBufOut);

So, what can these things do?


We can safely draw some conclusions here now, can't we? The chips can do:
  • SHA 256
  • ECDSA sign/verify
  • ECDH
  • AES CTR, ECB, CCM
But this is a ROM API. If you look at the corresponding .c file, you will see things in the lines of this (excerpt from the same TI-RTOS version):

typedef uint8_t(*ecdsa_sign_t)(uint32_t *, uint32_t *,uint32_t *, uint32_t *, uint32_t *);
ecdsa_sign_t ecc_ecdsa_sign = (ecdsa_sign_t)(0x10017969);

uint8_t
ECC_ECDSA_sign(uint32_t *secretKey, uint32_t *text, uint32_t *randString,
               uint32_t *sign1, uint32_t *sign2)
{
  return (uint8_t)ecc_ecdsa_sign((uint32_t*)secretKey, (uint32_t*)text, (uint32_t*)randString,
                                 (uint32_t*)sign1, (uint32_t*)sign2);
}

Thus, a call to ECC_ECDSA_sign() is fundamentally a jump to a pre-determined address in ROM through a function pointer. The same applies for ECDH and SHA functions. What we cannot know for certain until TI decides to tell us is what exactly happens under the hood at these addresses on ROM. Nothing stopping us from guessing though, and I can imagine two scenarios:
  • Either that address on ROM hosts a fully software-based implementation of ECDSA (or ECDH or SHA and so on)
  • Or that address in ROM hosts a driver for some undocumented hardware crypto engine.
If we look at the addresses on ROM a little more closely:

ecdsa_sign_t ecc_ecdsa_sign = (ecdsa_sign_t)(0x10017969);
ecdsa_verify_t ecc_ecdsa_verify = (ecdsa_verify_t)(0x10017b01);

Ergo, there is a gap of 0x10017b01 - 0x10017969 = 408 bytes there available for ecc_ecdsa_sign. Draw your own conclusions if you fancy doing so.

What we can also do is actually try to use those functions and benchmark them; this could provide more hints about whether we are looking at a hardware crypto engine.

A brief note about RNGs


In the CC26xx Technical Reference Manual [1], TI have boldly stated:
"The true random number generator (TRNG) module provides a true, nondeterministic noise source for the purpose of generating keys, initialization vectors (IVs), and other random number requirements. The TRNG is built on 24 ring oscillators that create unpredictable output to feed a complex nonlinear combinatorial circuit. That post-processing of the output data is required to obtain cryptographically secure random data."
TI don't normally make such claims lightly. For instance, the CC2538 User Guide [2] clearly classifies the respective RNG as a Pseudo-RNG and does not suggest that the module is suitable for crypto. In fact the document contains statements like:
"Randomness tests show good results for this module. However, a slight DC component exists."
and
"To fully qualify the random generator as true random, much more elaborate tests are required. Software packages that may be useful in this respect are available on the internet."
This is something I personally interpret as, "If you want to do crypto using this thing, do so at your own risk".

Final thoughts


During a recent e-mail exchange, a colleague of mine whom I respect immensely wrote to me something in the lines of "Why does the chip with all the crypto capability lack a cryptographically suitable RNG, whereas the chip that does have a cryptographically secure RNG has limited crypto capability?".

That was a very valid point and I suspect we have not heard the entire story yet.

What I have not yet had time to do is search around for more information on the hardware in places such as TI's E2E forum as well as on the wider internet. What I also want to do is have a closer look at TI-RTOS' sources and see how (and if) it uses those ROM functions. Doing so may reveal further hints...

References

[1] "CC26xx SimpleLinkTM Wireless MCU Technical Reference Manual", SWCU117D, February 2015 - Revised September 2015, [ pdf ]
[2] "CC2538 System-on-Chip Solution for 2.4-GHz IEEE 802.15.4 and ZigBee®/ZigBee IP® Applications", SWRU319C, April 2012 - Revised May 2013, [ pdf ]