Raspberry Pi e Windows Azure Service Bus via AMQP con la libreria Qpid Proton C 

Posted by Paolo Patierno Friday, April 18, 2014 3:05:25 PM
Rate this Content 0 Votes

Nel corso di questa tutorial vedremo in che modo sia possibile utilizzare la Raspberry Pi come client AMQP (Advanced Message Queuing Protocol) e collegarla al Windows Azure Service Bus che supporta la versione AMQP 1.0.

Ovviamente, la scelta della libreria client da utilizzare è quasi obbligata : Apache Qpid Proton. Tale libreria sviluppata in C fornisce comunque il bindings per altri linguaggi tra cui Java, Python e PHP ma nel corso dell’articolo utilizzeremo solo la versione nativa.

Generalmente, la Raspberry Pi viene utilizzata con la distribuzione Raspbian (basata su Debian) che è a tutti gli effetti una distribuzione Linux. Ciò vuol dire che possiamo installare la libreria Qpid Proton come faremo su un normale distribuzione Ubuntu su un PC oppure su una macchina virtuale ad esempio su Windows Azure.

Connessione alla Raspberry Pi

Tutte le operazioni che seguono possono essere effettuate accedendo direttamente alla Raspberry Pi attraverso un monitor, una tastiera ed un mouse collegati ad essa oppure in remoto attraverso l’utilizzo di SSH.

La seconda soluzione è sicuramente la più comoda, utilizzado un tool come Putty e specificando l’indirizzo IP della nostra board, la porta (tipicamente la 22) ed il tipo di connessione (SSH).

01

02

Installazione dei prerequisiti

Una volta effettuato l’accesso, in primo luogo bisogna installare dei componenti fondamentali tra cui GCC, CMAKE (sistema di build utilizzato da Qpid) e la libreria UUID per la generazione di identificativi univoci.

sudo apt-get install gcc cmake uuid-dev

Poichè Qpid utilizza SSL e il Service Bus necessita di questo prerequisito per la connessione, dobbiamo installare OpenSSL nel nostro sistema (che in realtà potrebbe essere già installato).

sudo apt-get install openssl

La presenza della libreria OpenSSL non include la presenza degli header file e delle librerie statiche necessarie per lo sviluppo. Bisogna quindi installare la libssl-dev.

sudo apt-get install libssl-dev

Non essendo interessato ad alcun binding con altri linguaggi, possiamo evitare di installare i package per Python, PHP e così via, passando direttamente al download della libreria dal sito ufficiale. Inoltre, non installiamo le dipendenze che riguardano la generazione automatica della documentazione.

Download e compilazione della Qpid Proton

Dal sito ufficiale possiamo ricavare uno dei mirror da cui scaricare la libreria nella sezione “Download” per poi scaricarla usando il tool WGET.

pi@raspberrypi ~ $ wget http://apache.fastbull.org/qpid/proton/0.6/qpid-proton-0.6.tar.gz
--2014-04-16 07:09:52--  http://apache.fastbull.org/qpid/proton/0.6/qpid-proton-0.6.tar.gz
Resolving apache.fastbull.org (apache.fastbull.org)... 194.116.84.14
Connecting to apache.fastbull.org (apache.fastbull.org)|194.116.84.14|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 629147 (614K) [application/x-gzip]
Saving to: `qpid-proton-0.6.tar.gz'

100%[======================================>] 629,147     1.00M/s   in 0.6s

2014-04-16 07:09:53 (1.00 MB/s) - `qpid-proton-0.6.tar.gz' saved [629147/629147]

Dopo il download. estraiamo il contenuto del file.

tar xvfz qpid-proton-0.6.tar.gz

Entriamo nella cartella appena create (qpid-proton-0.6) e creiamo una cartella “build” in cui faremo generare dal tool CMAKE il corrispondente Makefile per la compilazione della libreria.

mkdir build

cd build

cmake -DCMAKE_INSTALL_PREFIX=/usr ..

L’output del comando cmake dovrebbe essere il seguente.

pi@raspberrypi ~/qpid-proton-0.6/build $ cmake -DCMAKE_INSTALL_PREFIX=/usr ..
-- The C compiler identification is GNU 4.6.3
-- Check for working C compiler: /usr/bin/gcc
-- Check for working C compiler: /usr/bin/gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- PN_VERSION: 0.6
-- Found Java: /usr/bin/java
-- Java version: 1.7.0.40. javac is at: /usr/bin/javac
-- Locations of Bouncycastle 1.47 jars: BOUNCYCASTLE_BCPROV_JAR-NOTFOUND BOUNCYCASTLE_BCPKIX_JAR-NOTFOUND
-- Won't build proton-j-impl because one or more Bouncycastle jars were not found. PROTON_JAR_DEPEND_DIR was: /usr/share/java
-- Found OpenSSL: /usr/lib/arm-linux-gnueabihf/libssl.so;/usr/lib/arm-linux-gnueabihf/libcrypto.so (found version "1.0.1e")
-- Looking for clock_gettime
-- Looking for clock_gettime - not found.
-- Looking for clock_gettime in rt
-- Looking for clock_gettime in rt - found
-- Looking for uuid_generate
-- Looking for uuid_generate - not found.
-- Looking for uuid_generate in uuid
-- Looking for uuid_generate in uuid - found
-- Looking for strerror_r
-- Looking for strerror_r - found
-- Looking for atoll
-- Looking for atoll - found
-- Could NOT find SWIG (missing:  SWIG_EXECUTABLE SWIG_DIR)
-- Could NOT find Doxygen (missing:  DOXYGEN_EXECUTABLE)
-- Looking for include file inttypes.h
-- Looking for include file inttypes.h - found
-- Can't locate the valgrind command; no run-time error detection
-- Cannot find rspec, skipping rspec tests
-- Cannot find both Java and Maven: testing disabled for Proton-J and JNI Bindings
-- Configuring done
-- Generating done
-- Build files have been written to: /home/pi/qpid-proton-0.6/build

Ci sono alcuni warning sull’impossibilità di trovare il runtime Java, Swig e Doxygen. Come già anticipato, non siamo interessato al binding con altri linguaggi ed alla generazione automatica della documentazione per cui possiamo non preoccuparci di tali warning.

L’ultimo step consiste nell’utilizzare il tool MAKE per elaborare il Makefile appena generato da cmake ed installare la libreria nel sistema.

sudo make install

Al termine della compilazione, la libreria è installata nel sistema in corrispondenza della cartella /usr (come specificato nel primo comando CMAKE eseguito) ed in particolare :

  • /usr/share/proton : contiene un esempio di utilizzo;

  • /usr/bin e /usr/lib : contengono i file relativi la libreria vera e propria;

  • /usr/include/proton : contiene gli header file necessari per lo sviluppo di un’applicazione;

Esempio di invio e ricezione su Service Bus

Per poter testare il corretto funzionamento della libreria utilizziamo i semplici esempi di send e receive distribuiti con la libreria stessa durante l’installazione.

cd /usr/share/proton/examples/messenger/

Anche in questo caso possiamo sfruttare il tool CMAKE per la generazione del Makefile necessario alla compilazione (da notare che è necessario l’esecuzione come Super User).

sudo mkdir build

cd build

sudo cmake ..

sudo make all

Al termine della compilazione avremo i due file eseguibili recv e send corrispondenti a due semplici applicativi che permettono di ricevere ed inviare messaggi ad una coda via AMQP.

Per fare questo, creiamo un nuovo namespace per il Service Bus sul portale di Microsoft Azure ed in corrispondenza di questo anche una queue. Nel mio caso, il namespace è qpidproton.servicebus.windows.net e la coda banalmente “myqueue”. Attraverso il portale dobbiamo ricavare due parametri fondamentali per la connessione che sono lo SharedSecretIssuer (tipicamente “owner”) e lo SharedSecretValue.

03

L’indirizzo per la connessione al Service Bus avrà la seguente struttura :

amqps://username:password@namespace.servicebus.windows.net/queue_name

Poichè il Service Bus usa le connessioni SSL, dobbiamo utilizzare AMQPS in luogo del semplice AMQP.

Per inviare un messaggio con testo “Hello” alla queue dobbiamo eseguire l’applicazione send nel modo seguente.

./send –a amqps://username:password@namespace.servicebus.windows.net/queue_name Hello

Per poter ricevere un messaggio dalla stessa queue possiamo utilizzare l’applicazione recv nel modo seguente.

./recv amqps://username:password@namespace.servicebus.windows.net/queue_name

Con un risultato di questo tipo.

Address: amqps://username:password@namespace.servicebus.windows.net/queue_name
Subject: (no subject)
Content: "Hello"

Microsoft Azure per l’Internet of Things 

Posted by Paolo Patierno Thursday, April 17, 2014 2:20:39 PM
Rate this Content 0 Votes

Immagine

Come ulteriore conferma che la Microsoft vuole entrare a far parte del business dell’Internet of Things, è stata rilasciata una “limited preview” di un nuovo prodotto su Azure : Microsoft Azure Intelligent System Service.

L’obiettivo primario è quello di fornire un’unica piattaforma in grado di acquisire dati generati da sistemi eterogenei (e quindi anche non Microsoft) per poterli elaborare ed analizzare in tempo reale con strumenti come HDInsight.

Le principali potenzialità saranno :

  • Connettività : possibilità di connettere un qualsiasi device indipendentemente dal sistema operativo onboard;
  • Configurazione : definizione di regole per automatizzare i processi sui device;
  • Amministrazione : possibilità di monitorare, configurare ed aggiornare i device sul campo;
  • Estendibilità : maggiore scalabilità ed efficienza grazie all’infrastruttura basata sul Cloud;

Al seguente link, è possibili richiedere la limited preview alla quale avranno accesso i potenziali utilizzatori a seguito di un questionario con cui valutare il progetto da realizzare.

Qpid Proton C su una macchina virtuale Ubuntu Server 12.04 in Windows Azure per l’utilizzo del Service Bus con AMQP : creazione, configurazione, compilazione ed uso 

Posted by Paolo Patierno Wednesday, April 16, 2014 1:45:06 PM
Rate this Content 0 Votes

Uno dei protocolli maggiormente utilizzati nell’ambito del messaging che può trovare applicazione anche nell’Internet of Things è l’AMQP (Advanced Message Queuing Protocol), ormai già standard OASIS da alcuni anni e giunto alla versione 1.0.

Il servizio Service Bus offerto da Windows Azure supporta tale protocollo che, essendo standard, garantisce la comunicazione tra client sviluppati su piattaforme diverse. Nel caso di una piattaforma Microsoft non abbiamo alcun problema grazie al Windows Azure SDK (giunto alla versione 2.3) che astrae completamente il protocollo di comunicazione sottostante con il Service Bus (AMQP, SBMP, …) grazie al suo modello di programmazione.

Nel caso in cui ci troviamo a lavorare su un sistema non Microsoft, una delle migliori scelte è quella di adottare le librerie del progetto Apache Qpid ed in particolare la Qpid Proton. Tale libreria sviluppata in C fornisce comunque il bindings per altri linguaggi tra cui Java, Python e PHP.

Nel corso di questo tutorial, vedremo come sia possibile creare una macchina virtuale Ubuntu Server 12.04 su Windows Azure, installare ed utilizzare la libreria Qpid Proton per inviare e ricevere messaggi attraverso il Service Bus con il protocollo AMQP. Ovviamente, tale procedura può essere utilizzata anche nel caso di un qualsiasi sistema Ubuntu 12.04 (anche client e non server) non necessariamente su Windows Azure ma sul nostro PC in locale.

Creazione della macchina virtuale su Windows Azure

In primo luogo dobbiamo creare una macchina virtuale con il sistema operativo Ubuntu Server 12.04 LTS su Windows Azure. Per farlo, è necessario collegarsi al Management Portal e loggarsi con il proprio account. Una volta loggati, selezioniamo sulla sinistra “Virtual Machines” e cliccate su “Create a Virtual Machine”; utilizziamo l’opzione di “Quick create” impostando :

  • DNS Name : il nome DNS da assegnare alla macchina virtuale;
  • Image : l’immagine del sistema operativo da utilizzare che in questo caso è “Ubuntu Server 12.04 LTS”;
  • Size : la “dimensione” della macchina virtuale in base alle nostre necessità;
  • New password/Confirm : password e relativa conferma per l’utente creato di default che si chiama “azureuser”;
  • Region/Affinity Group : la regione (data center) in cui creare la nostra macchina virtuale;

Clicchiamo su “Create a virtual machine” per avviare la creazione della macchina virtuale.

01_create_vm

Al termine del processo di creazione che dura alcuni minuti avremo la conferma.

02_vm_created

Per poterci collegare alla macchina virtuale in remoto, è necessario conoscere l’endpoint per l’accesso via SSH che possiamo trovare cliccando sul nome della macchina virtuale appena creata (nel mio caso ppatiernoubuntu) e poi sul tab “Endpoints” (nel mio caso la porta è la 22).

03_SSH_endpoint

Scarichiamo un client Telnet come Putty per poterci collegare, inserendo l’host name e la porta corretta.

04_Putty

All’apertura della console digitiamo “azureuser” come nome utente e la corrispondente password che abbiamo scelto nella fase di creazione della macchina virtuale.

Installazione dei prerequisiti

Il file README distribuito con la libreria Qpid Proton descrive abbastanza nel dettaglio la procedura per l’installazione della libreria ma fa riferimento al tool YUM che su Ubuntu non abbiamo nativamente a disposizione; in luogo di esso usiamo APT. Inoltre, alcune libreria non hanno esattamente lo stesso nome come descritto nel file README.

In genere, la prima operazione che faccio su una macchina Ubuntu è quella di installare il package “build-essential” con tutti gli strumenti principali per la compilazione, eseguendo il comando :

sudo apt-get install build-essential

Il passo successivo è quello di installare le dipendenze principali tra cui GCC (che avremo già installato grazie al package “build-essential”), CMAKE (sistema di build utilizzato da Qpid) e la libreria UUID per la generazione di identificativi univoci (un pò come il nostro caro Guid).

sudo apt-get install gcc cmake uuid-dev

Poichè Qpid utilizza SSL e il Service Bus necessita di questo prerequisito per la connessione, dobbiamo installare OpenSSL nel nostro sistema (che in realtà potrebbe essere già installato).

sudo apt-get install openssl

La presenza della libreria OpenSSL non include la presenza degli header file e delle librerie statiche necessarie per lo sviluppo. Bisogna quindi installare la libssl-dev.

sudo apt-get install libssl-dev

Non essendo interessato ad alcun binding con altri linguaggi, possiamo evitare di installare i package per Python, PHP e così via, passando direttamente al download della libreria dal sito ufficiale. Inoltre, non installiamo le dipendenze che riguardano la generazione automatica della documentazione.

Download e compilazione della Qpid Proton

Dal sito ufficiale possiamo ricavare uno dei mirror da cui scaricare la libreria nella sezione “Download” per poi scaricarla usando il tool WGET.

azureuser@ppatiernoubuntu:~$ wget http://apache.fastbull.org/qpid/proton/0.6/qpid-proton-0.6.tar.gz
--2014-04-16 07:09:52-- 
http://apache.fastbull.org/qpid/proton/0.6/qpid-proton-0.6.tar.gz
Resolving apache.fastbull.org (apache.fastbull.org)... 194.116.84.14
Connecting to apache.fastbull.org (apache.fastbull.org)|194.116.84.14|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 629147 (614K) [application/x-gzip]
Saving to: `qpid-proton-0.6.tar.gz'

100%[======================================>] 629,147     1.00M/s   in 0.6s

2014-04-16 07:09:53 (1.00 MB/s) - `qpid-proton-0.6.tar.gz' saved [629147/629147]

Dopo il download. estraiamo il contenuto del file.

tar xvfz qpid-proton-0.6.tar.gz

Entriamo nella cartella appena create (qpid-proton-0.6) e creiamo una cartella “build” in cui faremo generare dal tool CMAKE il corrispondente Makefile per la compilazione della libreria.

mkdir build

cd build

cmake -DCMAKE_INSTALL_PREFIX=/usr ..

L’output del comando cmake dovrebbe essere il seguente.

azureuser@ppatiernoubuntu:~/qpid-proton-0.6/build$ cmake -DCMAKE_INSTALL_PREFIX=/usr ..
-- The C compiler identification is GNU
-- Check for working C compiler: /usr/bin/gcc
-- Check for working C compiler: /usr/bin/gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- PN_VERSION: 0.6
-- Could NOT find Java (missing:  Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE)
-- Found OpenSSL: /usr/lib/x86_64-linux-gnu/libssl.so;/usr/lib/x86_64-linux-gnu/libcrypto.so (found version "1..1")
-- Looking for clock_gettime
-- Looking for clock_gettime - not found.
-- Looking for clock_gettime in rt
-- Looking for clock_gettime in rt - found
-- Looking for uuid_generate
-- Looking for uuid_generate - not found.
-- Looking for uuid_generate in uuid
-- Looking for uuid_generate in uuid - found
-- Looking for strerror_r
-- Looking for strerror_r - found
-- Looking for atoll
-- Looking for atoll - found
-- Could NOT find SWIG (missing:  SWIG_EXECUTABLE SWIG_DIR)
-- Could NOT find Doxygen (missing:  DOXYGEN_EXECUTABLE)
-- Looking for include files INTTYPES_AVAILABLE
-- Looking for include files INTTYPES_AVAILABLE - found
-- Can't locate the valgrind command; no run-time error detection
-- Cannot find ruby, skipping ruby tests
-- Cannot find both Java and Maven: testing disabled for Proton-J and JNI Bindings
-- Configuring done
-- Generating done
-- Build files have been written to: /home/azureuser/qpid-proton-0.6/build

Ci sono alcuni warning sull’impossibilità di trovare il runtime Java, Swig e Doxygen. Come già anticipato, non siamo interessato al binding con altri linguaggi ed alla generazione automatica della documentazione per cui possiamo non preoccuparci di tali warning.

L’ultimo step consiste nell’utilizzare il tool MAKE per elaborare il Makefile appena generato da cmake ed installare la libreria nel sistema.

sudo make install

Al termine della compilazione, la libreria è installata nel sistema in corrispondenza della cartella /usr (come specificato nel primo comando CMAKE eseguito) ed in particolare :

  • /usr/share/proton : contiene un esempio di utilizzo;
  • /usr/bin e /usr/lib : contengono i file relativi la libreria vera e propria;
  • /usr/include/proton : contiene gli header file necessari per lo sviluppo di un’applicazione;

Esempio di invio e ricezione su Service Bus

Per poter testare il corretto funzionamento della libreria utilizziamo i semplici esempi di send e receive distribuiti con la libreria stessa durante l’installazione.

cd /usr/share/proton/examples/messenger/

Anche in questo caso possiamo sfruttare il tool CMAKE per la generazione del Makefile necessario alla compilazione (da notare che è necessario l’esecuzione come Super User).

sudo mkdir build

cd build

sudo cmake ..

sudo make all

Al termine della compilazione avremo i due file eseguibili recv e send corrispondenti a due semplici applicativi che permettono di ricevere ed inviare messaggi ad una coda via AMQP.

Per fare questo, creiamo un nuovo namespace per il Service Bus sul portale di Microsoft Azure ed in corrispondenza di questo anche una queue. Nel mio caso, il namespace è qpidproton.servicebus.windows.net e la coda banalmente “myqueue”. Attraverso il portale dobbiamo ricavare due parametri fondamentali per la connessione che sono lo SharedSecretIssuer (tipicamente “owner”) e lo SharedSecretValue.

05_sb_access

L’indirizzo per la connessione al Service Bus avrà la seguente struttura :

amqps://username:password@namespace.servicebus.windows.net/queue_name

Poichè il Service Bus usa le connessioni SSL, dobbiamo utilizzare AMQPS in luogo del semplice AMQP.

Per inviare un messaggio con testo “Hello” alla queue dobbiamo eseguire l’applicazione send nel modo seguente.

./send –a amqps://username:password@namespace.servicebus.windows.net/queue_name Hello

Per poter ricevere un messaggio dalla stessa queue possiamo utilizzare l’applicazione recv nel modo seguente.

./recv amqps://username:password@namespace.servicebus.windows.net/queue_name

Con un risultato di questo tipo.

Address: amqps://username:password@namespace.servicebus.windows.net/queue_name
Subject: (no subject)
Content: "Hello"

NaCl Crypto Library on Mountaineer 4.3.1 platform 

Posted by Marco Poponi Saturday, April 12, 2014 10:12:01 AM
Rate this Content 0 Votes

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.


 
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):

 

static byte[] EncryptSecretKey(string message, byte[] secretKey,
    byte[] nonce) { // We need a byte array for the message byte[]
    messageBuffer = UTF8Encoding.UTF8.GetBytes(message);
 
        // Prepare buffers for encrypted data and padded message text
        var unencryptedDataBuffer = new byte[CryptoBox.ZeroBytes + messageBuffer.Length]; 
        var encryptedDataBuffer = new byte[unencryptedDataBuffer.Length];
 
        //NaCl requires a zero padded buffer:
        Array.Copy(messageBuffer, 0, unencryptedDataBuffer, CryptoSecretBox.ZeroBytes, messageBuffer.Length);
       
        //encrypt
        CryptoSecretBox.Box(encryptedDataBuffer,0, unencryptedDataBuffer, 0,unencryptedDataBuffer.Length,nonce, secretKey);
 
        return encryptedDataBuffer;
    }
 
 
static string DecryptSecretKey(byte[] encryptedMessage, byte[] secretKey, byte[] nonce)
    {
        // Prepare buffers
        var decryptedDataBuffer = new byte[encryptedMessage.Length];
        var encryptedDataPadded = new byte[encryptedMessage.Length + CryptoSecretBox.BoxZeroBytes];
 
        //decrypt
        if (CryptoSecretBox.Open(decryptedDataBuffer, 0, encryptedMessage, 0, encryptedMessage.Length, nonce, secretKey)
                != 0)
        {
            //this happens if data has been tampered with or the key is wrong
            throw new ArgumentException("Could not decrypt data");
        }
 
        // Message could be decrypted, convert byte array to string
        int dataLength = (decryptedDataBuffer.Length - CryptoSecretBox.ZeroBytes);
        char[] buffer = UTF8Encoding.UTF8.GetChars(decryptedDataBuffer, CryptoSecretBox.ZeroBytes, dataLength);
        return new string(buffer);
    }

 

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

 

static void TestSymmetric()
    {
        // First we create a nonce specify the nonce and fill it with random values
        var nonce = new byte[CryptoSecretBox.NonceBytes];
        RandomNumberGenerator rng = RandomNumberGenerator.Create();
        rng.GetBytes(nonce);
 
        // Then we create a secret key
        var key = new byte[CryptoSecretBox.KeyBytes];
        rng.GetBytes(key);
 
        //the secret message!!!
        var message = "winter is coming";
 
        //normal operations:
        try
        {
            //encrypt
            byte[] cypertext = EncryptSecretKey(message, key, nonce);
 
            //decrypt
            string decrypted = DecryptSecretKey(cypertext, key, nonce);
 
            //test
            if (decrypted == message)
            {
                Debug.Print("OK! the text matches");
            }
            else
            {
                Debug.Print("ERROR: this should NOT happen, ouch, the decyphered text is wrong!");
            }
        }
        catch (Exception ex)
        {
            Debug.Print("ERROR: this should NOT happen!");
        }
 
        try
        {
            byte[] cypertext = EncryptSecretKey(message, key, nonce);
 
            //just changes a byte in the cyphertext:
            cypertext[4] =1;
 
            string decrypted = DecryptSecretKey(cypertext, key, nonce);
            Debug.Print("this should never be executed!");
 
        }
        catch (Exception ex)
        {
            Debug.Print(" this error SHOULD happen, the cyphertext has been tampered with, yay!");
        }
 
 
        try
        {
            byte[] cypertext = EncryptSecretKey(message, key, nonce);
 
            //wrong key:
            key[4] = 0;
 
            string decrypted = DecryptSecretKey(cypertext, key, nonce);
            Debug.Print("this should never be executed!");
 
        }
        catch (Exception ex)
        {
            Debug.Print("this error SHOULD happen, the key has been changed, yay!");
        }
 
        
    }
 

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):

static byte[] EncryptAsymmetric(string message, byte[] publicKey, byte[] secretKey, byte[] nonce)
    {
        // First convert the string to a byte array:
        byte[] messageBuffer = UTF8Encoding.UTF8.GetBytes(message);
        // Preallocate array and accomodate space for zero padding.
        var unencryptedData = new byte[CryptoBox.ZeroBytes + messageBuffer.Length];
        Array.Copy(messageBuffer, 0, unencryptedData, CryptoBox.ZeroBytes, messageBuffer.Length);
        // Preallocate output buffer
        var encryptedData = new byte[unencryptedData.Length];
        CryptoBox.Box(encryptedData, 0, unencryptedData, 0, unencryptedData.Length, nonce, publicKey, secretKey);
        return encryptedData;
    }
 
static string DecryptAsymmetric(byte[] encryptedData, byte[] publicKey, byte[] secretKey, byte[] nonce)
    {
        // First preallocate the data array
        var decryptedData = new byte[encryptedData.Length];
        if (CryptoBox.Open(decryptedData, 0, encryptedData, 0, encryptedData.Length, nonce, publicKey, secretKey)
                != 0)
        {
            throw new ArgumentException("Could not decrypt data");
        }
        // Message could be decrypted, convert byte array to string
        int dataLength = (decryptedData.Length - CryptoBox.ZeroBytes);
        char[] buffer = UTF8Encoding.UTF8.GetChars(decryptedData, CryptoBox.ZeroBytes, dataLength);
        return new string(buffer);
    }
 

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:

class KeyPair
    {
        internal byte[] PublicKey = new byte[CryptoBox.PublicKeyBytes];
        internal byte[] SecretKey = new byte[CryptoBox.SecretKeyBytes];
    }
 
static void TestAsymmetric()
    {
        // First create the keypairs for both Alice and Bob
        var Alice = new KeyPair();
        var Bob = new KeyPair();
        CryptoBox.ComputeKeyPair(Alice.PublicKey, Alice.SecretKey);
        CryptoBox.ComputeKeyPair(Bob.PublicKey, Bob.SecretKey);
 
        // Then specify the nonce and fill it with random values
        var nonce = new byte[CryptoBox.NonceBytes];
        RandomNumberGenerator rng = RandomNumberGenerator.Create();
        rng.GetBytes(nonce);
 
        // Alice sends a message to Bob
 
        var message = "Hear Me Roar!";
         
        byte[] secretMessage = EncryptAsymmetric(message, Bob.PublicKey, Alice.SecretKey, nonce);
 
        // Bob receives the encrypted message and decrypts it
        string decryptedMessage = DecryptAsymmetric(secretMessage, Alice.PublicKey, Bob.SecretKey, nonce);
        
        //test:
       
        if (decryptedMessage == message)
        {
            Debug.Print("OK! the text matches");
        }
        else
        {
            Debug.Print("ERROR: this should NOT happen, ouch, the decyphered text is wrong!");
        }
 
 
 
    }
 

 

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):

 

static double  TestSymmetricPerformances(int numberOfRuns)
    {
        // First we create a nonce specify the nonce and fill it with random values
        var nonce = new byte[CryptoSecretBox.NonceBytes];
        RandomNumberGenerator rng = RandomNumberGenerator.Create();
        rng.GetBytes(nonce);
 
        // Then we create a secret key
        var key = new byte[CryptoSecretBox.KeyBytes];
        rng.GetBytes(key);
 
        //the secret message!!!
        var message = "you know nothing Jon Snow";
 
        DateTime now = DateTime.Now;
        //normal operations:
 
        for (int i = 0; i < numberOfRuns; i++)
        {
            //encrypt
            byte[] cypertext = EncryptSecretKey(message, key, nonce);
 
            //decrypt
            string decrypted = DecryptSecretKey(cypertext, key, nonce);
        }
 
         var span = ((TimeSpan)(DateTime.Now - now));
 
        //no totalMilliseconds on MF
        return span.Minutes*60*1000+span.Seconds*1000+span.Milliseconds;
 
 
    }
 


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 roughly 1.2ms per run!

 

Let's try the more demanding asymmetric encryption:

static double TestAsymmetricPerformances(int numberOfRuns)
    {
        // First create the keypairs for both Alice and Bob
        var Alice = new KeyPair();
        var Bob = new KeyPair();
        CryptoBox.ComputeKeyPair(Alice.PublicKey, Alice.SecretKey);
        CryptoBox.ComputeKeyPair(Bob.PublicKey, Bob.SecretKey);
 
        // Then specify the nonce and fill it with random values
        var nonce = new byte[CryptoBox.NonceBytes];
        RandomNumberGenerator rng = RandomNumberGenerator.Create();
        rng.GetBytes(nonce);
 
        // Alice sends a message to Bob
 
        var message = "You know nothing Jon Snow!";
 
        DateTime now = DateTime.Now;
        //normal operations:
        for (int i = 0; i < numberOfRuns; i++)
        {
        byte[] secretMessage = EncryptAsymmetric(message, Bob.PublicKey, Alice.SecretKey, nonce);
 
        // Bob receives the encrypted message and decrypts it
        string decryptedMessage = DecryptAsymmetric(secretMessage, Alice.PublicKey, Bob.SecretKey, nonce);
        }
 
        var span = ((TimeSpan)(DateTime.Now - now));
 
        //no totalMillisecons on MF
        return span.Minutes * 60 * 1000 + span.Seconds * 1000 + span.Milliseconds;
       
    }
 

 

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:

static byte[] Sign(string message, byte[] secretKey)
    {
        byte[] messageBuffer = UTF8Encoding.UTF8.GetBytes(message);
 
        var signedMessage = new byte[CryptoSign.Bytes + messageBuffer.Length];
 
        int smlen;
        CryptoSign.Sign(signedMessage, 0, out smlen, messageBuffer, 0, messageBuffer.Length, secretKey);
 
        if (smlen != signedMessage.Length)
        {
            var buffer = new byte[smlen];
            Array.Copy(signedMessage, 0, buffer, 0, smlen);
            return buffer;
        }
        else
        {
            return signedMessage;
        }
    }
 
    static string Verify(byte[] signedMessage, byte[] publicKey)
    {
        var buffer = new byte[signedMessage.Length];
        int mlen;
        if (CryptoSign.Open(buffer, 0, out mlen, signedMessage, 0, signedMessage.Length, publicKey)
                != 0)
        {
            throw new ArgumentException("Could not verify message!");
        }
        char[] messageBuffer = UTF8Encoding.UTF8.GetChars(buffer, 0, mlen);
        return new string(messageBuffer);
    }
 


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:

GnatMQ : un broker MQTT per il .Net Framework 

Posted by Paolo Patierno Friday, April 04, 2014 5:19:07 PM
Rate this Content 0 Votes

Cattura

Con una settimana di ritardo rispetto l’uscita prevista, ho finalmente rilasciato in versione Beta un broker MQTT completamente sviluppato in C# e che può essere eseguito con il .Net Framework ed il .Net Compact Framework 3.9 (su sistemi con Windows Embedded Compact 2013) … il suo nome è GnatMQ !

Al suo interno pulsa il cuore della libreria M2Mqtt con la quale condivide il “core” del protocollo MQTT, per quanto riguarda la parte di connessione al client e la gestione dei messaggi.

Ovviamente, è completamente open source e disponibile su CodePlex ma è attualmente in versione Beta (aspetto numerose segnalazioni da parte vostra !).

Come riportato nella pagina di documentazione supporta le seguenti funzionalità :

  • Tutti i livelli di QoS del protocollo MQTT;
  • Flag Clean Session alla connessione di un client;
  • Flag di Retained Message;
  • Will Message con relativo QoS e topic;
  • Autorizzazione con username e password;
  • Sottoscrizione ai topic con wildcards;
  • Publish e subscribe mediante una “inflight queue”;

Tra le funzionalità non ancora supportate abbiamo :

  • Configurazione del broker da un file di configurazione;
  • Sicurezza basata su SSL/TLS;
  • Configurazione bridge (broker to broker);
  • Salvataggio permanente (es. database) delle sessioni, retained message e will message;

Il mio obiettivo è di supportare lo sviluppo di questo broker così come per la libreria M2Mqtt nella speranza che possa essere utilizzato e migliorato grazie alle vostre segnalazioni !

Per poterne seguire l’evoluzione è possibile utilizzare anche la relativa pagina Facebook ed account Twitter.

Page 6 of 42 << < 1 2 3 4 5 6 7 8 9 10 20 40 > >>