it-swarm.dev

Lezioni apprese e idee sbagliate su crittografia e crittografia

La crittografia è un argomento così vasto che anche i programmatori esperti faranno quasi sempre errori le prime volte. Tuttavia, la crittografia è un argomento così importante, spesso non possiamo permetterci di avere questi errori.

L'intento di questa domanda è identificare ed elencare cosa fare not con un determinato algoritmo o API. In questo modo possiamo imparare dalle esperienze altrui e prevenire la diffusione di cattive pratiche.

Per mantenere costruttiva questa domanda, per favore

  1. Includi un esempio "sbagliato"
  2. Spiega cosa c'è che non va in quell'esempio
  3. Fornire un'implementazione corretta (se applicabile).
  4. Per quanto possibile, fornisci riferimenti relativi al n. 2 e al n. 3 sopra.
68

Non eseguire il rollup della tua crittografia.

Non inventare il proprio algoritmo o protocollo di crittografia; è estremamente soggetto a errori. Come piace dire a Bruce Schneier,

"Chiunque può inventare un algoritmo di crittografia che essi stessi non possono rompere; è molto più difficile inventarne uno che nessun altro può rompere".

Gli algoritmi Crypto sono molto intricati e necessitano di un controllo approfondito per essere sicuri; se inventi il ​​tuo, non lo capirai, ed è molto facile finire con qualcosa di insicuro senza rendersene conto.

Utilizzare invece un algoritmo e un protocollo crittografico standard. Le probabilità sono che qualcun altro abbia riscontrato il tuo problema in precedenza e abbia progettato un algoritmo appropriato a tale scopo.

Il tuo caso migliore è usare uno schema ben controllato di alto livello: per la sicurezza della comunicazione, usa TLS (o SSL); per i dati a riposo, utilizzare GPG (o PGP). Se non riesci a farlo, usa una libreria crittografica di alto livello, come cryptlib , GPGME, Keyczar o NaCL , invece di un uno di basso livello, come OpenSSL, CryptoAPI, JCE, ecc. Grazie a Nate Lawson per questo suggerimento.

76
D.W.

Non utilizzare la crittografia senza autenticazione dei messaggi

È un errore molto comune crittografare i dati senza autenticarli.

Esempio: lo sviluppatore desidera mantenere un messaggio segreto, quindi crittografa il messaggio con la modalità AES-CBC. Errore: questo non è sufficiente per la sicurezza in presenza di attacchi attivi, attacchi di risposta, attacchi di reazione, ecc. Esistono attacchi noti alla crittografia senza autenticazione dei messaggi e gli attacchi possono essere piuttosto gravi. La correzione è aggiungere l'autenticazione del messaggio.

Questo errore ha portato a gravi vulnerabilità nei sistemi distribuiti che utilizzavano la crittografia senza autenticazione, tra cui ASP.NET , XML crittografia , Amazon EC2 , JavaServer Faces, Ruby su rotaie, OWASP ESAPI , IPSEC , WEP , di nuovo ASP.NET e SSH2 Non vuoi essere il prossimo in questo elenco.

Per evitare questi problemi, è necessario utilizzare l'autenticazione dei messaggi ogni volta che si applica la crittografia. Hai due scelte su come farlo:

  • Probabilmente la soluzione più semplice è utilizzare uno schema di crittografia che fornisca crittografia autenticata , ad es. GCM, CWC, EAX, CCM, OCB. (Vedi anche: 1 .) Lo schema di crittografia autenticato lo gestisce per te, quindi non devi pensarci.

  • In alternativa, puoi applicare la tua autenticazione dei messaggi, come segue. Innanzitutto, crittografa il messaggio utilizzando uno schema di crittografia a chiave simmetrica appropriato (ad es. AES-CBC). Quindi, prendi l'intero testo cifrato (inclusi eventuali IV, nonces o altri valori necessari per la decrittazione), applica un codice di autenticazione del messaggio (ad es. AES-CMAC, SHA1-HMAC, SHA256-HMAC) e aggiungi il digest MAC risultante al testo cifrato prima della trasmissione. Sul lato ricevente, verificare che il digest MAC sia valido prima di decrittografare. Questa è conosciuta come la costruzione di crittografia e autenticazione. (Vedi anche: 1 , 2 .) Funziona bene, ma richiede un po 'più di cura da parte tua.

47
D.W.

Prestare attenzione quando si concatenano più stringhe, prima dell'hash.

A volte vedo un errore: le persone vogliono un hash delle stringhe S e T. Le concatenano per ottenere una singola stringa S || T, quindi l'hash per ottenere H (S || T). Questo è difettoso.

Il problema: la concatenazione lascia ambiguo il confine tra le due stringhe. Esempio: builtin || securely = built || insecurely. Detto in altro modo, l'hash H (S || T) non identifica in modo univoco la stringa S e T. Pertanto, l'attaccante potrebbe essere in grado di modificare il confine tra le due stringhe, senza modificare l'hash. Ad esempio, se Alice volesse inviare le due stringhe builtin e securely, l'attaccante potrebbe cambiarle in due stringhe built e insecurely senza invalidare il hash.

Problemi simili si applicano quando si applica una firma digitale o un codice di autenticazione dei messaggi a una concatenazione di stringhe.

La correzione: piuttosto che semplice concatenazione, utilizzare una codifica decodificabile in modo inequivocabile. Ad esempio, invece di calcolare H (S || T), è possibile calcolare H (lunghezza (S) || S || T), dove lunghezza (S) è un valore di 32 bit che indica la lunghezza di S in byte. Oppure, un'altra possibilità è utilizzare H (H (S) || H (T)) o persino H (H (S) || T).

Per un esempio reale di questo difetto, vedi questo difetto in Amazon Web Services o questo difetto in Flickr [pdf].

36
D.W.

Non riutilizzare nonces o IVs

Molte modalità operative richiedono un IV (vettore di inizializzazione). Non devi mai riutilizzare lo stesso valore per un IV due volte; ciò può annullare tutte le garanzie di sicurezza e causare una catastrofica violazione della sicurezza.

  • Per le modalità operative di cifratura stream, come la modalità CTR o OFB, il riutilizzo di un IV è un disastro di sicurezza. Può far sì che i messaggi crittografati siano banalmente recuperabili.

  • Per altre modalità operative, come la modalità CBC, il riutilizzo di un IV può anche facilitare in alcuni casi attacchi di recupero del testo in chiaro.

Indipendentemente dalla modalità di funzionamento che usi, non dovresti riutilizzare IV. Se ti stai chiedendo come farlo nel modo giusto, specifica NIST fornisce una documentazione dettagliata su come usare correttamente le modalità di funzionamento con cifratura a blocchi.

Il progetto Tarsnap fornisce un buon esempio di questa trappola. Tarsnap crittografa i dati di backup dividendoli in blocchi e quindi crittografando ogni blocco con AES in modalità CTR. Nelle versioni da 1.0.22 a 1.0.27 di Tarsnap, lo stesso IV è stato inavvertitamente riutilizzato, consentendo il recupero del testo in chiaro.

Come è successo? Al fine di semplificare il codice Tarsnap - e nella speranza di ridurre il potenziale di bug - Colin Percival ha colto l'occasione per "refactificare" il codice AES-CTR in un nuovo file (lib/crypto/crypto_aesctr.c nel codice sorgente di Tarsnap ) e modificato i luoghi esistenti in cui è stato utilizzato AES-CTR per trarre vantaggio da queste routine. Il nuovo codice è simile al seguente:

/* Crittografa i dati. */
 - aes_ctr (& encr_aes-> key, encr_aes-> nonce ++, buf, len, 
 - filebuf + CRYPTO_FILE_HLEN); 
 + if (((stream = 
 + crypto_aesctr_init (& encr_aes-> key, encr_aes-> nonce)) == NULL) 
 + goto err0; 
 + crypto_aesctr_stream (stream, buf, filebuf + CRYPTO_FILE_HLEN, len); 
 + crypto_aesctr_free (stream); 

Durante il refactoring, il encr_aes->nonce++ inavvertitamente è stato trasformato in encr_aes->nonce, e di conseguenza lo stesso valore nonce è stato utilizzato ripetutamente . In particolare, il valore nonce CTR non viene incrementato dopo la crittografia di ogni blocco. (Il contatore CTR viene incrementato correttamente dopo l'elaborazione di ogni 16 byte di dati, ma questo contatore viene azzerato per ogni nuovo blocco.) I dettagli completi sono descritti da Colin Percival in: http: //www.daemonology. net/blog/2011-01-18-Tarsnap-critical-sicurezza-bug.html

29
Alex Holst

Assicurati di seminare generatori di numeri casuali con abbastanza entropia.

Assicurati di usare generatori di numeri pseudocasuali cripto-intensi per cose come la generazione di chiavi, la scelta di IV/noncce, ecc. Non usare Rand(), random(), drand48() , eccetera.

Assicurati di seminare il generatore di numeri pseudocasuali con abbastanza entropia. Non seminarlo con l'ora del giorno; è indovinabile.

Esempi: srand(time(NULL)) è molto male. Un buon modo per seminare il tuo PRNG è quello di prendere 128 bit o numeri casuali, ad es. Da /dev/urandom, CryptGenRandom o simile. In Java, utilizzare SecureRandom, non Random. In .NET, utilizzare System.Security.Cryptography.RandomNumberGenerator, non System.Random. In Python, usa random.SystemRandom, non random. Grazie a Nate Lawson per alcuni esempi.

Esempio reale: vedi questo difetto nelle prime versioni del browser di Netscape , che ha permesso a un utente malintenzionato di violare SSL.

29
D.W.

Non utilizzare un codice a blocchi con BCE per la crittografia simmetrica

(Si applica ad AES, 3DES, ...)

Ecco un post e un molto simile articolo di Microsoft KB riguardo al modo in cui la modalità ECB genera codice non crittografato.

Vedi anche questo post simile da Rook

Messaggio di testo semplice:

alt text

Lo stesso messaggio crittografato con la modalità ECB (non importa quale cifra usi): alt text

Lo stesso messaggio EXACT usando la modalità CBC (di nuovo, non importa quale cifra usi): alt text

Il modo sbagliato

public static string Encrypt(string toEncrypt, string key, bool useHashing)
{

byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);

if (useHashing)
    keyArray = new MD5CryptoServiceProvider().ComputeHash(keyArray);

var tdes = new TripleDESCryptoServiceProvider() 
    { Key = keyArray, Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 };

ICryptoTransform cTransform = tdes.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(
    toEncryptArray, 0, toEncryptArray.Length);

return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}

L'errore è nella riga seguente

{Key = keyArray, Mode = CipherMode.ECB , Padding = PaddingMode.PKCS7};


La strada giusta

La brava gente di Microsoft mi ha inviato il seguente codice per correggere l'articolo KB collegato sopra. Questo è indicato nel caso # 111021973179005

Questo codice di esempio utilizza AES per crittografare i dati e la chiave per la crittografia AES è il codice hash generato da SHA256. AES è l'algoritmo Advanced Encryption Standard (AES). L'algoritmo AES si basa su permutazioni e sostituzioni. Le permutazioni sono riarrangiamenti di dati e le sostituzioni sostituiscono un'unità di dati con un'altra. AES esegue permutazioni e sostituzioni utilizzando diverse tecniche diverse. Per maggiori dettagli su AES, consultare l'articolo "Proteggi i tuoi dati con il nuovo standard di crittografia avanzata" su MSDN Magazine all'indirizzo http://msdn.Microsoft.com/en-us/magazine/cc164055.aspx .

SHA è l'algoritmo Secure Hash. SHA-2 (SHA-224, SHA-256, SHA-384, SHA-512) è ora raccomandato. Per informazioni più dettagliate sui valori hash in .NET Framework, fare riferimento a http://msdn.Microsoft.com/en-us/library/92f9ye3s.aspx#hash_values .

Il valore predefinito della modalità per il funzionamento dell'algoritmo simmetrico per AesCryptoServiceProvider è CBC. CBC è la modalità concatenamento del blocco di crittografia. Introduce feedback. Prima che ogni blocco di testo semplice venga crittografato, viene combinato con il testo di crittografia del blocco precedente mediante un'operazione OR esclusiva bit a bit. Ciò garantisce che anche se il testo in chiaro contiene molti blocchi identici, ciascuno di essi crittograferà in un blocco di testo diverso. Il vettore di inizializzazione viene combinato con il primo blocco di testo semplice mediante un'operazione esclusiva OR bit a bit prima che il blocco venga crittografato. Se un singolo bit del blocco di testo di cifratura è alterato, anche il corrispondente blocco di testo normale verrà alterato. Inoltre, un bit nel blocco successivo, nella stessa posizione del bit con angolo originale, verrà modificato. Per informazioni più dettagliate su CipherMode, fai riferimento a http://msdn.Microsoft.com/en-us/library/system.security.cryptography.ciphermode.aspx .

Ecco il codice di esempio.

// This function is used for encrypting the data with key and iv.
byte[] Encrypt(byte[] data, byte[] key, byte[] iv)
{
    // Create an AESCryptoProvider.
    using (var aesCryptoProvider = new AesCryptoServiceProvider())
    {
        // Initialize the AESCryptoProvider with key and iv.
        aesCryptoProvider.KeySize = key.Length * 8;
        aesCryptoProvider.IV = iv;
        aesCryptoProvider.Key = key;

        // Create encryptor from the AESCryptoProvider.
        using (ICryptoTransform encryptor = aesCryptoProvider.CreateEncryptor())
        {
            // Create memory stream to store the encrypted data.
            using (MemoryStream stream = new MemoryStream())
            {
                // Create a CryptoStream to encrypt the data.
                using (CryptoStream cryptoStream = new CryptoStream(stream, encryptor, CryptoStreamMode.Write))
                    // Encrypt the data.
                    cryptoStream.Write(data, 0, data.Length);

                // return the encrypted data.
                return stream.ToArray();
            }
        }
    }
}

// This function is used for decrypting the data with key and iv.
byte[] Decrypt(byte[] data, byte[] key, byte[] iv)
{
    // Create an AESCryptoServiceProvider.
    using (var aesCryptoProvider = new AesCryptoServiceProvider())
    {
        // Initialize the AESCryptoServiceProvier with key and iv.
        aesCryptoProvider.KeySize = key.Length * 8;
        aesCryptoProvider.IV = iv;
        aesCryptoProvider.Key = key;

        // Create decryptor from the AESCryptoServiceProvider.
        using (ICryptoTransform decryptor = aesCryptoProvider.CreateDecryptor())
        {
            // Create a memory stream including the encrypted data.
            using (MemoryStream stream = new MemoryStream(data))
            {
                // Create a CryptoStream to decrypt the encrypted data.
                using (CryptoStream cryptoStream = new CryptoStream(stream, decryptor, CryptoStreamMode.Read))
                {
                    // Create a byte buffer array.
                    byte[] readData = new byte[1024];
                    int readDataCount = 0;

                    // Create a memory stream to store the decrypted data.
                    using (MemoryStream resultStream = new MemoryStream())
                    {
                        do
                        {
                            // Decrypt the data and write the data into readData buffer array.
                           readDataCount = cryptoStream.Read(readData, 0, readData.Length);
                            // Write the decrypted data to resultStream.
                            resultStream.Write(readData, 0, readDataCount);
                        }
                        // Check whether there is any more encrypted data in stream.
                        while (readDataCount > 0);
                        // Return the decrypted data.
                        return resultStream.ToArray();
                    }
                }
            }
        }
    }
}



// This function is used for generating a valid key binary with UTF8 encoding and SHA256 hash algorithm.
byte[] GetKey(string key)
{
    // Create SHA256 hash algorithm class.
    using (SHA256Managed sha256 = new SHA256Managed())

    // Decode the string key to binary and compute the hash binary of the key.
    return sha256.ComputeHash(Encoding.UTF8.GetBytes(key));
}

Per maggiori dettagli sulle classi nel codice di esempio, fare riferimento ai seguenti collegamenti:

· AesCryptoServiceProvider Class

· SHA256Managed Class

· Classe CryptoStream

Inoltre, ci sono diversi articoli che possono aiutare a comprendere meglio la crittografia in .NET Framework, fare riferimento ai collegamenti seguenti:

· Servizi crittografici

· . NET Framework Cryptography Model

· na semplice guida alla crittografia

· Crittografia senza segreti

20

Non utilizzare la stessa chiave sia per la crittografia che per l'autenticazione. Non usare la stessa chiave per la crittografia e la firma.

Una chiave non deve essere riutilizzata per molteplici scopi; che può aprire vari attacchi sottili.

Ad esempio, se si dispone di una coppia di chiavi private/pubbliche RSA, non è necessario utilizzarle sia per la crittografia (crittografia con chiave pubblica, decrittografia con chiave privata) sia per la firma (firmare con la chiave privata, verificare con la chiave pubblica ): scegli un solo scopo e usalo solo per quello scopo. Se hai bisogno di entrambe le abilità, genera due coppie di chiavi, una per la firma e una per la crittografia/decrittografia.

Allo stesso modo, con la crittografia simmetrica, è necessario utilizzare una chiave per la crittografia e una chiave indipendente separata per l'autenticazione dei messaggi. Non riutilizzare la stessa chiave per entrambi gli scopi.

20
D.W.

Principio di Kerckhoffs: un sistema crittografico dovrebbe essere sicuro anche se tutto ciò che riguarda il sistema, tranne la chiave, è di dominio pubblico

Un esempio sbagliato: hash LANMAN

Gli hash di LANMAN sarebbero difficili da capire se nessuno conoscesse l'algoritmo, tuttavia, una volta che l'algoritmo era noto, ora è molto banale decifrare.

L'algoritmo è il seguente ( da wikipedia ):

  1. La password dell'utente ASCII viene convertita in maiuscolo.
  2. Questa password è riempita con null a 14 byte
  3. La password "a lunghezza fissa" è divisa in due metà di sette byte.
  4. Questi valori vengono utilizzati per creare due DES, una per ogni metà di 7 byte
  5. Ognuna delle due chiavi viene utilizzata per DES-crittografare la costante ASCII “KGS! @ # $%”, Risultante in due valori di testo cifrato a 8 byte.
  6. Questi due valori di testo cifrato sono concatenati per formare un valore di 16 byte, che è l'hash LM

Dato che ora conosci il testo cifrato di questi fatti, ora puoi facilmente suddividere il testo cifrato in due testi cifrati che sai essere in maiuscolo e che comportano un numero limitato di caratteri che potrebbe essere la password.

Un esempio corretto: Crittografia AES

  • Algoritmo noto
  • Bilance con tecnologia. Aumenta la dimensione della chiave quando hai bisogno di più grinta crittografica
17
Chris Dale

Cerca di evitare di usare le password come chiavi di crittografia.

Una debolezza comune in molti sistemi è l'uso di una password o passphrase, o un hash di una password o passphrase, come chiave di crittografia/decrittografia. Il problema è che questo tende ad essere altamente suscettibile agli attacchi offline di ricerca delle chiavi. La maggior parte degli utenti sceglie password che non dispongono di entropia sufficiente per resistere a tali attacchi.

La soluzione migliore è utilizzare una chiave di crittografia/decrittografia veramente casuale, non una generata in modo deterministico da una password/passphrase.

Tuttavia, se è necessario utilizzarne uno basato su una password/passphrase, utilizzare uno schema appropriato per rallentare la ricerca di chiavi esaustiva. Consiglio PBKDF2 , che utilizza l'hashing iterativo (sulla falsariga di H(H(H(....H(password)...)))) per rallentare la ricerca nel dizionario. Disporre di utilizzare un numero sufficiente di iterazioni per far sì che questo processo impieghi, diciamo, 100ms sul computer dell'utente per generare la chiave.

13
D.W.

In un protocollo crittografico: Rendi riconoscibili tutti i messaggi autenticati: non ci dovrebbero essere due messaggi uguali

Una generalizzazione/variante di:

  • Prestare attenzione quando si concatenano più stringhe, prima dell'hash.
  • Non riutilizzare le chiavi.
  • Non riutilizzare i nonci.

Durante una serie di protocolli crittografici è possibile scambiare molti messaggi che non possono essere contraffatti senza un segreto (chiave o nonce). Questi messaggi possono essere verificati dal destinatario perché conosce una chiave pubblica (firma) o perché solo lui e il mittente conoscono una chiave simmetrica o nonce. Questo si assicura che questi messaggi non siano stati modificati.

Ma questo non assicura che questi messaggi siano stati emessi durante la stessa esecuzione del protocollo: un avversario potrebbe aver catturato questi messaggi in precedenza, o durante un esecuzione simultanea del protocollo. Un avversario può avviare molte esecuzioni simultanee di un protocollo crittografico per acquisire messaggi validi e riutilizzarli non modificati.

Riesaminando abilmente i messaggi, potrebbe essere possibile attaccare un protocollo senza compromettere alcuna chiave primaria, senza attaccare alcun RNG, alcun cifratore, ecc.

Rendendo ogni messaggio autenticato del protocollo chiaramente distinto per il destinatario, le opportunità di riprodurre messaggi non modificati vengono ridotte (non eliminate).

13
curiousguy

Non utilizzare lunghezze di chiave non sicure.

Assicurati di utilizzare algoritmi con una chiave sufficientemente lunga.

Per la crittografia a chiave simmetrica, consiglierei almeno una chiave a 80 bit e, se possibile, una chiave a 128 bit è una buona idea. Non utilizzare la crittografia a 40 bit; è insicuro e facilmente distrutto dai dilettanti, semplicemente provando esaustivamente ogni chiave possibile. Non utilizzare DES a 56 bit; non è banale rompere, ma è alla portata di attaccanti dedicati rompere DES. Un algoritmo a 128 bit, come AES, non è notevolmente più lento della crittografia a 40 bit, quindi non hai scuse per usare la crittografia scadente.

Per la crittografia a chiave pubblica, le raccomandazioni sulla lunghezza delle chiavi dipendono dall'algoritmo e dal livello di sicurezza richiesto. Inoltre, aumentare le dimensioni della chiave influisce negativamente sulle prestazioni, quindi un eccessivo overkill non è economico; quindi, ciò richiede un po 'più di pensiero rispetto alla selezione delle dimensioni della chiave simmetrica. Per RSA, El Gamal o Diffie-Hellman, consiglierei che la chiave sia almeno 1024 bit, come minimo assoluto; tuttavia, le chiavi a 1024 bit sono sul bordo di ciò che potrebbe diventare crackabile nel breve termine e generalmente non sono raccomandate per un uso moderno, quindi se possibile, consiglierei chiavi a 1536 o addirittura a 2048 bit. Per la crittografia a curva ellittica, le chiavi a 160 bit sembrano adeguate e le chiavi a 224 bit sono migliori. Puoi anche fare riferimento alle linee guida pubblicate che stabiliscono equivalenze approssimative tra le dimensioni della chiave simmetrica e della chiave pubblica .

8
D.W.

Non utilizzare la stessa chiave in entrambe le direzioni.

Nelle comunicazioni di rete, un errore comune è usare lo stesso tasto per la comunicazione nella direzione A-> B della direzione B-> A. Questa è una cattiva idea, perché spesso consente di ripetere gli attacchi che riproducono qualcosa A inviato a B, di nuovo ad A.

L'approccio più sicuro è quello di negoziare due chiavi indipendenti, una per ogni direzione. In alternativa, è possibile negoziare una singola chiave K, quindi utilizzare K1 = AES (K, 00..0) per una direzione e K2 = AES (K, 11..1) per l'altra direzione.

8
D.W.

Un pad one-time non è un pad one-time se la chiave è allungata da un algoritmo

L'identificatore "one-time pad" (noto anche come codice Vernam) viene spesso applicato erroneamente a varie soluzioni crittografiche nel tentativo di rivendicare una sicurezza indistruttibile. Ma per definizione, un codice Vernam è sicuro se e solo se tutte e tre queste condizioni sono soddisfatte:

  • Il materiale chiave è davvero imprevedibile; E
  • Il materiale chiave ha la stessa lunghezza del testo in chiaro; E
  • Il materiale chiave non viene mai riutilizzato.

Qualsiasi violazione di tali condizioni significa che non è più una cifra di una tantum.

L'errore comune commesso è che un tasto corto viene allungato con un algoritmo. Questa azione viola la regola dell'imprevedibilità (non importa la regola della lunghezza della chiave.) Una volta fatto, il pad una tantum viene trasformato matematicamente in un algoritmo di stiramento delle chiavi. La combinazione del tasto funzione con byte casuali modifica solo lo spazio di ricerca necessario per forzare l'algoritmo di stiramento del tasto. Allo stesso modo, l'utilizzo di byte "generati casualmente" trasforma l'algoritmo del generatore di numeri casuali in algoritmo di sicurezza.

Qui c'è un semplice esempio. Ho un messaggio che crittograferò usando un "pad una tantum" che utilizza una funzione crittograficamente sicura come generatore di chiavi. Ho scelto una chiave segreta, quindi ho aggiunto un numero casuale per assicurarmi che non venga riutilizzato. Poiché non sto riutilizzando la chiave, non c'è modo di attaccare il testo cifrato sottraendo un messaggio da un altro.

          plaintext : 1234567890123456789012345678901234567890
       key material : 757578fbf23ffa4d748e0800dd7c424a46feb0cc
OTP function (xor)  : ----------
         ciphertext : 67412E83622DCE1B0C1E1A348B04D25872A8C85C

Il materiale chiave è stato generato in modo sicuro utilizzando SHA-1 per eseguire l'hashing della mia password segreta (più casuale) al fine di allungarla. Ma qualsiasi attaccante che conosce l'algoritmo di stretching * utilizzato è SHA-1 può attaccarlo provando vari input in SHA-1 e XORing l'output con il testo cifrato. Indovinare la chiave "OTP" non è più difficile che indovinare gli input combinati dell'algoritmo crittografico. Questa proprietà è valida indipendentemente da quale algoritmo crittografico di base è stato scelto, quali misure di complessità contiene o come viene implementato o seminato.

Potresti avere un ottimo algoritmo di key-stretching. Potresti anche avere un generatore di numeri casuali molto sicuro. Tuttavia, il tuo algoritmo non è per definizione un pad monouso e quindi non ha la proprietà indistruttibile di un pad monouso.

* L'applicazione del principio di Kerckhoff significa che si deve presumere che l'attaccante possa sempre determinare gli algoritmi utilizzati.

3
John Deters

Utilizzare la modalità corretta

Allo stesso modo, non fare affidamento sulle impostazioni predefinite della libreria per essere sicuri. In particolare, molte librerie che implementano AES implementano l'algoritmo descritto in FIPS 197, che è la cosiddetta modalità ECB (Electronic Code Book), che è essenzialmente una mappatura semplice di:

AES(plaintext [32]byte, key [32]byte) -> ciphertext [32]byte

è molto insicuro. Il ragionamento è semplice, mentre il numero di possibili chiavi nello spazio delle chiavi è piuttosto grande, il collegamento debole qui è la quantità di entropia nel messaggio. Come sempre, xkcd.com descrive è meglio di me http://xkcd.com/257/

È molto importante usare qualcosa come CBC (Cipher Block Chaining) che fondamentalmente rende ciphertext [i] una mappatura:

ciphertext[i] = SomeFunction(ciphertext[i-1], message[i], key)

Solo per indicare alcune librerie di lingue in cui questo tipo di errore è facile da commettere: http://golang.org/pkg/crypto/aes/ fornisce un'implementazione AES che, se usata ingenuamente, risulta in modalità BCE.

La libreria pycrypto imposta automaticamente la modalità ECB quando si crea un nuovo oggetto AES.

OpenSSL, fa bene. Ogni chiamata AES è esplicita sulla modalità di funzionamento. La cosa più sicura per IMO è semplicemente provare a non fare criptovalute di basso livello come questa. Se sei costretto a farlo, procedi come se stessi camminando su vetri rotti (con attenzione) e cerca di assicurarti che i tuoi utenti siano giustificati nel riporre la loro fiducia in te per salvaguardare i loro dati.

3
Shane Hansen

Non riutilizzare la stessa chiave su molti dispositivi.

Quanto più ampiamente condividi una chiave crittografica, tanto meno sarai in grado di mantenerla segreta. Alcuni sistemi distribuiti hanno riutilizzato la stessa chiave simmetrica su tutti i dispositivi del sistema. Il problema è che prima o poi qualcuno estrarrà la chiave da un singolo dispositivo e quindi sarà in grado di attaccare tutti gli altri dispositivi. Quindi, non farlo.

Vedi anche "Crittografia simmetrica Non # 6: non condividere una singola chiave su molti dispositivi" in questo articolo del blog . Crediti a Matthew Green.

3
D.W.

Non utilizzare un codice OTP o stream cifratura nella crittografia del disco

Esempio 1

Supponiamo che due file vengano salvati utilizzando un codice di flusso/OTP. Se il file viene salvato di nuovo dopo una modifica minore, un utente malintenzionato può vedere che sono stati modificati solo alcuni bit e dedurre informazioni sul documento. (Immagina di cambiare il saluto "Dear Bob" in "Dear Alice").

Esempio 2

Non c'è integrità nell'output: un utente malintenzionato può modificare il testo cifrato e modificare il contenuto dei dati semplicemente XORing dei dati.

Take away: le modifiche al testo cifrato non vengono rilevate e hanno un impatto prevedibile sul testo in chiaro.

Soluzione

Utilizzare un codice a blocchi per queste situazioni che include controlli di integrità dei messaggi

1

Non fidarti degli standard.

Nella crittografia esistono molti standard e talvolta è necessario utilizzarli. Ma non dare per scontato che le persone che scrivono gli standard abbiano compreso adeguatamente la crittografia di cui avevano bisogno. Ad esempio, EAX è stato rielaborato secondo uno standard di rete. EAX ha una prova di sicurezza. La versione rielaborata no.

MD5 è uno standard. Ora è rotto. Chip e PIN è stato rotto più volte più volte, grazie all'abbondanza di funzioni pericolose. GPG supporta ancora chiavi DSA che sono troppo corte per comodità. SSL ha opzioni che non dovrebbero essere utilizzate e richiedono cura di evitarli.

Cosa si può fare al riguardo? Stare attenti, comprendere i rischi noti e stare al passo con la ricerca di nuovi.

1
Watson Ladd

sa solo MAC che non sono vulnerabili agli attacchi di estensione del messaggio

Un MAC è un codice hash che garantisce l'integrità del messaggio (nessuna modifica, ecc.) Di un dato testo normale. Molte implementazioni e standard pubblicati non riescono a proteggere un MAC da un utente malintenzionato che aggiunge ulteriori dati al MAC.

La soluzione per questo è che l'implementazione MAC utilizzi una seconda (diversa) chiave e crittografi nuovamente l'output finale.

ECBC e NMAC sono esempi di cifre che impediscono correttamente l'attacco dell'estensione del messaggio.

Soluzione:

  • Usa Encrypted CBC (ECBC) invece di raw CBC
  • Usa NMAC invece di cascade
0

Non utilizzare mai un One Time Pad (OTP) o lo stream cipher key più di una volta

Un OTP applicato due volte significa che i dati crittografati con "segreto perfetto" saranno decifrati e in chiaro. Ciò accade perché i dati sono XOR due volte.

Esempio

Supponiamo che un OTP/o stream con la stessa chiave venga riutilizzato.

Un utente malintenzionato raccoglie molti dati inviati da un client a un server e XOR mette insieme un insieme di due pacchetti fino a quando i due pacchetti non si decodificano a vicenda (o sottoinsieme in essi).

La codifica ASCII ha una ridondanza sufficiente, il che significa che dato un testo cifrato sufficiente, i messaggi originali potrebbero essere decodificati (insieme alla chiave OTP segreta).

Esempi del mondo reale

  • Il progetto Verona (1941-46) per un esempio di un OTP utilizzato dai russi e successivamente decifrato dall'agenzia di intelligence americana

  • PPTPv1 di Microsoft sia il client che il server crittografano i dati utilizzando la stessa chiave.

  • WEP riutilizza la stessa chiave una volta che vengono inviati 2 ^ 24 pacchetti o se viene reimpostato un NIC viene reimpostata. Il primo problema è dovuto al fatto che il IV è lungo 24 bit, risultando che dopo 16 milioni di frame sono viene creato un time pad a due. Il secondo problema si verifica nelle implementazioni hardware in cui dopo un ciclo di accensione, l'IV si reimposta a zero, risultando in un time pad. Questo problema è facilmente visibile poiché l'IV viene inviato in chiaro.

Raccomandazioni

  • È necessario creare una nuova chiave per ogni sessione (ad esempio TLS).

  • Il client dovrebbe usare un OTP (o stream cipher w/PRG) con il server e il server dovrebbe usare un chiave diversa quando si crittografano i dati al client

  • Invece di generare molte molte chiavi, è possibile espandere una singola chiave in un lungo flusso usando un PRG (supponendo che si abbia fiducia nel PRG) e utilizzare ogni segmento di tale espansione come chiave.

  • Sappi che non tutti i PRG sono fatti funzionare in modalità incrementale e potrebbe essere necessario un input casuale. (RC4 presenta questo problema in modalità incremento)

0

Non usare RC4

RC4 è stato progettato nel 1987 per l'uso come stream cipher. È utilizzato in HTTPS e WEP.

Ci sono punti deboli

  1. C'è un bias nell'output iniziale: Pr [2nd byte = 0] = 2/256
  2. La probabilità di sedici bit uguali a zero è 1/256 ^ 2 + 1/256 ^ 3. Ciò si verifica dopo che diversi concerti di dati sono stati crittografati.
  3. Vulnerabile ai relativi attacchi di chiave, in cui cambia solo l'IV ma la chiave rimane invariata.

Take away Se devi usare RC4, ignora i primi 256 byte poiché sono distorti. Se si utilizza RC4 per concerti di dati, la distorsione in RC4 consentirà attacchi di tutti i dati crittografati precedenti.

0

Usa processori stream moderni che funzionano in modo appropriato in Hardware o Software

Non tutti i codici di flusso sono progettati per essere implementati in hardware o software. Linear feedback shift register (LFSR) è un esempio di un codice hardware ampiamente diffuso che può essere facilmente rotto.

LFSR è utilizzato in:

  • Crittografia DVD (noto anche come CSS) 2 LFSR
  • Crittografia GSM (A5/1.2) 3 LSFR
  • Bluetooth (E0): 4 LFSR

L'hardware per quanto sopra è ampiamente distribuito e quindi difficile da aggiornare o adeguare agli standard moderni. Tutto quanto sopra è gravemente rotto e non dovrebbe essere attendibile per comunicazioni sicure.

Attacco:

Poiché la chiave viene suddivisa in due sezioni durante la crittografia (17 bit e 25 bit) e quei bit vengono utilizzati per crittografare lo stesso testo cifrato, è possibile utilizzare la conoscenza del formato MPEG e creare una chiave a 17 bit per estrapolare la chiave a 25 bit è.

Questo non è affatto nuovo, ma FOSS è facile da trovare che dimostra questo problema.

Soluzione:

progetto eStream (nel 2008) ha qualificato 5 cifre di stream che dovrebbero essere utilizzate. Una differenza notevole è che invece di usare una chiave con un IV, le cifre usano una chiave, un nonce e un contatore. Salsa20 funziona in questo modo ed è progettato per essere facilmente utilizzato sia in hardware che in software. In particolare, è incluso nel set di istruzioni SSE2 x86.

parte

Le cifre moderne non sono solo più sicure, ma anche più veloci:

PRG          Speed (MB/sec)
RC4              126         (obsolete)
Salsa20/12       643         (modern)
Sosemaunk        727         (modern)
0