Partizione nascosta visibile solo se abilitata, Sicurezza in caso di spegnimento, Protezione da utilizzatori esterni
SCOPRIIl progetto consiste nella realizzazione di un prototipo di una scheda SD la cui principale caratteristica è quella di avere una partizione di memoria accessibile dall'utente mediante un dispositivo abilitante univoco
che permette l'accesso a tale zona in modo esclusivo.
Pertanto, solo l'utente che dispone del dispositivo abilitante è in grado effettuare operazioni di lettura/scrittura su tale partizione.
Per fornire un maggior livello di sicurezza, la partizione di memoria nascosta viene disabilitata ad ogni spegnimento del dispositivo ospitante la scheda.
Dunque, per avere nuovamente accesso alla zona protetta risulta necessario estrarre la scheda dal dispositivo di utilizzo ed inserirla nel dispositivo abilitante.
Una volta abilitata, sarà possibile inserire la scheda nuovamente nell'utilizzatore.
Il prototipo è stato realizzato in linguaggio VHDL per una possibile implementazione su FPGA.
Il sito ha la seguente struttura:
La partizione di memoria nascosta è accessibile solo dopo la fase di abilitazione.
Ad ogni spegnimento la partizione nascosta viene disabilitata riportando la scheda al suo utilizzo nella zona liberamente visibile.
Il dispositivo abilitante è unico permettendo l'abilitazione della partizione solamente agli utenti che lo possiedono.
Il progetto si compone di una entity principale che realizza il prototipo della scheda SD, la quale include un'interfaccia e una zona di memoria.
Verranno introdotte brevemente le parti principali di una scheda SD.
Spiegazione relativa al progetto dell'interfaccia di sistema verso il dispositivo ospitante e della memoria.
Implementazione di un dispositivo per l'abilitazione della partizione nascosta.
La Secure Digital (SD) è un formato di schede di memoria non volatili introdotto dalla SD Association (SDA), il cui scopo è quello di memorizzare in formato digitale un quantitativo di informazioni all’interno di memorie di tipo flash. Lo standard relativo alle memorie SD è stato introdotto nell’agosto del 1999 tramite una collaborazione tra Sandisk, Panasonic e Toshiba ponendo come obiettivo il miglioramento rispetto alle precedenti memorie MultiMediaCard (MMC). Il prototipo implementato in questo progetto è stato realizzato implementando principalmente due blocchi:
La seguente immagine rappresenta lo schema a blocchi relativo al prototipo di scheda SD implementata in cui internamente ad essa si possono notare i due blocchi principali che la compongono.
Tipicamente, le schede SD sono dotate di memorie di tipo flash che sono memorie a stato solido di tipo non volatile e sono caratterizzate da un’elevata portabilità e una buona capacità di salvataggio dei dati. In questo prototipo è stata realizzata una memoria RAM composta da 256 righe ciascuna da 32 bit in modo da semplificare il progetto dal momento che la memoria flash di cui dispone la FPGA utilizza un complesso protocollo di comunicazione e in caso di malfunzionamenti è possibile danneggiare le celle di memoria. Per simulare la persistenza della memoria viene effettuato il salvataggio su file di testo dei dati contenuti all’interno della memoria ad ogni cambio di stato delle celle. All'interno di tale file, i dati contenuti nella memoria vengono salvati seguendo l'ordine crescente degli indirizzi. Ad ogni riavvio della scheda, il contenuto della memoria viene ripristinato ricaricando i dati dal file alla RAM. La regione di memoria nascosta viene indicizzata fissando ad un valore diverso da 0 i due bit più significativi dell'indirizzo di memoria. Quando tale regione non risulta essere abilitata, i due bit più significativi vengono forzati a 0 in modo tale da non permetterne l'accesso.
L’interfaccia è il componente della scheda SD che si occupa di gestire i segnali provenienti dal master (dispositivo che monta la scheda) verso la sezione di gestione della memoria e viceversa.
Essa è composta da sei segnali che si interfacciano con il mondo esterno e sei segnali che si interfacciano con la memoria vera e propria.
Oltre ai contatti di alimentazione, i quali non sono presenti a livello di descrizione dell’hardware in VHDL, la pedinatura della scheda si compone dei seguenti segnali, tutti di tipologia std_logic e dunque segnali a singolo bit:
Una volta inserita la scheda all’interno del dispositivo host, vengono effettuate alcune operazioni preliminari per poi entrare in una modalità di attesa di qualche comando riconosciuto:
Le tre operazioni vengono fatte in modo concorrente. La prima fase (lettura del flag per l’abilitazione della partizione nascosta) si occupa di capire se l’utilizzo della zona di memoria in oggetto è permesso o meno, andando a leggere il contenuto di una speciale cella di memoria la quale, se ad un valore logico alto, indica che la partizione nascosta della scheda SD è stata abilitata. Tale valore viene copiato in un flag interno alla scheda per un successivo utilizzo nelle fasi di lettura/scrittura e il valore della cella di memoria viene resettato di modo che, ad un successivo boot, la zona nascosta non risulti abilitata a meno di un preventivo inserimento della scheda nel dispositivo abilitante.
La seconda fase (inizializzazione della macchina a stati per la ricezione dei comandi) non fa altro che inizializzare la macchina a stati che si occupa della comprensione dei comandi impartiti dal master ad uno stato di idle, in cui attende che l’elaborazione venga abilitata alzando il valore logico del segnale enable.
L’ultima fase si occupa di capire se, al momento dell’accensione della scheda, il dispositivo master è il dispositivo abilitante. In tale occasione, una volta avvenuto il riconoscimento del dispositivo, viene forzato ad un valore alto il flag relativo all’abilitazione della regione nascosta e la scheda viene espulsa per un successivo utilizzo.
La zona di memoria è suddivisa in due parti: la parte visibile a tutti gli utilizzatori della scheda SD e la parte nascosta, accessibile solamente dopo aver abilitato la scheda inserendola nell’apposito dispositivo abilitante. Le schede SD solitamente montano al loro interno una memoria di tipo flash non volatile. In questo progetto, tale memoria viene simulata sintetizzando un banco di memoria RAM composta da 256 parole da 32 bit l’una e la persistenza dei dati viene ottenuta effettuando un salvataggio su file di testo dell’intera memoria ad ogni operazione di scrittura. La memoria è dunque indirizzabile tramite un indirizzo a 8 bit dove i due bit più significativi possono essere forzati o meno, a seconda che si stia lavorando su una scheda la quale partizione nascosta è abilitata o meno. Uno schema generale della struttura della memoria è rappresentato dalla seguente immagine:
A livello di sintesi VHDL, il blocco rappresentante la memoria è composto da cinque segnali in ingresso e due segnali in uscita. Il segnale address è un bus a 8 bit mentre data_in è un bus a 32 bit. Una volta che la memoria ha effettuato l’operazione, ne segnala il successo ponendo ad un valore logico alto il segnale ready e immettendo i dati (in caso di lettura) sul bus data_out, anch’esso da 32 bit. Internamente, a livello di simulazione della persistenza dei dati, ad ogni scrittura viene salvato l’intero contenuto della memoria su un file di testo il quale viene importato ad ogni nuovo avvio della scheda.
Come evidenziato in precedenza, il funzionamento dell’interfaccia e dunque dell’intero sistema, si basa su una macchina a stati che si occupa della comprensione dei comandi impartiti dal dispositivo master. Tali comandi devono dunque aderire ad un protocollo di comunicazione che descrive le informazioni da immettere sui segnali in ingresso alla scheda in relazione all’istruzione che si vuole eseguire. Il protocollo scelto implementa una versione semplificata del protocollo SPI utilizzato per l’interfaccia con memorie di tipo flash presenti nella maggior parte dei dispositivi a memorie non volatili. Esso prevede l’utilizzo di tre segnali:
L’andamento dei segnali in questa prima fase è il seguente:
Una volta alzato il segnale enable, sul segnale cmd_in inizia la comunicazione del comando da eseguire inserendo un bit che discrimina un’operazione di lettura o scrittura, seguito dallo stream seriale dei bit rappresentanti l’indirizzo di memoria in cui leggere/scrivere dei dati. Nel caso si trattasse di una operazione di scrittura, al termine dell’inserimento dell’indirizzo in cui scrivere, sul segnale data inizia la trasmissione dei bit da salvare nella posizione indicata.
I bit rappresentanti l’indirizzo e i dati da salvare devono essere inseriti sui bus in ingresso alla memoria e dunque, l’interfaccia si occupa anche della de-serializzazione dei bit tramite un registro SIPO per fornire i dati sui bus address e data_in della memoria in modo parallelo.
Nel caso in cui il flag di accesso alla zona di memoria nascosta sia disattivato, i due bit più significativi dell’indirizzo su cui effettuare l’operazione indicata vengono forzati a 0 prima di inserirli sul bus opportuno della memoria, in modo da obbligare il dispositivo a lavorare esclusivamente nella partizione libera senza alcuna possibilità di intervenire sull’indirizzo. L’utilizzatore non si accorgerà di nulla in quanto l’operazione verrà portata a buon fine su un indirizzo diverso da quello specificato, come è possibile notare dalla seguente immagine. Infatti, l’utilizzatore della scheda effettua una richiesta di scrittura con successiva lettura allo stesso indirizzo, il quale appartiene alla zona di memoria nascosta. Tale indirizzo viene dunque modificato ma, a monte della scheda, l’operazione sembra essere comunque stata effettuata all’indirizzo specificato.
Nel caso di una lettura, la memoria fornirà sul suo bus data_out la stringa di 32 bit presente all’indirizzo indicato. Dunque, l’interfaccia si occupa anche della serializzazione dei dati provenienti dalla memoria tramite un registro PISO per porli poi in uscita sul segnale data. L’utilizzatore della scheda dovrà dunque utilizzare quest’ultimo segnale sia come ingresso (per inserire i dati da scrivere ad un determinato indirizzo) sia come uscita (per leggere i dati ritrovati all’indirizzo specificato).
Tutte queste operazioni vengono descritte tramite una macchina a stati il quale diagramma di transizione è visualizzabile nella seguente figura:
E’ composta da 17 stati e la radice è lo stato di IDLE, nel quale il dispositivo rimane in congelamento nell’attesa che una operazione venga specificata. Appena il segnale enable diventa alto, l’elaborazione ha inizio. Ogni stato effettua delle precise operazioni. La prima parte di transizioni si concentra nel discriminare il comando impartito (lettura o scrittura) e la lettura del flag di abilitazione della memoria per capire se è necessario oscurare la partizione nascosta o renderla fisicamente indirizzabile. La seguente tabella dimostra la discriminazione dell’istruzione a seconda del valore dei segnali interessati:
reg_enable | cmd_in (r/w) | azione da eseguire | stato di arrivo |
---|---|---|---|
1 | 1 | Scrittura con zona proibita abilitata | WRITE_HIDDEN |
1 | 0 | Lettura con zona proibita abilitata |
READ_HIDDEN |
0 | 1 | Scrittura con zona proibita NON abilitata | WRITE_CLEAR |
0 | 0 | Lettura con zona proibita NON abilitata | READ_CLEAR |
Negli stati di arrivo, viene letto l’indirizzo al quale effettuare l’azione indicata e viene posto su un segnale a 8 bit che si interfaccia con la memoria. Nel caso di scritture, si passa allo stato SET_DATA il quale si occupa di leggere i 32 bit dei dati da scrivere in memoria e disporli su un bus della stessa lunghezza. A questo punto, la transizione prosegue nello stato WAIT_FOR_MEMORY_W dove viene abilitata la memoria per l’esecuzione dell’operazione. L’interfaccia rimane in attesa della corretta scrittura da parte della memoria ascoltando il relativo segnale di ready. Una volta che tale segnale diventa alto, la memoria ha terminato l’operazione e l’interfaccia si pone nuovamente nello stato di IDLE in attesa di una successiva operazione. Nel caso di letture invece, dagli stati specificati in tabella si giunge nello stato WAIT_FOR_MEM_R nel quale si attende che la memoria finisca l’operazione di lettura e fornisca i dati sul suo bus di uscita. A questo punto si passa allo stato PISO il quale si occupa di serializzare i dati arrivati dalla memoria e porli, un bit alla volta, sul pin data della scheda. Alla fine di questa operazione, la macchina a stati converge nello stato IDLE.
Il dispositivo abilitante è necessario per rendere utilizzabile la partizione di memoria nascosta. Il suo funzionamento si basa sull'utilizzo di una sequenza a 10 bit univoca pari a "1011111101" che, una volta riconosciuta dalla scheda SD collegata, permette la modifica dello stato del flag che indica l'abilitazione della zona nascosta. In particolare, tale flag viene posto a '1'. Al successivo avvio della scheda, pertanto, la partizione nascosta della memoria risulterà abilitata.
Nella seguente immagine, è possibile visualizzare la struttura del blocco relativo all'abilitatore il quale dispone di tre segnali di uscita:
Dal lato della scheda SD, la sequenza viene validata da una macchina a stati: se la sequenza risulta essere corretta, il dispostivo viene abilitato; altrimenti la macchina a stati fornisce un errore e la abilitazione non va a buon fine. La seguente immagine mostra il diagramma di transizione degli stati della FSM interna all'interfaccia che svolge quanto spiegato precedentemente.
In questa sezione vengono riportati i codici VHDL che implementato i vari moduli e il testbench finale per la simulazione del sistema.
L'obiettivo della simulazione è quello di verificare il corretto funzionamento dei singoli componenti e del dispositivo nella sua totalità. L'architettura del testbench è composta dal componente SD il quale viene collegato o al dispositivo abilitante oppure ad un generatore di segnali mediante un multiplexer secondo il seguente schema a blocchi.
Tramite il comando Cmd è possibile scegliere se utilizzare il dispositivo abilitante oppure il generatore di segnali.
La simulazione parte dal generatore di segnali, il quale effettua delle scritture in determinati indirizzi. Dal momento in cui la scheda SD è stata riavviata, la partizione nascosta risulta essere disabilitata e dunque tali scritture vengono eseguite nella zona visibile. Successivamente vengono effettuate delle letture nei medesimi indirizzi per verificare la corretta procedura di scrittura dei dati.
La seconda fase della simulazione consiste nel collegare, tramite il mux, il dispostivo abilitante per abilitare la partizione nascosta. Passato il periodo necessario per il riconoscimento del dispostivo abilitante, esso viene scollegato e la scheda SD viene ricollegata al generatore di segnali. Come test di corretto funzionamento vengono effettuate nuovamente delle letture agli stessi indirizzi sui quali sono state effettuate le precedenti scritture. I dati ottenuti dalle letture non saranno uguali ai precedenti nel caso in cui i due bit più significativi dell'indirizzo di memoria siano diversi da 0.
La seguente tabella mostra i dati salvati e gli indirizzi associati durante la fase di scrittura della zona libera.
Indirizzo | Dato |
---|---|
00000000 | 11111111111111111111111111111111 |
00001111 | 10101010101010101010101010101010 |
11110000 | 11111111111111110000000000000000 |
11111111 | 00000000000000001111111111111111 |
Il seguente video mostra la fase di simulazione della scheda SD in cui vengono sottolineate le fasi di lettura e scrittura nella sezione libera e nella partizione nascosta.
Si può notare che, la lettura negli ultimi due indirizzi produce il ritrovamento di un dato diverso rispetto a quello scritto in quanto la scrittura viene effettuata nella partizione libera mentre l'operazione di lettura avviene nella partizione nascosta. Dunque, il risultato dipenderà dal valore presente in memoria a quelle locazioni.
La difficoltà principale è stata riscontrata nell'individuazione dei blocchi componenti la scheda SD e il protocollo da loro utilizzato per una sua semplificazione
mantenendolo comunque fedele all'interfaccia fisica di una scheda SD.
Inoltre, durante la scrittura del codice VHDL si sono verificate alcune situazioni di incompatibilità tra i segnali che sono stati risolti tramite un'attenta analisi delle
fasi di transizione dei segnali.
In futuro il prototipo potrà essere caricato su una FPGA per verificare il corretto funzionamento, ottenuto tramite la simulazione, direttamente su hardware.
A tal proposito risulterebbe necessaria l'implementazione del protocollo SPI per l'interfacciamento del prototipo con una memoria di tipo flash in quanto la persistenza della memoria
simulata non risulta sintetizzabile.