
Strumento automatizzato di fuzzing differenziale per software crittografico che rileva errori di implementazione, fallimenti di conformità e perdite da canali laterali attraverso test intelligenti e parallelizzati su più linguaggi e piattaforme.
CDF è uno strumento per testare automaticamente la correttezza e la sicurezza del software crittografico. CDF può rilevare errori di implementazione, non conformità, perdite di canali laterali e così via.
CDF implementa una combinazione di test unitari con "fuzzing differenziale", un approccio che confronta il comportamento di diverse implementazioni delle stesse primitive quando vengono alimentate con casi limite e valori che massimizzano la copertura del codice.
A differenza dei fuzzer generici e dei software di test, CDF è:
Intelligente: CDF conosce il tipo di algoritmo che sta testando e si adatta alle funzioni testate
Veloce: CDF testa solo ciò che deve essere testato e parallelizza i suoi test il più possibile
Polivalente: CDF non è specifico per nessun linguaggio o API, ma supporta programmi o script eseguibili arbitrari
Portabile: CDF funzionerà su qualsiasi piattaforma Unix o Windows, essendo scritto in Go senza dipendenze specifiche della piattaforma
Lo scopo di CDF è fornire uno strumento di testing più efficiente a sviluppatori e ricercatori di sicurezza, essendo più efficace dei vettori di test e più economico della verifica formale manuale.
CDF è stato presentato per la prima volta al Black Hat USA 2017. Puoi visualizzare le diapositive della nostra presentazione, che contengono informazioni generali sulla logica alla base e sul design di CDF.
CDF è codificato in Go, la versione corrente è stata sviluppata utilizzando Go 1.8. Non ha dipendenze al di fuori della libreria standard di Go.
Tuttavia, forniamo programmi di esempio da testare utilizzando CDF, che sono in C, Python, C++, Java e Go e richiedono librerie crittografiche specifiche per essere eseguiti. Attualmente le librerie richieste sono:
make compilerà il binario cdf.
Un gruppo di programmi di esempio è disponibile in example: make examples-all compilerà tutti gli esempi, mentre make examples-go compilerà solo gli esempi Go.
make test eseguirà i test unitari (di CDF).
Per iniziare potresti voler visualizzare le informazioni di utilizzo eseguendo cdf -h.
Puoi quindi provare un esempio come l'interfaccia rsaenc contro gli esempi RSA OAEP Go e CryptoPP. Considerando CryptoPP come riferimento, puoi testare l'implementazione Go facendo:
cdf rsaenc /examples/oaep_rsa2048_go /examples/oaep_rsa2048_cryptopp
Questo comando eseguirà vari test specifici per l'interfaccia rsaenc.
In questo esempio, CDF dovrebbe lamentarsi della dimensione massima dell'esponente pubblico supportata dall'implementazione Go: se controlliamo il suo codice possiamo vedere che l'esponente pubblico è memorizzato come un normale intero, mentre in CryptoPP (e nella maggior parte delle altre implementazioni) è memorizzato come un intero grande. Questo è tuttavia per design e probabilmente non verrà modificato.
I parametri sono definiti in config.json.
La maggior parte dei parametri è autoesplicativa. Potresti voler impostare altre chiavi private per rsaenc e ecdsa (queste interfacce vengono testate con chiavi fisse, sebbene alcuni parametri delle chiavi, come gli esponenti, vengano modificati in alcuni test).
Il parametro seed ti permette di cambiare il seme utilizzato nei generatori pseudo-casuali di CDF. (Tuttavia, il programma testato potrebbe utilizzare un PRNG seminato diversamente, come negli esempi OAEP.) Il parametro concurrency ti permette di impostare il numero di goroutine concorrenti che CDF dovrebbe generare quando fork i programmi. Nota che è meglio mantenere questo numero al di sotto del numero reale di core. Il parametro verboseLog, se impostato su true, scriverà tutti gli input e output dei programmi, anche per i test riusciti, in un file log.txt.
Per testare il tuo software utilizzando CDF, devi creare un programma che legga input e scriva output in conformità con le interfacce CDF, e che internamente chiami il programma testato. Le interfacce CDF sono astrazioni di una funzionalità crittografica, per consentire il test black-box di implementazioni arbitrarie.
Ad esempio, se hai implementato lo schema di firma ECDSA, il tuo programma deve soddisfare l'interfaccia ecdsa e come tale accettare come input 4 o 5 argomenti, rispettivamente per firmare un messaggio o verificare una firma. Questi argomenti sono la coordinata X pubblica, la coordinata Y pubblica, il grande intero D privato e il messaggio che vuoi firmare, e poi deve produrre in output solo i grandi interi R e S ciascuno su una nuova riga. Oppure, per verificare un messaggio, deve accettare X, Y, R, S e il messaggio e poi produrre solo True o False. Le specifiche delle interfacce sono dettagliate di seguito.
I nostri esempi di implementazioni di interfacce ti aiuteranno a crearne di tue.
La gestione degli errori è lasciata al programma testato, tuttavia per avere errori significativi in CDF è meglio uscire in caso di fallimento, restituire un codice di errore e stampare un messaggio di errore.
Il programma dell'interfaccia può essere scritto in qualsiasi linguaggio, deve solo essere un file eseguibile conforme a un'interfaccia CDF. Un programma di interfaccia è tipicamente scritto nello stesso linguaggio del programma testato, ma non è obbligatorio (può essere un wrapper in un altro linguaggio, ad esempio per programmi Java).
CDF attualmente supporta le seguenti interfacce, in cui i parametri sono codificati come stringhe ASCII esadecimali, salvo diversa indicazione:
L'interfaccia dsa testa implementazioni del Digital Signature Algorithm (DSA). Deve supportare le operazioni di firma e verifica:
| Operazione | Input | Output |
|---|---|---|
| Firma | p q g y x m | r s |
| Verifica | p q g y r s m | valore di verità |
Qui p, q, g sono parametri DSA, y è una chiave pubblica, x è una chiave privata, m è un messaggio, r e s formano la firma, che deve essere restituita separata da una nuova riga. Il valore di verità, "true" o "false", è rappresentato come una stringa.
L'interfaccia dsa supporta un test opzionale: -h consente di bypassare il processo di hashing e fornire direttamente il valore hash da firmare. Questo permette a CDF di eseguire più test, come la verifica di overflow o troncamento dell'hash.
L'interfaccia ecdsa testa implementazioni dell'Elliptic Curve Digital Signature Algorithm (ECDSA). Deve supportare le operazioni di firma e verifica:
| Operazione | Input | Output |
|---|---|---|
| Firma | x y d m | r s |
| Verifica | x y r s m | valore di verità |
Qui x e y sono le coordinate di una chiave pubblica ECDSA, d è una chiave privata, m è un messaggio, e r e s formano la firma, che deve essere restituita separata da una nuova riga. Il valore di verità, "true" o "false", è rappresentato da una stringa.
Il flag -h serve allo stesso scopo di dsa.
Si prega di notare che il nostro design attuale assume una curva fissa, definita nel programma testato.
Per ottenere risultati riproducibili con questi test e sfruttare tutte le capacità di rilevamento di CDF, devi seminare il tuo generatore casuale con un seme fisso o utilizzare una variante ECDSA deterministica, altrimenti CDF non può rilevare automaticamente problemi come problemi di tag identici.
L'interfaccia enc testa operazioni di crittografia e decrittografia simmetrica, tipicamente eseguite con un cifrario a blocchi (i cifrari a flusso possono essere testati con l'interfaccia prf). Deve supportare crittografia e decrittografia:
| Operazione | Input | Output |
|---|---|---|
| Crittografia | k m | c |
| Decrittografia | k c | r |
Qui k è una chiave, m è un messaggio, c è un testo cifrato e r è un testo in chiaro recuperato.
L'interfaccia prf testa hashing con chiave (funzioni pseudocasuali, MAC), così come cifrari a flusso:
| Operazione | Input | Output |
|---|---|---|
| Calcolo | k m | h |
Qui k è una chiave, m è un messaggio (o nonce nel caso di un cifrario a flusso), e h è il risultato del calcolo PRF. La nostra interfaccia assume una dimensione fissa della chiave e lunghezze variabili dell'input. Se deve essere specificata una chiave particolare, è responsabilità del programma testato ignorare l'input della chiave o l'interfaccia xof potrebbe essere una scelta migliore.
L'interfaccia rsaenc testa la crittografia e decrittografia RSA, sia OAEP (PKCS 2.1) che PKCS 1.5:
| Operazione | Input | Output |
|---|---|---|
| Crittografia | n e m | c |
| Decrittografia | p q e d c | r |
Qui n è un modulo, e è un esponente pubblico (per compatibilità con alcune librerie, e è necessario anche per la decrittografia), m è un messaggio, p e q sono i fattori di n (tali che p > q, poiché le librerie comunemente lo richiedono), d è un esponente privato, e r è un testo in chiaro recuperato.
L'interfaccia xof testa funzioni hash, funzioni a output estendibile (XOF), generatori di bit casuali deterministici (DRBG):
| Operazione | Input | Output |
|---|---|---|
| Calcolo | m | h |
Qui m è il messaggio e h è il risultato.
CDF si basa su idee iniziali di JP Aumasson, divulgate per la prima volta al WarCon 2016, e la maggior parte del codice è stata scritta da Yolan Romailler.
CDF è copyright (c) 2016-2017 Nagravision SA, tutti i diritti riservati.
CDF è rilasciato sotto GPLv3.