Algoritmo inscripcion autenticacion

Iniciado por matake, 20 Noviembre 2016, 23:58 PM

0 Miembros y 2 Visitantes están viendo este tema.

matake

#10
CitarOtro esquema más y el que más me gusta desde el punto matemático, el más empleado en el real world:

-El usuario al registrarse en el servicio, genera en su equipo un par de claves RSA 2048-bit, envía su clave pública al server y guarda la privada firmada por AES-256 en su equipo. La clave simétrica para cifrar la privada la elige a gusto, pero HA DE RECORDARLA (si la pierde tendrá que avisarte)


Ok entendido.

Lo que desconozco por ahora sobre este sistema, es como implementarlo en el lado cliente.

Mirando un poco por la web di con esta libreria javascript.

https://github.com/wwwtyro/cryptico

Si tienes un minuto para mirar el Overview de la misma a mi me parece que encajaría con lo que propones tu.

Lo que no se, son los pasos que habría tenido que hacer el cliente para cumplir lo que me dijiste arriba

Te pongo aquí dichos pasos tal como lo pienso yo (para ver si he entendido bien) :

- emplear esta librería, u otra parecida a esta en el lado cliente (vi otras discusiones sobre la fiabilidad de las mismas en http://crypto.stackexchange.com/questions/10200/is-javascript-rsa-signing-safe pero parece que cumple ... tu que opinas ?) y generar el par de claves RSA

- sacarle una casilla en donde tiene que ingresar su passphrase para cifrar su llave privada con AES-256 (ya tengo esta otra librería probada )

Aquí tengo una duda Se necesitan 2 Passphrases una para RSA y otra para AES
¿Se utiliza la misma (la que el usuario tiene que memorizar)?

- y al pulsar enviar que mande al servidor su publica (eventualmente en el mismo tiempo con sus datos de inscripción)

- Luego sacarle en una caja de texto la clave suya privada y cifrada con RSA, codificada en base64 para ser compatible ASCII
- el cliente copia la misma y se la guarde como texto en su maquina  (mejor en una usb o tarjeta ssd etc) (Modo paranoia ON -> Esteganografia para privada cifrada con RSA :D )


- Después del login le pongo una caja de texto en donde tiene que pegar su clave privada (ya que con javascript no se pueden abrir ficheros ... aunque vi algo en el mismo HTML5 que tiene una API creo... lo mirare)

- Otra casilla en donde tiene que ingresar su passphrase  y ... "Lo he dejado a los matemáticos" :D

Si es así el resto lo entendí todo.




Me gustaría, si puedes, confirmarme (o no) si los pasos que hago en el lado cliente son correctos o si tu habría pensado en otra cosa.

Un saludo.

kub0x

He revisado el overview de la librería, así como aspectos técnicos y código fuente de funciones cruciales como generación de la clave RSA, AES e IV.

La passphrase vista aquí:

Código (javascript) [Seleccionar]
// The passphrase used to repeatably generate this RSA key.
var PassPhrase = "The Moon is a Harsh Mistress.";

// The length of the RSA key, in bits.
var Bits = 1024;

var MattsRSAkey = cryptico.generateRSAKey(PassPhrase, Bits);


Sirve para generar entropía tomando el SHA-256 de la passphrase, de esta forma se generará la clave RSA dependiendo de un hash único. Haz un PBKDF user+pass+salt+it y pásaselo a generateRsaKey como la passphrase. Si dos passphrase son iguales, también lo serán las private key.

Esto es importante también:

CitarEncryption

A 32-byte AES key is generated with Tom Wu's random number generator. The plaintext message is converted to a byte string and padded with zeros to 16 bytes round. An initialization vector is created with Tom Wu's random number generator. The AES key is expanded and the plaintext message is encrypted with the Cipher-block chaining mode using the jsaes library. The AES key is encrypted with the recipient's public key using Tom Wu's RSA encryption library.

Cada vez que se quiera cifrar un mensaje, se genera una clave AES aleatoria (no confundir con la AES de la privada del usuario). Aquí no necesitas establecer ninguna passphrase para AES (menos trabajo para tí), la propia librería subyacente generará la entropía necesaría para que las claves sean distintas en cada generación. Es importante, ya que si usaramos una passphrase inicial y alguien la adivina, sería trivial adivinar la secuencia de claves AES generada por el PRNG.

CitarAquí tengo una duda Se necesitan 2 Passphrases una para RSA y otra para AES
¿Se utiliza la misma (la que el usuario tiene que memorizar)?

Genera la passphrase para RSA como he mencionado arriba, úsala para generar el par de claves RSA, ahora obliga al usuario a introducir otra passphrase (textbox?) que con PBKDF genere una clave AES para cifrar la privada RSA. Una vez generado el par, no vuelvas a usar passphrases (JAMÁS, como ya he dicho), ya que estas dos passphrases SÓLO se usan para generar el par público/privado + AES para la private RSA. El resto de claves AES serán aleatorias para cifrar mensajes. Espero se entienda porque esto es lo más importante.

La librería lleva 4 años sin actualizarse. Pero no nos alarmemos, no es más que una interface en high level de las liberías de http://www-cs-students.stanford.edu/~tjw/jsbn/ las cuales parecen seguras ya que utilizan el padding PKCS#1 y CBC con padding también así que perfecto. El exponente es 3 en vez de 65537, verás mucho novato diciendo que son vulnerables, pero realmente no es así, es cuestión del padding pero al ser PKCS no hay problema, de hecho usando 3 es más rápida.

Citar- y al pulsar enviar que mande al servidor su publica (eventualmente en el mismo tiempo con sus datos de inscripción)

- Luego sacarle en una caja de texto la clave suya privada y cifrada con RSA, codificada en base64 para ser compatible ASCII
- el cliente copia la misma y se la guarde como texto en su maquina  (mejor en una usb o tarjeta ssd etc) (Modo paranoia ON -> Esteganografia para privada cifrada con RSA :D )


- Después del login le pongo una caja de texto en donde tiene que pegar su clave privada (ya que con javascript no se pueden abrir ficheros ... aunque vi algo en el mismo HTML5 que tiene una API creo... lo mirare)

- Otra casilla en donde tiene que ingresar su passphrase  y ... "Lo he dejado a los matemáticos" :D

-Correcto, se envía la pública del usuario + sus datos personales.
-En el textbox sacas la clave privada cifrada con AES (no por RSA  :P), en b64 ASCII creo que debería ser así el formato estándar, correcto.
-Exacto, el cliente copia la clave privada cifrada con AES en una memoria USB al ser posible o en su PC alternativamente.
-Sí, después del login tendrá que poner en un textbox la privada cifrada con AES y otro textbox para coger la passphrase que se utilizó para generar la clave AES que cifra la privada. De esta forma descifrar la private RSA y ya podrás intercambiar mensajes que cumplan las firmas digitales para probar la autenticación.

Siguiendo estos pasos tendrás un mecanismo de autenticación muy robusto, ya que si comparamos el robar la tarjeta de coordenadas del usuario con robarle la private key cifrada con AES, pues obviamente con la tarjeta suplantamos al usuario, pero con la private cifrada podemos estár 100 veces la vida del universo intentando ataques que no podríamos hacer nada (el atacante tendría que adivinar la passphrase AES (díficil si obligas al usuario a escoger una clave 10+ carácteres alfanuméricos).

Saludos!
Viejos siempre viejos,
Ellos tienen el poder,
Y la juventud,
¡En el ataúd! Criaturas Al poder.

Visita mi perfil en ResearchGate


matake

#12
Gracias kubox,

En principio me ha quedado todo claro.


CitarHaz un PBKDF user+pass+salt+it y pásaselo a generateRsaKey como la passphrase. Si dos passphrase son iguales, también lo serán las private key.

¿Aportaria alguna mejora si hago asi?

Como tengo otra libreria (CryptoJS) para AES (cada una con sus pro y contras ) intentare aprovechar lo mejor de cada una por ejemplo:

CryptoJS tiene SHA3-512 PBDKF2 y Pkcs7 para padding pero no tiene PRNG
En cambio cryptico tiene PRNG pero hashes mas flojos pbdkf1 y padding con ceros

Entonces usare PRNG de la libreria cryptico para generar IV y salt
y generare la key usando la libreria CryptoJS

Código (javascript) [Seleccionar]
var key = CryptoJS.PBKDF2(passphrase, salt, { hasher: CryptoJS.algo.SHA3-512, keySize: 4, iterations: it });
//keySize: 4 es para 32bytes



hmm el padding se queda con ceros (pero voy a mirar si puedo emplear CryptoJS para AES en vez de AES que tiene "cryptico"

Apropósito: Desde algunos meses que hemos hablado la primera vez me he quedado con una duda:
El numero de iteraciones ... hay que guardarlo en algún lugar ?  no se si te acuerdas que me dijiste que algunos emplea un rango de tiempo 9-10 milisegundos ...

Entonces cuando uno va a descifrar con AES ¿como saber cuantas iteraciones poner?


Citarla clave privada cifrada con AES (no por RSA  :P)
:D Ha sido solo una confusión de términos (al no ser muy acostumbrado con ellos)  ... en la cabeza la tenia correcto AES y no RSA.


Citar
- Después del login, el usuario genera una clave simétrica AES y un mensaje aleatorio. El usuario computa el SHA-256 sobre el mensaje y lo firma con su privada, esto es una firma digital sobre el mensaje. Ahora el usuario cifra el mensaje aleatorio con la simétrica y cifra la clave simétrica con la pública del servidor y envía al servidor el mensaje aleatorio cifrado, la clave simétrica cifrada por la pública del server y la firma digital.
- El servidor recibe el mensaje aleatorio cifrado por AES, la clave simétrica AES cifrada con la pública del servidor (su pública) y la firma digital. El propio server coge la clave simétrica cifrada y la descifra con su privada, coge la firma digital y la descifra con la pública del usuario (recuerda que fue guardada en el registro), coge el mensaje aleatorio y lo descifra con la simétrica obtenida. Ahora que tiene el mensaje aleatorio en plaintext, computa el SHA-256 y lo compara con el descifrado de la firma digital. Si son iguales, el servidor sabe que el mensaje fue firmado por el usuario y sabe que sólo el propio servidor puede descifrar la clave simétrica. Esto nos da una autenticidad REAL (PGP trabaja así cuando se utiliza RSA+AES).

El proceso en si, después del login lo he entendido, pero como nunca he trabajado con RSA me queda una duda.
(casi dos con lo de firmar "y lo firma con su privada") ... supongo que "firmar" quiere decir también "cifrar" con su privada (en este caso) ...
entonces si es así me queda solo una duda:

En el proceso de cifrar con las claves publicas (mia y la del usuario) y privada del usuario
¿se utiliza AES para cifrar y se emplean dichas claves como passphrase para crear una clave AES ? Si seria asi , no hace falta que me expliques como se hace porque esto ya lo se hacer. (PBKDF+passphrase+SHA+IV+salt+it)
¿O es un cifrado que se hace de alguna forma (diferente de AES) con el mismo RSA?
(cosa que por ahora desconozco ... intentare ahora averiguarlo )


Ok creo  lo he averiguado.
para el lado cliente en la misma libreria js pone un ejemplo:
Citarcryptico.encrypt(PlainText, MattsPublicKeyString);
y en el servidor con openssl.

Saludos


P.D ... Perdona si me he puesto pesado con tantas preguntas pero prefiero estar seguro que he entendido todo













kub0x

CitarCryptoJS tiene SHA3-512 PBDKF2 y Pkcs7 para padding pero no tiene PRNG
En cambio cryptico tiene PRNG pero hashes mas flojos pbdkf1 y padding con ceros

Entonces usare PRNG de la libreria cryptico para generar IV y salt
y generare la key usando la libreria CryptoJS

Ojo, CryptoJS y Cryptico ambos implementan padding PKCS7# sólo que CryptoJS en el padding introduce N bytes cuyo valor es N y Cryptico Zero padding. Me quedo con el de CryptoJS.
Sí, lo mejor sería generar una clave AES llamando a la funcion:

Código (javascript) [Seleccionar]
my.generateAESKey = function()
    {
        var key = new Array(32);
        var r = new SecureRandom();
        r.nextBytes(key);
        return key;
}


La cual devuelve la clave AES-256 aleatoria usando el PRNG de Cryptico, el cual es seguro ya que tiene la suficiente entropía para no tener una tendencia (bias). Ahora usa esa clave aleatoria para cifrar con AES-CBC en CryptoJS (por el tema del padding).

Entonces, como hemos dicho. Al registrarse el usuario se genera la private key RSA mediante PKBDF2 -> user+pass+salt+it y oblígale a introducir un passphrase que generará la clave AES PKBDF2 -> passphrase+salt+it. Cifra la privada mediante AES, haz que guarde la privada cifrada en algún sitio y deshazte de la clave AES.

CitarOk creo  lo he averiguado.
para el lado cliente en la misma libreria js pone un ejemplo:

cryptico.encrypt(PlainText, MattsPublicKeyString);

y en el servidor con openssl.

Ahí sólo estás cifrando un mensaje con la pública. No veo que estés generando una clave AES aleatoria, ni un mensaje, ni una firma digital ni nada de lo que dije anteriormente :D

Arriba he mostrado como generar una key AES-256 aleatoria. El mensaje a cifrar puede ser el mismo ya que el IV hace que en cada cifrado el ciphertext sea distinto, lo mejor aun así es generar un mensaje aleatorio con el PRNG. Vale ya sabes como generar una clave AES y mensaje aleatorios.

Ahora tienes que hacer la firma digital sobre el mensaje, cryptico utiliza esta función para ello:

Código (javascript) [Seleccionar]
function _rsasign_signStringWithSHA256(s)
{
    var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), 'sha256');
    var biPaddedMessage = parseBigInt(hPM, 16);
    var biSign = this.doPrivate(biPaddedMessage);
    var hexSign = biSign.toString(16);
    return hexSign;
}


La firma digital también lleva padding y acuérdate que internamente computa el SHA-256 del mensaje, le añade padding y lo firma con la privada (cifrar con la privada está mal dicho realmente, no gusta en el argot de la crypto).

Sólo falta que cifres la clave AES-256 aleatoria con la pública del servidor, como has puesto en el ejemplo. Y ya tienes: clave AES aleatoria cifrada por pública de servidor, mensaje aleatorio cifrado por clave AES aleatoria y firma digital sobre mensaje aleatorio. Manda esa info al server y el server se ocupara de:

Descifrar la clave AES con su privada (la del server). Descifrar el mensaje cifrado por AES y llamar a la función:

Código (javascript) [Seleccionar]

function _rsasign_verifyHexSignatureForMessage(hSig, sMsg)
{
    var biSig = parseBigInt(hSig, 16);
    var result = _rsasign_verifySignatureWithArgs(sMsg, biSig, this.n.toString(16), this.e.toString(16));
    return result;
}


La cual coge el mensaje descifrado por AES y la firma digital y verifica si en efecto el mensaje no ha sido alterado. De esta forma has autenticado al 100% al otro extremo.

NOTA: Te pongo el código de las funciones para que veas un poquito como se comportan por dentro, aunque hagan llamdas internas, es más facil dartelo así que sólo el nombre de la función a la que tienes que llamar. Esto hace que te familiarices un poco más con la librería.

Entiendo que es un tema extenso y más cuando primero tienes que entender lo que estás haciendo antes de implementar nada, ya que pondrías en riesgo toda la infraestructura si no encajas bien las piezas. Si no entiendes algo, pues aquí estoy para lo que necesites.

Saludos!
Viejos siempre viejos,
Ellos tienen el poder,
Y la juventud,
¡En el ataúd! Criaturas Al poder.

Visita mi perfil en ResearchGate


matake

#14
CitarSi no entiendes algo, pues aquí estoy para lo que necesites.

No sabes cuanto te lo agradezco kub0x !

Al intentar aprender todo como autodidacta (cosas de la vida + tonterias de la juventud) pues aprendo trocitos de cosas quedándome siempre partes que estoy saltando (por no saber de su existencia)

Ojala el proyecto que tengo en la cabeza ira bien, entonces no voy a olvidar tu ayuda te lo aseguro !


Citar
CitarOk creo  lo he averiguado.
para el lado cliente en la misma libreria js pone un ejemplo:

cryptico.encrypt(PlainText, MattsPublicKeyString);

y en el servidor con openssl.

Ahí sólo estás cifrando un mensaje con la pública. No veo que estés generando una clave AES aleatoria, ni un mensaje, ni una firma digital ni nada de lo que dije anteriormente :D


Puse solo como un resumen ... (el proceso en si, lo he entendido ... por esto puse lo de usar lo mejor de las dos librerías ... solo estaba un poco confundido con lo del padding )


Sin embargo en lo de la firma , cuando escribi el mensaje puse una pregunta (no se si lo habrás leído) donde te preguntaba si esto de la firma es otro proceso o bien es simplemente un cifrado con AES ... pero luego ... he deducido (MAL) que si, que solo es otro cifrado AES (al que tu llamaste firma) así que borre dicha pregunta.

Ahora que me pusiste las funciones en js ... me puse a encontrar su equivalente en openssl y creo haber encontrado algo el "dgst" (aunque los ejemplos que encontré eran para firmar-verificar un fichero de texto ) de todos modos me doy cuenta que estoy cerca así que lo averiguare por mi mismo.


Ahora ya que se me ha quedado en la cabeza el proceso entero (al menos este cual tratamos aquí en este hilo),
me falta todavía practicarlo un poco cuando tendré tiempo (lo de AES ya he echo practicas queda RSA + esta firma )


O sea ahora de punto de vista matemático seria digamos aceptable como robustez

Los puntos débiles que le veo por ahora serian: la intrusión en algunos (o ambos) de los lados cliente - servidor y/o el phishing + eventualmente la criptoanalisis

Por otro lado, en mi codigo php tengo ya hecha (trabajando en local) la verificación y saneamiento de todos los datos de entrada + PDO + procedimientos almacenados para la interacción con la base de datos
Para el servidor también: redirecionamiento https + HSTS + Hardening & Security cabeceras (XSS, CSRF, secure httponly cookies etc)

Volviendo al tema:
Ahora ya con lo que se sobre AES si RSA intentare reforzar un poco la lógica del login (ya no empleare métodos de la edad de piedra para que el usuario tenga que contar hieroglifos en una tabla sumeria :D )

A ver que te parece.

Asumiendo que el usuario pilla algun keylogger virus troyano etc, o peor un acceso a su maquina o se le hace un phishing. Entonces esto comprometería todo.

Por esto voy a dividir el acceso a los usuarios en dos partes:
-una para poder trabajar solo con usuario + contraseña, en donde si alguien le roba su contraseña o la sesión que no le afecte
-y otra para los datos sensibles donde tendrá que utilizar su clave privada (como ya hemos hablado)


En el proceso de inscripción (aparte de lo que hemos hablado) voy a añadir también una OTP que lo va a recibir por SMS (de todos modos voy a tener que comprobar su teléfono.
Lo que no me puedo permitirme al principio, es usar SMS como segundo factor siempre en cada login ... no todos somos ricos :D )

con esta OTP puedo cifrar su publica al enviarla al servidor y luego que me envía los otros datos ya cifrados con su privada + firma etc, como si seria el primer login.

Entonces esto sera un poco mas cómodo para el cliente ya que solo de vez en cuando tendra que emplear su clave privada ademas la esta exponiendo menos.

O sea la privada del cliente solo se empleara como autorización para los datos sensibles o si se logea de otra maquina (o ha borrado la cookie de su maquina)

-Dicha cookie no va a ser para guardar su sesión (siempre voy a pedir user+pass para login aunque tenga cookie)
pero la empleare como si seria una OTP una vez usado generare otra (cifrada en el servidor + httponly + secure)

Así que si se le roba el pass o esta cookie otra vez SMS + su privada (como hemos hablado) Si alguien abusa de SMS hago que mande el a mi un SMS.

Entonces aunque se le ha robado incluso su privada + su passphrase queda el SMS como OTP.

Ademas al mandarle el SMS, lo voy a emplear también para cifrar la publica del cliente que tengo en el servidor.
Me mando esta clave que he empleado a mi mismo y la destruyo (asi cubro tambien la parte del servidor)

Ahora (desde mi punto de vista quedarían estas debilidades seguro son mas :D pero no me doy cuenta):

-Que el atacante haga todo el proceso ar revés

O sea primero hacerse con la publica del cliente que tengo en servidor y luego que robe al menos user+pass+privada+passphrase del usuario y usarlos para descifrar los datos del cliente.

¿Tendrás alguna idea al respecto para evitar esto? (claro que no entre! pero si entra ... creo que ya me dijiste ... si entra .... no sirve de nada el cifrado )

Y la segunda seria criptoanalisis en lo cual soy NULO !

Por esto mi pregunta es:
¿ayudaría que los passphrases del cliente para la generación del primer par RSA y la del AES (usada para cifrar su privada) serian algo complicadisimos y largos?

Algo así (mas complejos todavía pero no me deja el foro ponerlos aquí:
Citar
¥ö `ŠúZtq¯>à@I?¥øƒafF ÁƒpÂé‡ 臬qúy_Ðpà,,Á?ð8‡7`ÆRÍØU±+XøŒàBb:9^ƒPCmêm"oU›í£è\õ':ë`µNžTêOfEùÁŸ =:/ðf£­e


Ya te preguntaras ¿Y como se supone que va memorar el usuario tal cosa?

He pensado en hacer que el usuario guarde su privada y su passphrase en unas fotos (esto si no juntas)

Por esto quiero usar para que escoja unas fotos que se puede recordar usando

CitarFileReader(); //para abrir las fotos en el lado cliente
readAsBinaryString(); // para generar la passphrase


y emplear esta librería: https://eligrey.com/demos/FileSaver.js/

para que el cliente guarde de manera mas sencilla su privada y su passphrase (esto si AVISANDOLE QUE NO LAS GUARDE en la maquina por lo menos la foto de passphrase) ... de todos modos podre emplear el SMS que recibe para crear un algoritmo de regenarcion de passphrase en base a dicha foto

Todo esto en el lado cliente sin necesidad del servidor.

Apropósito servirá de algo, que antes de introducir su foto (usada como passphrase) le obligo que se desconecte de internet ?
Puedo chequear si tiene conexión y sugerirle que se desconecte antes de introducir su privada y su passphrase luego quitar la memoria (ssd o usb) y volver a conectarse para continuar el proceso  

Se que es muy paranoia pero de este modo solo seria complicado para mi hacerlo y no para el usuario emplearlo asi que puedo cumplir tambien con lo de Kerckhoff (menos lo de desconectarse de internet).


Bueno ojala funcione bien lo que intento hacer como negocio y si se gana algo emplear personas calificadas para estos propósitos creo que seria lo mejor pero hasta entonces tendré que sobrevivir

Te aseguro que no me olvidare de ti tampoco

Gracias por tu paciencia y tu extensa ayuda  ... me ha servido mucho

Ahora como he dicho practicar (cuando puedo) y te molestare de vez en cuando con alguna duda puntual y no escribirte mas novelas como esta

Un saludo y felicitaciones por lo que haces







kub0x

#15
Buenas noches Matake,

me alegro de que vayas pillando los conceptos y sepas como juntarlos, aun así todavía veo alguna cosa que no te ha quedado del todo clara jeje intentaré ayudarte. Empecemos:

CitarSin embargo en lo de la firma , cuando escribi el mensaje puse una pregunta (no se si lo habrás leído) donde te preguntaba si esto de la firma es otro proceso o bien es simplemente un cifrado con AES ... pero luego ... he deducido (MAL) que si, que solo es otro cifrado AES (al que tu llamaste firma) así que borre dicha pregunta.

La firma no es otro cifrado con AES, una firma creo que la vés como MAC, pero esto es una firma DIGITAL :D . Una firma digital sirve para que el destinatario compruebe que el mensaje no fue modificado y proviene de la fuente original y no de un atacante. Se basa en probar que la firma digital fue creada por la clave privada del emisor.

Creo que lo he explicado dos veces por los anteriores post, pero centraré más atención esta vez en el proceso de firma digital. La función de firma digital también la puse arriba, te hare quote de ella:

Código (javascript) [Seleccionar]
   function _rsasign_signStringWithSHA256(s)
   {
       var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), 'sha256');
       var biPaddedMessage = parseBigInt(hPM, 16);
       var biSign = this.doPrivate(biPaddedMessage);
       var hexSign = biSign.toString(16);
       return hexSign;
   }


¿Y cómo se computa una firma digital sobre un mensaje? Nosotros somos el emisor y queremos provar al destinatario que el mensaje que vamos a enviar no ha sido modificado y que realmente somos nosotros al 100% quien ha enviado ese mensaje. Entonces:

- Generamos un mensaje y computamos el SHA-256 del mismo.
- Añadimos un padding a dicho Hash (sino varios mensajes iguales tendrían la misma firma digital, sería un big fail).
- Ahora firmamos con la privada el hash y ya tenemos la firma digital sobre el mensaje.

Ahora el destinatario recibe el mensaje y la firma digital, el destinatario (servidor) posee la clave pública del usuario (recuerda que la entregó en el sign-up o registro).

- Computa el SHA-256 del mensaje.
- Descifra la firma digital con la pública del usuario.
- Compara el primer Hash y el del descifrado de la firma digital, si ambos hashes son iguales, entonces sabemos que el mensaje no fue modificado y que proviene del emisor (nosotros) ya que la clave pública está relacionada con la privada, y la privada del emisor firmó el mensaje.

Vale, ya está explicado con todo detalle el proceso de firma digital y en que se basa.

CitarLos puntos débiles que le veo por ahora serian: la intrusión en algunos (o ambos) de los lados cliente - servidor y/o el phishing + eventualmente la criptoanalisis

Por otro lado, en mi codigo php tengo ya hecha (trabajando en local) la verificación y saneamiento de todos los datos de entrada + PDO + procedimientos almacenados para la interacción con la base de datos
Para el servidor también: redirecionamiento https + HSTS + Hardening & Security cabeceras (XSS, CSRF, secure httponly cookies etc)

La intrusión en el server no ayudaría en nada, ya que sólo obtendrían hashes salteados de las password, las públicas de los usuarios y su username. Los datos sensibles deberías cifrarlos con una simétrica que detallaré luego el como se genera. Si instalan keylogger al usuario no es tu problema, recuérdalo. Si capturan la private key del user, tendrían que romper AES o brute force a la passphrase. Así que no te preocupes.
Las medidas de protección del server me parecen ideales, HSTS para evitar SSL-Stripping, TLS over HTTPS con ECDHE_ECDSA_AES-256-GCM al poder ser, pregúntame luego si quieres el por que :D y un buen NIDS (Network Intrusion Detection System o Firewall), httponly para no capturar cookies por JS y todo sanitizado, si señor. Por el criptoanálisis, no te preocupes, es seguro (hasta que venga el PC cuántico) mientras implementes todo bien claro.

Por lo que veo te preocupa mucho que descifren los datos del usuario almacenados en tu servidor. Te voy a proponer lo siguiente. Teniendo en cuenta que tu eres más cuidadoso que cualquier usuario, vamos a proteger bien esa información, para que en caso de intrusión, no puedan ni descifrar los datos del usuario.

El usuario hace sign-up por primera vez:

- Genera un par de claves RSA en el lado del servidor. Esto ya contábamos con ello ¿por qué sino como cifra el usuario la simétrica AES sobre el mensaje aleatorio?. La privada RSA es única (un mismo par para todo) y cifrála con el passphrase que desees en AES-256.
- El usuario computa una firma digital sobre su info y cifra dicha info con una clave AES aleatoria. El user cifra la clave aleatoria AES con la pública del server y envía todo lo especificado aquí al server.
- El server descifra la clave AES con su privada (la del server obvio), descifra el mensaje con la clave AES y verifica la firma digital. Si todo va bien, re-cifra la info del usuario, cifra la clave AES con la pública del server y guarda la info cifrada por AES y la clave AES cifrada por la pública RSA.

Ahora si entrán a tu server, verán que la info de todos los usuarios está cifrada, y también verán que hay una clave AES cifrada por la pública de tu server. Entonces pensarán, bueno sólo necesito descifrar la info por la key AES, vale vamos a buscar la private key del server. Digamos que la encuentran, pero no verán más que la privada tuya cifrada por AES.

La autenticación la hacemos como te dije, generas mensaje y clave AES aleatoria. Computas firma digital con la privada del usuario sobre el mensaje aleatorio y cifras el mensaje con AES. Envías la info al server y el server descifra la AES con su privada (la del server), descifra el mensaje con la AES y computa la firma digital con la pública del cliente. Si la firma digital es satisfactoria entonces has autenticado al cliente al 100%.

Como ves es un esquema fuerte en el que si sólo observan mensajes necesitan un ordenador cuántico para atacar el protocolo. Si entran al servidor no podrán saber la info de los usuarios ya que necesitan la privada del servidor. Si comprometen al cliente, todo depende de su seguridad, si roban su privada y la passphrase que la protege entonces se podrán autenticar, para eso lo mejor es que hagas como GMAIL, guarda la IP o el PC mediante cookie y si cambia de PC o de rango de IP entonces avísalo y hasta que no confirme no le dejes entrar.

Saludos!
Viejos siempre viejos,
Ellos tienen el poder,
Y la juventud,
¡En el ataúd! Criaturas Al poder.

Visita mi perfil en ResearchGate


matake

Muy buenas ,

Citar
La firma no es otro cifrado con AES, una firma creo que la vés como MAC, pero esto es una firma DIGITAL

Gracias por los detalles que me diste esto me aclaro todo.
Caso cerrado lo de la firma :D




CitarEl usuario hace sign-up por primera vez:

- Genera un par de claves RSA en el lado del servidor. Esto ya contábamos con ello ¿por qué sino como cifra el usuario la simétrica AES sobre el mensaje aleatorio?. La privada RSA es única (un mismo par para todo) y cifrála con el passphrase que desees en AES-256.
- El usuario computa una firma digital sobre su info y cifra dicha info con una clave AES aleatoria. El user cifra la clave aleatoria AES con la pública del server y envía todo lo especificado aquí al server.
- El server descifra la clave AES con su privada (la del server obvio), descifra el mensaje con la clave AES y verifica la firma digital. Si todo va bien, re-cifra la info del usuario, cifra la clave AES con la privada del server y guarda la info cifrada por AES y la clave AES cifrada por la privada RSA.

Ahora si entrán a tu server, verán que la info de todos los usuarios está cifrada, y también verán que hay una clave AES cifrada por la privada de tu server. Entonces pensarán, bueno sólo necesito descifrar la info por la key AES, vale vamos a buscar la private key del server. Digamos que la encuentran, pero no verán más que la privada tuya cifrada por AES.

La autenticación la hacemos como te dije, generas mensaje y clave AES aleatoria. Computas firma digital con la privada del usuario sobre el mensaje aleatorio y cifras el mensaje con AES. Envías la info al server y el server descifra la AES con su privada (la del server), descifra el mensaje con la AES y computa la firma digital con la pública del cliente. Si la firma digital es satisfactoria entonces has autenticado al cliente al 100%.


Segun entiendo , en esta propuesta el usuario ya no genera sus claves RSA (como hemo hablado anteriormente).
Las genera el servidor y se los manda al usuario (¿es esto correcto?)

Aunque creo que he entendido luego el proceso de autenticacion, estoy un poco perdido en esto:

CitarAhora si entrán a tu server ... vamos a buscar la private key del server ... Digamos que la encuentran, pero no verán más que la privada tuya cifrada por AES.

Y dicha clave AES (la que utilizo para cifrar la privada mía) tendré que tenerla fuera del servidor ... sino no le veo lógica. ¿Es esto correcto?

Si es así ... entonces entiendo que la publica me basta para autenticación 100%,
pero en este caso (si no me equivoco) aunque este autentificado, el usuario no puede descifrar sus datos.

A no ser que no he entendido  bien el proceso

Tambien estoy un poco confundido cuando me dices de las privadas del servidor
¿Hablamos solo de la privada del user generada por servidor? o de dos privadas una del user y otra mia (ambas presentes en el servidor).

Un saludo

kub0x

Buenas matake, por lo que veo tienes un lío en esto:

CitarY dicha clave AES (la que utilizo para cifrar la privada mía) tendré que tenerla fuera del servidor ... sino no le veo lógica. ¿Es esto correcto?

Si es así ... entonces entiendo que la publica me basta para autenticación 100%,
pero en este caso (si no me equivoco) aunque este autentificado, el usuario no puede descifrar sus datos.

A no ser que no he entendido  bien el proceso

Tambien estoy un poco confundido cuando me dices de las privadas del servidor
¿Hablamos solo de la privada del user generada por servidor? o de dos privadas una del user y otra mia (ambas presentes en el servidor).

Quizá me haya explicado mal en ese sentido, espero que ese post sirva para aclarar todas tus dudas sobre el proceso de generación de claves en el sign-up y sobre el proceso de autenticación.

Primero antes de todo, el usuario y el servidor tienen dos pares RSA distintos, ambos de 2048-bit. La clave privada del servidor estará cifrada por una clave AES que tu has generado (sólo tu conoces). Esa clave es conveniente que esté en otro lugar distinto al servidor, o que para tener acceso se necesite de privilegios root. El par RSA del usuario lo debe general el mismo, no el servidor. Si sólo existiera el par de claves en el lado del server, el usuario no podría computar firmas digitales, por lo tanto cualquiera ha podido enviar información al server y tu no sabrías como autenticar dicha información.

Para cifrar los datos del usuario, la primera vez que el usuario hace sign-up (registro), se genera un par de claves para ese usuario, le obligas a introducir una passphrase que derivarás en una AES y cifrarás su privada con ella (todo esto del lado del usuario repito). Ahora se genera una AES aleatoria de lado del usuario, se computa una firma digital con la privada del usuario sobre sus datos, se cifran los datos por esa AES aleatoria y se cifra la AES aleatoria con la pública del server.

El usuario envía AES aleatoria cifrada por pública del servidor, datos cifrados por AES aleatoria y firma digital sobre los datos.

El servidor recibe dichos datos, descifra la AES con la privada del servidor, descifra los datos del usuario con la AES descifrada y verifica la firma digital sobre esos datos descifrados con la pública del usuario. La pública del usuario has de enviarla de alguna forma antes de este proceso. Si la firma digital es correcta entonces sabes que los datos del usuario no han sido modificados y que el usuario hizo la firma digital con su privada y nadie más pudo, así que autenticado al 100%.

Ahora guardas en la DB del server los datos cifrados por esa AES y guardas la clave AES asociada a esos datos cifrada por tu pública (la del server). Así si entran al server no podrán leer los datos de cada usuario, porque la clave AES que los descifra está cifrada por tu pública (sólo se puede descifrar por la privada tuya), y como tu privada está protegida con una AES que sólo tu conoces, pues, game over para el attacker.

¿Pero como descifra esos datos el usuario? Bueno, ese trabajo lo haces tú. Coges la info cifrada del usuario, la clave cifrada AES asociada a esa info y descifras con tu privada la AES asociada a esos datos y posteriormente los datos. Ahora los datos están en plano y se los puedes presentar al usuario. Si el usuario los modifica puedes obligarle a repetir el mismo proceso de generar AES aleatoria, firma digital sobre los nuevos datos etc, para que cada vez que cambien los datos se le asocie una nueva AES.

Ahora sólo queda el proceso de autenticación, que es lo mismo pero con un mensaje aleatorio.

Saludos!
Viejos siempre viejos,
Ellos tienen el poder,
Y la juventud,
¡En el ataúd! Criaturas Al poder.

Visita mi perfil en ResearchGate


matake

Hola kub0x,

"Mas claro que el agua" !!!
Ahora ya he entendido bien todo.

Fue esta frase que me confundió:
Citar- Genera un par de claves RSA en el lado del servidor. Esto ya contábamos con ello ¿por qué sino como cifra el usuario la simétrica AES sobre el mensaje aleatorio?

Por esto creí que quieres decir, que tengo que generar las claves del usuario en el servidor de donde deduje yo que luego tendría que mandárselo al usuario.
Ahora si me ha quedado claro que no es así.

Estas semanas intentare armarlo todo en local ya te contare que tal me ha ido.

Saludos y gracias por todo.