NaCl Crypto Library on Mountaineer 4.3.1 platform

Notice: Undefined index: id in C:\home\site\wwwroot\wp-content\plugins\oembed-gist\oembed-gist.php on line 105

It’s night, your home is silent. Your appliances quietly talk to each other, while MQTT messages run in your wifi network towards a distant broker, carrying both unassuming payloads like your bedroom temperature or the washing machine power consumption and more sensitive ones, like your alarm system sensors status.

The problem is that what to your appliances looks like one of your routers is not, in fact, one of your routers. Someone hijacked your network with a simple tool he bought on the internet for a handful of euros. That little guy is sending all your packets to his owner, who simply ignores your fridge and oven chatters but focuses on the data sent from the security sensor of your back door. The rest is a nightmare.

The Internet of Things, whatever it means these days, is a great opportunity for good and bad guys alike. The wealth of data transmitted among “Things” must be protected from prying eyes just like your emails and home banking transactions do. Some times, even more.
What you need is cryptography, the technique humans always used and refined to keep things secret, from the Pharaos to the NSA. Encrypting messages payloads could keep most of the bad guys outside your network, and your home.
The problem is that IoT devices must be kept small in terms of computing and memory resources in order to get low power consumption and acceptable costs, but this does not go well with the intricacies and calculation requirements of modern cryptography techniques.
To be suitable for use in a low power, single chip device, a crypto algorithm (indeed, a library of implementations of cryptographic algorithms) must be reasonably secure both in the algorithms themselves and in the code that implements them; it must work as fast as possible to avoid getting in the way of the job that the IoT network must do and to consume a small quantity of processing power and finally it must require the smallest memory footprint possible.

Writing such a library is a daunting task, well beyond the skills and time to market requirements of the vast majority of IoT developers. A properly written, fast and simple library, to really be secure, must also be easy to use: cryptography is a tricky matter, often learnt in higher level math courses. Using a secure but complex library in an inappropriate way could open dangerous vulnerabilities in your code and protocols.

The Mountaineer Group tries to come in help proposing a porting to c# for the .NET microframework of the widely known (and very positively reviewed) NaCl (pronounced “salt”) crypto library, written by Daniel J. Bernstein and Tanja Lange http://nacl.cr.yp.to/.  The engineers at Oberon have chosen an implementation from the original C code of each NaCl algorithms, they’ve built the necessary plumbing between the NaCl lib and the C# API, trying to mimic as closely as possible the original function signatures, and shared the library for review.  Little differences in data types still remain, but this should not hinder the overall safety and ease of use of the methods.


01b602c2c02911e386db0002c9559ce2_8

NaCl provides what is called “authenticated encryption”. In layman terms, this means that not only messages are encrypted, but they are authenticated: the receiver can be sure that none tampered with the encrypted text. Note that this, as explicitly stated by the NaCl team, does not mean “non repudiability” (a message is non-repudiable when the sender is securely identified and he or she cannot “repudiate” the sent message). If non repudiability is mandatory, one can use the same NaCl to digitally sign the cyphertext.

NaCl offers methods for both symmetric and asymmetric encryption.  While a formal explanation of these terms is way beyond the purpose of this post (and the skills of the writer), they can be summarized as such: symmetric encryption has only one secret key, it’s like putting your message in a safe, closing the safe with that key and secretely distributing copies of the key to your partners.  Whoever has that key can close and open the safe (encrypt and decrypt the message). This is fast, simple, but needs a secure channel to distribute the key, which must remain secret.

Asymmetric encryption is a little more complicated (and cpu intensive) but does not require the private sharing of a secret key. As a matter of fact, it is often called public key encryption. Imagine a strange safe that is normally open and has two keys: one, the public key, can only be used to lock the safe. The other, the private key, can only open the safe. If Bob is the receiver of the secret message, he can distribute openly the public key to anyone. Bob can make copies of it and spread it to the world. When his girlfriend Alice wants to send him a message, she puts it in the safe, uses the public key to lock the safe and sends him the safe. The only thing that Alice must be secure of is that the chosen public key is Bob’s. An attacker (the evil Eve) who intercepts the safe cannot open it, because she only has the public key (whose only purpose is to lock the safe). When Bob gets the safe, he uses the secret private key to open it, and reads the message.

An authenticated encryption scheme assures the receiver (and only the receiver) that no one has tampered with the safe (the encrypted message). If Bob wants also to be absolutely sure that the sender is who he thinks she is, Alice can digitally sign the message (the safe metaphor falls short now) with her own private key, and Bob can use Alice’s public key to verify the signature. If Eve wants to send BOB a message pretending she is Alice, she will not be able to do it, because she cannot sign it without knowing Alice’s private key.

Since Public Key Cryptography is expensive in terms of calculations, it is often only used to encrypt a symmetric secret key, an hash of the message, and the possibly bulky message is thus encrypted with the faster symmetric scheme.

NaCl does all this in a single step, although it uses a slightly different approach. If Alice wants to send Bob an authenticated encrypted message, she uses her private key and his public key to produce a shared secret. By means of a truly beautiful mathematical process, Bob can get the same shared secret by using his private key and Alice’s public key.  Then Alice uses a number that can only be used once in the exchange between her and Bob (this funny number is aptly called nonce) and, using an algorithm of her choice, she encrypts the message, calculates an authenticator (a number that would reveal if someone tampers with the encrypted text), packages everything into a package suitable to be transmitted and sends it to Bob, along with the nonce, that can be transmitted unprotected.  Bob decrypts the package and checks the validator using the nonce and the shared key he calculated earlier and he verifies that no one modified the encrypted text. Technically speaking, this is done by using an elliptic curve (curve25519) for the Diffie-Ellman shared keys, Salsa20 to encrypt and Poly1305 to authenticate (the primitive of CryptoBox is called curve25519xsalsa20poly1305).

All of this work is done by NaCl, all you have to do is provide the keys, the nonce and the message and call one (one) method. To be honest, NaCl can even produce these key pairs for you. For free.

What has this to do with the Internet of Things? A lot. Do you want to be sure that no one reads the packets that your appliances exchange? Encrypt them. Do you want to be absolutely sure that no one tampers with them? Encrypt and authenticate them. Do you want to be sure that it’s your alarm sensor speaking and not an attacker? Let it sign its encrypted and authenticated packets.
Do you need a lot of distributed sensors talk to a single receiver? Use asymmetric encryption.
The use cases are endless.

But, one may ask, does NaCl fit the requirements we asked for the IoT?
Definitely. It’s fast, as certified by many tests. It’s designed not to use dynamic memory allocation, and this predictability is a very desirable feature in a device with small onboard memory. It’s simple to use, embedding a lot of processes in a single method.
It’s reasonably secure, as it’s written by real gurus and extensively peer reviewed.

Well, let’s see how to use the Oberon porting of NaCl in one of our NetMF projects.

The porting comes both for .NET MF Mountaineer porting and for regular .NET. This is fun because it allows performance comparison between a decent i7 windows pc and a STM32F4-based board.

Firstly, let’s try the secret key (symmetric) encryption. We will use two static methods of the SecretCryptoBox class:

public static int Box(byte[] c, int coff, byte[] m, int moff, int mlen, byte[] n, byte[] k);

to cypher, where c is the cyphertext array, coff the offset into it, m the plaintext, moff the offset into it, n the nonce, k the secret key

public static int Open(byte[] m, int moff, byte[] c, int coff, int clen, byte[] n, byte[] k);

to decypher, where m is the plaintext, moff the offset into it, c is the cyphertext array, coff the offset into it, clen the cyphertext length, n the nonce, k the secret key

The nonce used is a 24 bytes long random number. To get the maximum security one should be absolutely sure that each nonce is never, never, never used again for the same key while using symmetric encryption or for the same couple of sender/receiver while using asymmetric encryption (which means, never use the same nonce for the same shared secret key twice).
In theory, just choosing a random number does not guarantee that there will not be collisions: the well known Birthday Paradox attack shows just this. Anyway, a 24 bytes long nonce, created with a good (pseudo) random number generator, better if started with a counter, gives reasonable security for most purposes without the burden of checking whether a number has already been used before.

We will write two very simple static methods to encrypt and decrypt a message (the zero paddings are required by NaCl, see the original docs for reference):

now we can test the methods for correct encryption/decryption and detection of tampering and wrong key use:

as you may notice, there are several constants (CryptoSecretBox.NonceBytes, CryptoSecretBox.KeyBytes,CryptoSecretBox.BoxZeroBytes ) that help in declaring the right array sizes. Testing the asymmetric encryption is a bit more convoluted, since we must create Keys for our friends Alice and Bob, then we will use the static methods of the class CryptoBox:

public static int Box(byte[] c, int coff, byte[] m, int moff, int mlen, byte[] n, byte[] pk, byte[] sk);

 

public static int Open(byte[] m, int moff, byte[] c, int coff, int clen, byte[] n, byte[] pk, byte[] sk);

the parameters are very similar to those we saw for CryptoSecretBox, with the additions of pk and sk, the public and secret keys arrays.

This code is heavily based on the useful samples provided by Oberon (https://bitbucket.org/oberon-microsystems/oberon.nacl.samples):

for the test method we must create two key pairs, one for Alice and one for Bob, using the method:

public static int ComputeKeyPair(byte[] pk, byte[] sk);

twice:

Tests for wrong key and cyphertext tampering can be done similarly to those we saw in TestSymmetric(), and are omitted for brevity.

We can modify slightly those Test functions to get a glimpse at performances (not recalculating nonces):

https://gist.github.com/pomarc/b8f20552e69db4ed0f76

Well, this thing is FAST.

On my i7 win8 64bit PC, a million runs only take around 3500ms, or about 0.0035ms per run.  On Mountaineer  boards, which is more interesting, 10000 runs take on average 12557ms, that’s roughly1.2ms per run!

 

Let’s try the more demanding asymmetric encryption:

 

On Mountaineer boards, this (10000 runs) took a total average of 12668ms!   Fast!  These tests are done calling the method we wrote and not directly and only the box() and open() methods because the overhead of preparing buffers and calling utility methods are a normal way of operation. This said, it is possible to squeeze better performances by reusing buffers.

But there’s more: if two parties needed to send many messages between them, the shared key obtained from the public and secret key can be precompiled and then used, thereby lowering the computational cost.

To do this, you have to use

public static int BeforeNm(byte[] k, byte[] pk, byte[] sk)

to obtain the shared key,

public static int AfterNm(byte[] c, int coff, byte[] m, int moff, int mlen, byte[] n, byte[] k)

to encrypt and

public static int OpenAfterNm(byte[] m, int moff, byte[] c, int coff, int clen, byte[] n, byte[] k)

to decrypt, where byte[] k is the precomputed shared key.

The use of AfterNm and OpenAfterNm is similar to what we’ve seen for the standard CryptoBox Box and Open methods.

The third operation we can do with NaCl is digital signature. If Bob wants to be sure that the message he’s receiving is from Alice and that no one modified it, he can ask her to cryptographically sign the message. She can do this by using an hashing algorithm to obtain a short hash of the message, called message digest; then she can use her own private key to encrypt this hash.
When Bob receives the hash and the message, he can use Alice’s public key to decrypt the hash, since a public key can be used to decryt a message encrypted with a private key, then he can recompute the hash of the received document, and if the two hashes match, he can be sure that Alice (or someone having her private key) signed the message, and that the message has not changed after the signature.

NaCl wraps these steps up and offers two very handy methods to sign and verify, from the CryptoSign static class:

to sign:

public static int Sign(byte[] sm, int smoff, out int smlen, byte[] m, int moff, int mlen, byte[] sk);

where sm is the destination (signed message) byte array, smoff the offset to it, smlen its length, m the message (input) buffer, moff and mlen the zero based offset into it and its length; sk the secret (private) key used to sign.

to verify:

public static int Open(byte[] m, int moff, out int mlen, byte[] sm, int smoff, int smlen, byte[] pk);

where m is the destination buffer, that contains the verified message between moff and mlen. sm is the signed message, between smoff and smlen, and pk is the signer’s public key.

The crypto primitives NaCl uses are Curve25519 elliptic curve (Edwards form) and SHA-512 secure hash algorithm (SHA-2).

Again, looking at the code from Oberon’s sample on bitbucket, we can see how simple signing and verifying with NaCl is:

Security and privacy are a very important and difficult aspect of every IoT project, the Oberon’s NaCl porting is a very handy, secure and fast toolkit that .NET MF developers can use to add an extra level of security to their products.

 

References:

 

 

public static int Open(byte[] m, int moff, byte[] c, int coff, int clen, byte[] n, byte[] pk, byte[] sk);

 

 

the parameters are very similar to those we saw for CryptoSecretBox, with the additions of pk and sk, the public and secret keys arrays. This code is heavily based on the useful samples provided by Oberon (https://bitbucket.org/oberon-microsystems/oberon.nacl.samples):

 

 

31/07/2014
Tags: , , , , , , , ,
Categorie: microframework
Autore: admin

It’s night, your home is silent. Your appliances quietly talk to each other, while MQTT messages run in your wifi network towards a distant broker, carrying both unassuming payloads like your bedroom temperature or the washing machine power consumption and more sensitive ones, like your alarm system sensors status. The problem is that what to […]


Support