Bootloader DES per AVR

L’articolo affronta il problema dell’implementazione di applicazioni cifrate secondo l’algoritmo DES su piattaforme AVR.

Il DES è un algoritmo di crittazione adottato per la prima volta dal governo americano nel 1977: si tratta di un sistema di cifratura che trasforma blocchi di dati di 64 bits mediante una serie di sostituzioni e di scambi in cui intervengono una o più chiavi di 56 bits. Nonostante l’età esso è ancora ampiamente utilizzato in tutte quelle applicazioni che non richiedono margini di sicurezza troppo elevati, dal momento che hardware specializzato potrebbe violare il sistema in tempi dell’ordine di giorni o settimane (anche se un’evoluzione del DES originario, il 3DES, è virtualmente inattaccabile).

Nel mondo dell’elettronica consumer la cifratura di dati e files è pratica diffusa soprattutto per la protezione di firmware dedicato a piattaforme a microcontrollore: spesso, infatti, il firmware necessita di interventi di upgrade che possono comportare accessi non autorizzati ad esso da parte di terze parti estranee al produttore (vedi l’adozione illecita di tecniche di reverseengineering per risalire ai dettagli costitutivi di una particolare architettura). E’ dunque comprensibile la duplice esigenza di disporre da un lato di micro in grado di gestire in sicurezza eventuali aggiornamenti di software, e dall’altro di sistemi di crittografia del software stesso, per consentirne una diffusione sicura verso la piattaforma target. Il primo di questi obiettivi è raggiungibile mediante l’implementazione nei microcontrollori di bootloader specializzati nella ricezione di firmware crittato, nella sua successiva decrittazione e nella scrittura del codice nelle aree di memoria opportune; il secondo si centra facendo ricorso agli algoritmi di crittografia, di cui il DES è uno dei più potenti e affidabili. La figura 1 riporta uno schema di come avviene il processo di produzione e successivo upgrade di software crittato per la piattaforma AVR; il micro che necessita di protezione viene fornito di bootloader, chiavi di decrittazione e programma  applicativo originale.

Figura 1: schema del processo di produzione e upgrade di software per le piattaforme AVR.

Figura 1: schema del processo di produzione e upgrade di software per le piattaforme AVR.

Il bootloader si occupa del trasferimento del firmware nella Flash memory del microcontrollore, mentre le chiavi sono necessarie per i successivi aggiornamenti  tramite software criptato; opportuni lock bits vengono settati in modo da evitare la cancellazione o la lettura del codice. Dopo la distribuzione sul mercato, un eventuale aggiornamento di firmware avviene con una cifratura del software e un successivo rilascio ai distributori: a questo punto accessi privi di autorizzazione a tale software sono inutili se non si dispone delle chiavi di decrittazione. La nuova release potrà così essere trasferita nel micro e solo all’interno di esso avverrà il processo inverso di decifratura. Nel seguito dell’articolo sarà riportato un esempio di realizzazione di un bootloader per i micro AVR, dotato delle precedenti proprietà e saranno analizzate le sue caratteristiche strutturali; prima, però, si farà un rapido cenno al sistema DES.

Crittografia DES

La crittografia è la scienza di mantenere segreta dell’informazione ed è basata sul non rivelare il metodo crittografico usato o tenere nascosta la chiave utilizzata negli algoritmi di cifratura, i quali possono essere di dominio pubblico; il primo tipo di metodologia è ormai di interesse storico e non è più utilizzato in pratica; i moderni algoritmi crittografici utilizzano una o più chiavi per controllare sia il processo di crittazione sia quello inverso di decrittazione. Senza le chiavi è virtualmente impossibile risalire al testo originale. Nell’ambito della messa in sicurezza di firmware per microcontrollori, è possibile salvare le chiavi all’interno di un bootloader dedicato, in modo che il dispositivo sia in grado di ricevere  il codice cifrato, attuare il processo di decifrazione e riprogrammare parti selezionate della memoria Flash o EEPROM. Non è in alcun modo possibile risalire alle chiavi utilizzate attraverso i dati crittati o tramite il microcontrollore stesso, se questo è protetto da scrittura o lettura mediante alcuni lock bits. Gli algoritmi basati su chiavi si dividono in due grandi classi: simmetrici e asimmetrici. I primi usano la medesima chiave per entrambi i processi di cifratura e decifratura, mentre i secondi fanno ricorso a chiavi differenti.  Il DES è uno dei più studiati e impiegati algoritmi del primo tipo: sviluppato originariamente negli anni Settanta, divenne poi uno Standard per l’US National Institutes of Standards (NIST). Esso fa ricorso ad una chiave a 56 bit, per cui il numero delle possibili combinazioni di chiavi è 256,  ovvero circa 7.2x1016 . Più in dettaglio l’algoritmo opera su blocchi di 64 bits di dati: ogni file da criptare viene così suddiviso in frammenti di questa lunghezza e ciascun blocco in ingresso è processato come mostrato in figura 2.

Figura 2: diagramma semplificato dell’algoritmo DES.

Figura 2: diagramma semplificato dell’algoritmo DES.

Come si vede, nel diagramma entrano in gioco 16 parole o subkeys, chiamate K1…K16: esse sono ricavate dalla chiave a 56 bits iniziale dopo alcune operazioni che non consideriamo  (si tratta di aggiunta di 8 bits di parità alla chiave, di una permutazione del risultato, di una successiva suddivisione in due blocchi, di opportune operazioni di shift su questi ed infine di un’ulteriore permutazione per ottenere i 16 blocchi di 48 bits denominati  Ki). Il primo passo consiste nell’eseguire una certa permutazione  (P) sul blocco a 64 bits, dopo di che il risultato viene diviso in due metà: i primi 32 bits sono chiamati L[0], mentre gli ultimi R[0]; questi vengono processati separatamente secondo una certa funzione f che fa intervenire di volta in volta le 16 subkeys a cui si è accennato prima; questa f opera in modo non lineare sui blocchi R[i-1] e K[i] e costituisce il segreto della difficoltà nel forzare il sistema crittografico. L’output a 32 bits generato dalla f subisce poi un’operazione di XOR (OR esclusivo) con il blocco L[i-1] a dare il successivo R[i], mentre L[i] prenderà i valori precedenti di R[i-1]. Tutta questa serie di operazioni viene eseguita 16 volte fino ad ottenere R[16] e L[16]: combinando infine questi ultimi e permutandoli in modo inverso rispetto alla prima permutazione (P-1)  si ottiene il blocco a 64 bits cifrato. Come si è gia detto il DES è un algoritmo simmetrico, per cui l’operazione di decrittazione utilizza la medesima chiave, ovvero le stesse 16 subkeys, ma in ordine inverso rispetto alla cifratura (K16…K1). Il 3DES (Triple Data Encryption Standard) è un’evoluzione del DES che fa uso di 3 chiavi a 56 bits l’una, per un totale di 2168, ovvero 3.74x1050 possibili combinazioni di chiavi. Il corrispondente algoritmo di cifratura si ottiene applicando tre volte di seguito il DES, facendo intervenire le 3 chiavi come mostrato in figura 3.

Figura 3: diagramma della crittazione 3DES.

Figura 3: diagramma della crittazione 3DES.

La decrittazione procede in modo inverso, in accordo alla figura 4.

Figura 4: diagramma della decrittazione 3DES.

Figura 4: diagramma della decrittazione 3DES.

Come si è visto sia il DES che il 3DES operano su blocchi di dati di lunghezza fissa (64 bits): questo significa che, da un certo blocco di input (noto) e una chiave costante (ma sconosciuta), il blocco cifrato prodotto in output sarà sempre lo stesso; questo fatto si può rivelare utile per chi cerca di forzare l’algoritmo ed è pertanto potenzialmente pericoloso per la sicurezza di tutto il sistema. Per questo motivo sono stati elaborati diversi metodi, il cui scopo è quello di ottenere blocchi cifrati diversi pur partendo dai medesimi blocchi in input; uno di questi è il metodo CBC (Cipher Block Chaining), che attua un’operazione di XOR tra un certo blocco di dati del file originale, poniamo il blocco i, e il blocco cifrato precedente, ottenuto dal frammento i-1. In questo modo viene aumentato il numero dei bits del file originale da cui dipende ogni singolo bit del file cifrato (come si sarà probabilmente intuito c’è bisogno di un blocco iniziale o vettore di inizializzazione per iniziare la concatenazione dei vari frammenti). Anche se il tempo macchina richiesto in un eventuale attacco a forza bruta per violare il codice cresce in modo esponenziale con la lunghezza della chiave usata (con questo genere di attacchi si provano tutte le possibili combinazioni delle chiavi), non bisogna dimenticare, d’altra parte, che la potenza di calcolo cresce anch’essa esponenzialmente col tempo, per cui non basta solo fare affidamento alla chiave (hardware altamente specializzato sull’algoritmo DES è in grado di forzarlo nel giro di alcune ore); si rivelano così utili alcuni accorgimenti che possono rendere più complicata la vita ai crackers. Infatti il software usato da questi ultimi è spesso configurato in modo da rivelare quelle parti di codice che occupano zone di memoria facilmente prevedibili, come per esempio i vettori di interrupt all’inizio della memoria di programma; per questo motivo è cosa accorta inviare al bootloader i frammenti  cifrati in ordine casuale, in modo che un possibile attacco non vada a ricercare nei primi frammenti la tabella dei vettori (prevedibili) e quindi possa affinare le chiavi di ricerca; in ogni caso i frammenti decifrati saranno comunque mappati nelle posizioni di memoria corrette. Questo comunque non è sufficiente, poiché perfino eventuali segnali del tipo OK/NotOK derivanti dal bootloader in fase di decrittazione potrebbero essere utilizzati come segnali di feedback per potenziali forzature: tutte queste considerazioni, unitamente alla difficoltà tecnica di forzare l’algoritmo a forza bruta, dovrebbero costituire un possibile deterrente per coloro interessati allo spionaggio industriale ed indirizzare   i loro sforzi allo sviluppo di software originale.

Implementazione e uso del bootloader

La figura 5 mostra una visione d’insieme delle varie parti di cui si compone una possibile applicazione per:

- creare e configurare un bootloader specializzato per il DES, in grado di ricevere codice cifrato, decrittarlo e programmare le aree di memoria del micro destinate al firmware o alle chiavi;

- creare e crittare nuove releases del firmware.

Figura 5: diagramma a blocchi del progetto.

Figura 5: diagramma a blocchi del progetto.

I principali  passi di cui si compone l’applicazione sono i seguenti:

■  1-Creare il  sorgente del bootloader per la particolare piattaforma AVR (Application Note) ed eventualmente un layout dei dati riservati alla EEPROM (Miscellaneous Editor).

2-Creare un file di configurazione con dati riguardanti  il progetto (numero delle chiavi, dimensione delle pagine di memoria, vettore di inizializzazione  per il CBC…) (GenTemp).

3-Eseguire l’applicazione denominata Create per creare il file header, il key-file, e il file crittato.

■  4-Attraverso l’IAR EW creare l’eseguibile del bootloader, configurato tramite l’header e il key-file.

■  5-Trasferire il  bootloader all’inter no dell’AVR, impostare i lock e i fuse bits (Avr Studio).

■  6-Aggiornare il firmware con frames crittati (Update).

Vediamo di chiarire in maggior dettaglio alcuni di questi punti.

Configuration File

Il file di configurazione contiene una lista di parametri usati per configurare  il progetto: la dimensione in bytes della pagina di memoria dell’AVR, le tre chiavi in esadecimale (ma queste sono opzionali poiché si può eventualmente creare un bootloader senza la funzionalità DES), il vettore di inizializzazione per il CBC, la signature (4 bytes) di autenticazione dei frames in ricezione, la richiesta (Yes/No) del controllo CRC.

Un esempio di file di configurazione, potrebbe essere:

PAGE_SIZE       = 128

MEM_SIZE        = 14336

KEY1           = 0123456789ABCDEF KEY2 = FEDCBA9876543210

KEY3            = 67ABCDEFGH123458

INITIAL_VECTOR  = 0011223344556677

SIGNATURE    = 78ABEFIL ENABLE_CRC      = YES

A tale file può essere assegnato qualsiasi nome e questo sarà successivamente passato come parametro all’applicazione che creerà i files del progetto (Create). Alcuni di questi parametri non possono essere impostati senza conoscere in anticipo l’AVR cui il file è destinato, per cui essi andranno ricercati sul datasheet del micro.

PC Application-GenTemp

Si tratta di una piccola applicazione per PC che genererà un template del file di configurazione; essa assicura la creazione di tre chiavi random e del vettore di inizializzazione del CBC, lasciando gli altri parametri legati al micro al programmatore. L’applicazione si usa con il seguente comando:

GenTemp FileName.Ext

dove FileName è il nome che verrà assegnato al file. Quest’ultimo sarà comunque modificabile tramite qualunque editor.

PC Application-Create

Quest’applicazione legge le informazioni contenute nel file di configurazione e genera, alla prima esecuzione,  i files header e key per il bootloader; nelle esecuzioni successive essa serve per crittare il firmware. E’ importante che in tutte le esecuzioni essa faccia sempre riferimento allo stesso file di configurazione, altrimenti il bootloader non disporrà del corretto set di chiavi e non potrà decifrare il codice. Digitando dal prompt dei comandi la riga: Create –c Config.txt –h BootLdr.h –k DESKeys.inc vengono generati l’header e il key-file; questi vanno copiati nella directory assegnata dal progetto al sorgente del bootloader e poi inclusi nel codice di quest’ultimo tramite direttive #include. Alle esecuzioni successive si procederà alla cifratura del codice; prima, però, questo andrà compilato, assemblato e linkato in un segmento di file-codice o in un segmento di file-EEPROM (entrambi del tipo Intel hex). Digitando al prompt:

Create –c Config.txt –e EEPROM.hex –f

Flash.hex –o Update.enc –l BLB11

BLB12

il firmware (destinato alla memoria flash) e il file dei dati EEPROM saranno combinati in un unico file crittato chiamato Update.enc. Il parametro –c indica il path al file di configurazione, -e il path all’EEPROM file, -f il path al Flash-file, ovvero al codice che andrà nell’Application section della memoria del micro, -k è riservato al nome del key-file in output, -o è seguito dal nome del file crittato finale e –l è seguito dai lock bits che devono essere settati dopo che tutti i dati sono stati caricati nelle rispettive aree di memoria e prima che il controllo passi all’applicazione Update. La figura 6 mostra un flow-chart dell’applicazione Create.

Figura 6: flow-chart dell’applicazione Create.

Figura 6: flow-chart dell’applicazione Create.

Come si vede dal diagramma esistono varie opzioni, che rendono l’applicazione flessibile circa la scelta del numero di chiavi o la creazione o meno dei file header, key, EEPROM o addirittura del file di output. Se vengono scelte le alternative corrispondenti, i files Flash ed EEPROM sono organizzati e linkati in una serie di records, la cui struttura cambia a seconda dell’area di memoria cui sono destinati; ciascun record ha una formattazione che riporta l’indirizzo cui è destinato, oltre alla lunghezza in bytes dei dati da esso veicolati; esistono anche records che contengono l’informazione di quali lock bits settare, ed altri che segnano la fine dei frames o la fine della trasmissione dell’intero file. La figura 7 mostra più in dettaglio il processo di creazione del file criptato finale: dopo che i dati sono stati formattati nel modo appena visto (step 1), viene aggiunto un byte nullo per segnare il termine di tutti i frames ed altri bytes random in modo da avere un file la cui lunghezza finale in bit sia un multiplo pari di 64.

Figura 7: processo di creazione del file criptato.

Figura 7: processo di creazione del file criptato.

A questo punto (step 2) il vettore di inizializzazione CBC viene posto all’inizio del file in modo da poter iniziare  il processo di concatenazione e di crittaggio (step 3). Se è stata scelta l’opzione relativa, alla fine del frame viene aggiunto un byte contenente la checksum CRC-16 (Controllo di Ridondanza Ciclico) per correggere eventuali errori nella successiva trasmissione del file (step 4). Questa procedura è ripetuta finchè tutti i frames  sono stati elaborati e collegati insieme nel file criptato di output.

Bootloader

Il  bootloader va caricato nel micro prima che il dispositivo possa essere aggiornato con nuove releases di software; esso si occupa della comunicazione col PC durante la fase di trasferimento di nuovo file e programma la EEPROM o l’area applicativa della memoria Flash. La figura 8 mostra il flusso del software; come si può notare il  bootloader può funzionare in due modalità, selezionabili tramite uno switch della scheda di sviluppo in cui è inserito  il micro: se SW7 è nello stato Off, allora il bootloader passa subito il controllo al programma applicativo, dopo un eventuale check CRC, altrimenti esso inizia la comunicazione con il  PC, ponendosi in modalità Update.

Figura 8: diagramma di flusso del bootloader

Figura 8: diagramma di flusso del bootloader

Quest’ultima prevede il trasferimento  del file criptato, un frame alla volta: se il relativo controllo CRC ha dato esito positivo, allora inizia la fase di decrittazione e il processo inverso alla concatenazione CBC; se si è ottenuta una signature valida, allora i dati ricavati dal frame appena decrittato vengono indirizzati all’area di memoria che gli compete (Flash o EEPROM) o utilizzati per la funzione specifica codificata nella parte iniziale della struttura del frame stesso come si è accennato prima, nella parte iniziale della struttura del frame stesso (cancellazione o set-up di una pagina di memoria, impostazione dei lock-bits…). Alla ricezione del byte End of Frame si ripete il ciclo di decodifica per il frame successivo, sino alla fine del file; a questo punto un segnale di reset pone il bootloader nuovamente di fronte alla scelta delle due possibili modalità di funzionamento. Prima della fase di compilazione del bootloader, è necessario settare alcuni parametri; innanzitutto bisogna includere nel file sorgente i file header e key generati dall’applicazione Create, con le direttive:

#include “bootldr.h”

#include “deskeys.inc”

(i due files vanno ovviamente copiati prima nella stessa directory in cui risiede il sorgente del bootloader). E’ poi necessario impostare altre opzioni proprie del compilatore, tipo il  non generare codice per il debug o l’ottimizzare il  codice eseguibile per ridur ne il più possibile la dimensione (alcuni AVR hanno una Bootloader section di soli 2KB); dopo la compilazione e il download del bootloader all’interno del micro (con l’applicazione AVR Studio, per esempio), prima di eseguirlo bisogna sia configurare la dimensione della sezione di boot o Bootloader section (sempre dallo stesso ambiente Studio), che attivare il vettore di reset, cui è indirizzato  il bootloader quando passa in modalità standby come visto prima. E’ inoltre particolarmente importante configurare correttamente l’oscillatore di clock, poiché da questo dipendono i tempi previsti nella comunicazione seriale col PC durante ogni up-date. I lock bits da settare sono quelli relativi alla protezione della memoria: essi vietano la lettura o la scrittura indesiderata (tramite un’interfaccia ISP per esempio), sia della Bootloader che dell’Application sections.

Applicazione PC - Update

L’applicazione Update risiede sul PC e serve ad inviare il file crittato al dispositivo target. I dati possono essere trasmessi via seriale direttamente all’ USART del micro; la figura 9 illustra le varie parti del programma.

Figura 9: flusso dell’applicazione di trasmissione Update.

Figura 9: flusso dell’applicazione di trasmissione Update.

Dopo l’inizializzazione della porta usata per la trasmissione del file (e dopo aver controllato che questo effettivamente esiste!), esso viene caricato interamente in un buffer di lettura; un apposito puntatore effettua la scansione di tale buffer, permettendo così di risalire alla dimensione di ciascun frame e di inviarne i relativi bytes al micro; un segnale di feedback da parte del bootloader comunica all’applicazione la ricezione completa di un frame (in caso di mancata ricezione del segnale il programma  chiuderà la comunicazione e questa andrà resettata): entra a questo punto in gioco il controllo di ridondanza ciclico il cui esito positivo farà incrementare il valore del puntatore del buffer e l’invio del frame successivo. Quando il puntatore assumerà un valore superiore alla dimensione del file, verranno chiusi sia la comunicazione seriale che il file. La tabella di figura 10 illustra i  tempi medi richiesti al micro per ricevere, decrittare e scrivere  il file in memoria; essi dipendono ovviamente dalle dimensioni del file, dal baudrate della trasmissione seriale, dal clock del micro, dal numero di chiavi DES e dall’abilitazione o meno del controllo CRC: FS è la dimensione in bytes del file, BR è il baudrate ed f la frequenza di clock in Mhz.

Figura 10: tempi medi di elaborazione del file criptato.

Figura 10: tempi medi di elaborazione del file criptato.

La decrittazione richiede 245k cicli per blocco cifrato DES e 724k cicli per blocco 3DES: i valori tipici relativi ad un micro a 16 Mhz e una velocità di trasmissione di 115200 Bauds sono di 20 secondi per il DES e 50 secondi per il 3DES.

 

 

Scrivi un commento