Ricerca di revisioni per l'autenticazione e l'approccio di crittografia dei messaggi

1

Ho un piano per la gestione dell'autenticazione e della crittografia dei messaggi, e mi piacerebbe che altri condividessero la conoscenza della crittografia per farmi sapere se il mio approccio è corretto o come dovrebbe essere migliorato.

Le app client si collegheranno al mio server tramite un socket TCP / IP. Mi piacerebbe evitare SSL / TLS. Sul server, sarò l'archiviazione per ogni utente (e cambiato ogni volta che l'utente cambia la password): un sale a caso, l'hash della codifica UTF-8 della loro parola d'accesso più il sale, una chiave simmetrica, e, eventualmente, la cifratura di quella chiave simmetrica (se la chiave simmetrica è casuale, invece di essere derivata dalla password / sale).

Quando gli utenti effettuano il login, il client invierà il nome utente, il server invierà il sale e il client invierà l'hash. Se l'hash corrisponde, il server invierà la chiave simmetrica crittografata e il client la decrittografa e utilizzerà la chiave simmetrica decrittografata per i successivi messaggi crittografati. Se riesco a ricavare la chiave simmetrica dalla password / sale, non sarà necessario calcolare e memorizzare la chiave simmetrica crittografata o inviarla al client per la decrittografia.

Per hashing la password / sale, mi stava progettando su un solo utilizzando SHA-384, ma è stato fatto notare a me (da zaph) che dovrei "iterare su un HMAC con un sale casuale per circa una durata 100 ms e salva il sale con l'hash ". Non voglio usare un'altra libreria, quindi penso che questo è ciò che intendeva:

int
    i;
byte[]
    passwordBytes,
    saltBytes,
    saltedPasswordBytes,
    hash;

passwordBytes = Encoding.UTF8.GetBytes( "MyPass" );
using ( RNGCryptoServiceProvider rngProvider = new RNGCryptoServiceProvider() )
{
    saltBytes = new byte[ 128 ];
    rngProvider.GetBytes( saltBytes );
}

//  Salt the password.
saltedPasswordBytes = new byte[ passwordBytes.Length + saltBytes.Length ];
System.Buffer.BlockCopy(
    passwordBytes, 0, saltedPasswordBytes, 0, passwordBytes.Length );
System.Buffer.BlockCopy(
    saltBytes, 0, saltedPasswordBytes, passwordBytes.Length, saltBytes.Length );

using ( HMACSHA512 hmac = new HMACSHA512( saltedPasswordBytes ) )
{
    //  Get the hash of the salted password.
    hash = hmac.ComputeHash( saltedPasswordBytes );

    //  Iterate, getting the hash of the hash.
    for ( i = 0; i < 2000; i++ )
        hash = hmac.ComputeHash( hash );
}

Un'altra grande preoccupazione è come crittografare la chiave simmetrica. Mi è stato originariamente pensato di AES, e l'invio della chiave simmetrica crittografata al cliente, ma mi chiedo se devo usare qualcosa come sopra, ma varia leggermente, come mettere uno zero nella parte anteriore dei byte di password salate prima di hashing esso e quindi prendendo i primi 32 byte di quello per la chiave. In questo modo, non avrò nemmeno bisogno di crittografare la chiave simmetrica.

Il mio prossimo problema è la crittografia dei messaggi. Dopo aver letto la pubblicazione NIST 800-38A e i post del blog, sono così confuso riguardo alle modalità di cifratura. Il CTR suona bene, ma non è supportato in .NET e non voglio usare librerie di terze parti. Poiché i miei messaggi possono essere piuttosto lunghi e possono avere molte parti ripetute, ECB sembra una cattiva scelta. Usando un altro, come CBC, ora ho bisogno di trattare con il IV. Un approccio che ho letto è quello di utilizzare un nuovo IV casuale con ogni messaggio e inviarlo prima dei byte crittografati. Suona bene per il primo messaggio inviato, ma mi piacerebbe mantenere i messaggi piccoli, quindi stavo pensando di alterare l'IV per ogni messaggio successivo, usando un algoritmo applicato da entrambe le parti. Ho letto che l'IV per i messaggi successivi deve essere imprevedibile, quindi suppongo di dover prendere l'hash di un contatore e XOR quello del IV precedente o qualcosa del genere.

Quindi, esperti, sto andando su questo nel modo giusto? L'iterazione è corretta? È una buona idea usare questo approccio (leggermente diverso, come con uno zero davanti alla password e al sale) per determinare la chiave simmetrica? Quale modalità di cifratura (e approccio IV, se applicabile) dovrei usare per crittografare i messaggi?

Grazie.

    
posta uncaged 10.07.2017 - 03:14
fonte

2 risposte

1

No, no, no, no, no! La prima regola del club di crittografia è non eseguire il proprio algoritmo. ; -)

Seriamente, non farlo. Anche se suona bene per te, o per tutti su questo forum, non farlo! È facile creare un algoritmo che tu non possa violare. Questo è raramente, se non addirittura mai sicuro.

La mia prima domanda sarebbe, cosa c'è di sbagliato nell'usare SSL / TLS? Esiste praticamente per risolvere il problema che stai affrontando. Se sapessimo perché non è adatto al tuo caso d'uso, potremmo essere in grado di offrire un'alternativa migliore.

I problemi più ovvi con il tuo design sono: 1) tutti i gadget, inclusa la chiave simmetrica vengono memorizzati sul tuo server, e 2) stai riutilizzando la stessa chiave simmetrica per ogni messaggio da un determinato utente.

Questo è pessimo.

Se il DB del server viene mai compromesso, i messaggi di tutti, passati, presenti e futuri vengono ora rivelati. Non c'è segreto in avanti. Al minimo, le chiavi simmetriche dei messaggi con il server dovrebbero essere limitate a sessione.

Come sempre, "la tua sicurezza è abbastanza buona" dipende interamente dal tuo modello di minaccia. Chi sta cercando la tua roba, e cosa vale per loro, e per te se viene compromessa.

Questo non è quello che definirei un approccio alla sicurezza pronto per la produzione.

    
risposta data 11.07.2017 - 03:12
fonte
0

Passando alla domanda rivista nel tuo commento:

Would it be a good idea to compute the symmetric key for encrypted messages, by concatenating a 0 byte, the password, and salt, getting the HMAC/SHA-512 of that, and then iterating the hash of the hash to take some time, and taking the first 32 bytes of that as the symmetric key?

No. Non "calcolare" la chiave simmetrica, che è inefficiente e teoricamente insicura (nel senso che la chiave è "derivabile" in una certa misura, dalla conoscenza dell'input).

Le chiavi dovrebbero essere casuali / non ipotizzabili / non derivabili.

Molto più semplice, efficiente e più sicuro è usare un buon generatore di numeri casuali - direttamente da / dev / urandom o da random () come funzione nel tuo linguaggio di programmazione preferito.

    
risposta data 10.07.2017 - 05:43
fonte

Leggi altre domande sui tag