API RLY Come cifrare i comandi da inviare in modalità Client

Guida per le API della RLY: Come cifrare i comandi da inviare alle RLY quando si trova in modalità Client

L’utente Juri ci ha chiesto come poter fare per inviare correttamente i comandi alla scheda relè con WiFi RLY-1601 quando quest’ultima si trova in modalità Client dato che i comandi devono essere criptati con l’algoritmo AES-128 prima dell’invio. Approfittiamo della richiesta per scrivere questo articolo di approfondimento. I concetti basilari, il listato dei comandi e i passi da compiere per utilizzare le API sono riportate nel manuale per programmatori scaricabile nella pagina del prodotto RLY-1601. In questo articolo verrà dato per scontato che l’utente abbia già letto il manuale.

Quando la RLY-1601 si trova in modalità Client tutti i comandi inviabili alla scheda devono essere cifrati utilizzando l’algoritmo AES-128 in modalità ECB (Electronic CodeBook). Se la board riceve un messaggio non cifrato o cifrato con una chiave (key) errata la richiesta viene rigettata e non viene eseguito nessun comando. Questo garantisce la massima sicurezza e l’impossibilità, per gli utenti che non conosco la chiave, di accedere alla board.

Quando la board riceve un comando cifrato con la key esatta la richiesta viene accettata ed il comando viene eseguito. A comando accettato la board invia un messaggio di conferma, anche questo cifrato con l’algoritmo AES-128, che dovrà essere decifrato per poterne capire il contenuto.

Il modo migliore per poter capire come avviene la procedura di cifratura dei comandi da inviare alla board e la decifratura delle risposte è facendo un semplice esempio.

Ipotizziamo di voler inviare alla board il comando NAME che, come illustrato nel Manuale per Programmatori, permette di ottenere come risposta il nome della board.

La stringa, in formato ASCII, da inviare via TCP/IP sulla porta 85 alla board è la seguente:

La stringa è rappresentata in formato ASCII. Utilizzando una tabella di conversione come questa è possibile convertire la stringa in un vettore di byte, ottenendo:

Per poter cifrare la stringa è necessario allungarla con caratteri dummy (casuali) in modo che la sua lunghezza sia esattamente di 16 caratteri o, pensando la stringa come ad un vettore di byte, di 16 byte.

E’ fondamentale che i caratteri usati per allungare la stringa da cifrare siano casuali e diversi ad ogni cifratura. Questo garantisce che medesimi comandi abbiano cifrature diverse ed elimina la possibilità, per un’attaccante, di utilizzare un attacco di brute force per determinare il comando inviato alla board.

Poichè questo è un concetto molto importante è bene chiarirlo meglio. Consideriamo di aggiungere al comando $N\r\n dodici zeri in modo da ottenere una stringa lunga esattamente 16 caratteri (16 byte):

Cifriamo la stringa con l’AES-128 in modo da ottenere un vettore di 16 byte, che chiamiamo A, ed inviamo tale vettore alla board. Ipotizziamo poi che per la nostra applicazione sia necessario inviare nuovamente il comando NAME alla board. Si potrebbe pensare di andare a fare quello che è già stato fatto al passo precedente ovvero, aggiungere dodici zeri al comando, effettuare la cifratura con l’AES e inviare il comando alla board. Oppure, ancora meglio, si potrebbe pensare di riutilizzare direttamente il vettore A in modo da liberare il processore dall’impegno di effettuare una nuova cifratura poiché il risultato sarebbe esattamente il medesimo ovvero otterremmo nuovamente il vettore A.

Procedere un questo modo sarebbe però completamente scorretto. Infatti se un attaccante (attacco Man in the Middle) osservasse i pacchetti scambiati tra la board e il device dell’utente, osserverebbe sempre il vettore A. E’ vero che l’attaccante non sa a quale comando corrisponde il vettore A ma alla lunga, non cambiando mai, potrebbe ricavarlo.

Il modo corretto di procedere sarebbe stato quello di aggiungere al comando $N\r\n un’altra serie ci caratteri diversi dai precedenti, ovvero da zero, di effettuare la cifratura di questa nuova stringa e di inviare quest’ultima alla board.

Chiarito questo concetto torniamo alla stringa allungata con zeri e formata da 16 caratteri (16 byte):

Utilizzamo un servizio on line come questo (che permette di scrivere anche in esadecimale il contenuto da cifrare) ed inseriamo in Input Text la stringa da cifrare mentre in Key la chiave da utilizzare per la cifratura (in questo esempio abbiamo usato la chiave: 0123456789123456 rappresentata in ASCII). Notare come sia in Input Text che in Key sia possibile scegliere se i dati inseriti siano rappresentati in plaintext (ASCII) o in hex (esadecimale). E’ possibile verificare come cambiando il modo di rappresentare la stringa il risultato non cambi.

cifratura-input-plain

Inserimento dati Plain Text

cifratura-input-hex

Inseriemento dati in esadecimale

risultato-cifratura

Risultato della cifratura

Il risultato fornito è un vettore di 16 byte. Tale vettore deve essere inviato alla board. L’invio alla board può essere eseguito in moltissimi modi sia realizzando un proprio software con il linguaggio di programmazione preferito sia sfruttando uno dei tanti software gratuiti che permettono l’invio di pacchetti TCP. Per questo esempio abbiamo utilizzato il software gratuito Packet Sender. Per inviare il pacchetto è sufficiente scrivere l’IP della board, la porta (85), il comando cifrato in esadecimale e premere su Send.

packetsender-comando-name

Dopo pochi attimi la board ci invierà la risposta che potremo vedere nel riquadro di log.

packetsender-risposta-name

Per decifrare la risposta è sufficiente copiare il vettore in esadecimale ed incollarlo nel riquadro di Input Text del servizio on line che abbiamo utilizzato per la cifratura e premere Decrypt!

decifratura

Adesso possiamo leggere la risposta in chiaro ovvero il nome della board: “ACE_1R0“.

Buona programmazione con le API della RLY-1601.

A presto!!!


Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *