Buscando una revisión para el enfoque de autenticación y cifrado de mensajes

1

Tengo un plan para manejar la autenticación y el cifrado de mensajes, y me gustaría que otros con más conocimientos de criptografía me informen si mi enfoque es correcto o cómo debería mejorarse.

Las aplicaciones del cliente se conectarán a mi servidor a través de un socket TCP / IP. Me gustaría evitar SSL / TLS. En el servidor, almacenaré para cada usuario (y cambiaré cada vez que el usuario cambie su contraseña): un salt aleatorio, el hash del UTF-8 de su contraseña más el salt, una clave simétrica y, posiblemente, el cifrado de esa clave simétrica (si la clave simétrica es aleatoria, en lugar de derivarse de la contraseña / salt).

Cuando los usuarios inician sesión, el cliente enviará el nombre de usuario, el servidor devolverá el salt y el cliente enviará el hash. Si el hash coincide, entonces el servidor enviará la clave simétrica cifrada, y el cliente la descifrará, y usará la clave simétrica descifrada para los mensajes cifrados posteriores. Si puedo derivar la clave simétrica a partir de la contraseña / sal, entonces no habrá necesidad de calcular y almacenar la clave simétrica cifrada, o enviarla al cliente para su descifrado.

Para el hashing de la contraseña / sal, había estado planeando simplemente usar SHA-384, pero se me indicó (por zaph) que debería "repetir una HMAC con una sal al azar durante aproximadamente 100 ms de duración y Salva la sal con el hachís ". No quiero usar otra biblioteca, entonces estoy pensando que esto es lo que quiso decir:

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 );
}

Otra gran preocupación es cómo cifrar la clave simétrica. Originalmente estaba pensando en AES y enviando la clave simétrica cifrada al cliente, pero me pregunto si debería usar algo como el anterior, pero varió ligeramente, como poner un cero en la parte frontal de los bytes de la contraseña con sal antes de hacer hashing y luego tomar los primeros 32 bytes de eso para la clave. De esa manera, ni siquiera necesitaré cifrar la clave simétrica.

Mi siguiente problema es el cifrado de mensajes. Después de leer la publicación NIST 800-38A y las publicaciones del blog, estoy tan confundido acerca de los modos de cifrado. CTR suena bien, pero no es compatible con .NET, y no quiero usar bibliotecas de terceros. Dado que mis mensajes pueden ser bastante largos y tener muchas porciones repetitivas, el BCE parece una mala elección. Usando otro, como CBC, ahora necesito lidiar con el IV. Un método que leí es usar un nuevo IV aleatorio con cada mensaje y enviarlo antes de los bytes cifrados. Eso suena bien para el primer mensaje enviado, pero me gustaría mantener los mensajes pequeños, por lo que estaba pensando en alterar el IV para cada mensaje subsiguiente, usando un algoritmo que se aplica a ambos lados. Leí que la IV para los mensajes subsiguientes debe ser impredecible, por lo que supongo que debo tomar el hash de un contador y XOR a la IV anterior o algo así.

Entonces, expertos, ¿voy a hacer esto de la manera correcta? ¿Es esa iteración correcta? ¿Es una buena idea usar ese enfoque (varió levemente, como con un cero delante de la contraseña y la sal) para determinar la clave simétrica? ¿Qué modo de cifrado (y método IV, si corresponde) debo usar para cifrar mensajes?

Gracias.

    
pregunta uncaged 10.07.2017 - 03:14
fuente

2 respuestas

1

No, no, no, no, no!
La primera regla del club de encriptación es no lanzar su propio algoritmo. ;-)

En serio, simplemente no lo hagas. Incluso si suena bien para usted o para todos en este foro, ¡no lo haga! Es fácil crear un algoritmo que usted no pueda romper. Esto rara vez es realmente seguro.

Mi primera pregunta sería, ¿qué hay de malo en usar SSL / TLS? Prácticamente existe para resolver el problema al que te enfrentas. Si supiéramos por qué no era adecuado para su caso de uso, podríamos ofrecerle una mejor alternativa.

Los problemas más obvios con su diseño son: 1) todas las ventajas, incluida la clave simétrica se almacenan en su servidor, y 2) está reutilizando la misma clave simétrica para cada mensaje de un usuario determinado.

Esto es muy malo.

Si la base de datos del servidor está comprometida, los mensajes de todos, el pasado, el presente y el futuro ahora se revelan. No hay secreto hacia adelante. Como mínimo, las claves simétricas de mensajes con el servidor deben limitarse a cada sesión.

Como siempre, "es su seguridad lo suficientemente buena" depende completamente de su modelo de amenaza. Quién va tras tus cosas, y cuánto vale para ellos, y para ti si se compromete.

Esto no es lo que llamaría un enfoque de seguridad preparado para la producción.

    
respondido por el JesseM 11.07.2017 - 03:12
fuente
0

Pasando por la pregunta revisada en tu comentario:

  

¿Sería una buena idea calcular la clave simétrica para cifrado   mensajes, al concatenar un byte 0, la contraseña y sal, obteniendo   el HMAC / SHA-512 de eso, y luego iterar el hash del hash para   tómese un tiempo y tome los primeros 32 bytes de eso como simétrico   clave?

No. No "calcule" la clave simétrica, es ineficiente y teóricamente insegura (en el sentido de que la clave es "derivable" en cierta medida, del conocimiento de la entrada).

Se supone que las claves son aleatorias / no adivinables / no derivables.

Mucho más simple, eficiente y seguro es usar un buen generador de números aleatorios, ya sea directamente desde / dev / urandom o desde una función aleatoria () en su lenguaje de programación favorito.

    
respondido por el Sas3 10.07.2017 - 05:43
fuente

Lea otras preguntas en las etiquetas