Como parte del cifrado de extremo a extremo de mi aplicación, estoy siguiendo el procedimiento estándar de usar RSA para intercambiar la clave temporal AES256. Actualmente, cuando A decide la clave para enviar a B, la cifra con la clave pública de B. Todo esto está participando a través de una conexión TLS al servidor. Sin embargo, B está tomando la clave en la fe ciega de que proviene de A. Por supuesto, no es como si alguien pudiera enviar a B la clave AES256. Debe iniciar sesión primero en el servidor antes de que esté dispuesto a pasar mensajes a A. La clave AES256 también se envía solo durante la configuración de una sesión entre A y B que B tendría que haber aceptado antes. El servidor también verificará que haya un inicio de sesión solicitado entre X y B antes de enviar algo a B y que realmente es X con lo que B quiere tener una sesión. El objetivo de extremo a extremo es evitar que el servidor sepa lo que está pasando entre A y B (incluso si es el mío).
Pensé que hacer que A incluyera un hash firmado de la clave a B le aseguraría a B que la clave realmente provenía de A. Sin embargo, Java en Android no puede cifrar el hash firmado porque es exactamente de 2048 bits ( como se esperaba). ¿Habría algún peligro con solo transmitir el hash firmado (Java RSA con SHA512) a plena vista? Según tengo entendido, los hashes son forzados a la fuerza bruta, lo que en este punto, de todos modos, es mejor que fueres la fuerza de la clave AES.
Editar: Como parece que la gente está llegando al corazón del problema: el cifrado sobre UDP, lo que está hecho está hecho. Voy a escribir cómo lo estoy haciendo actualmente. Es mi propio proyecto personal, así que doy la bienvenida a cualquier mejora. No estoy apegado emocionalmente al método actual.
(Todo esto tiene lugar sobre una conexión TLS existente ya que el socket "comando" es TCP)
- A genera la clave AES256 usando SecureRandom de java.
- A obtiene una copia de la clave pública de B del servidor.
- A envía una clave de cifrado RSA a B mediante el uso de RSA / NONE / OAEPWithSHA1AndMGF1Padding de android. Esto se elige para el relleno OAEP que (por lo que he leído) suena como el mejor método para hacer que la entrada a RSA se vea lo más aleatoria posible para evitar que la salida tenga ciertas características basadas en la entrada.
- B recibe el mensaje y envía un comando "ok" al servidor que le dice a A.
(El resto tiene lugar sobre UDP liso)
- A envía un mensaje a B usando AES / GCM / NoPadding del cifrado de Android. Se eligió GCM porque (por lo que he leído) es el mejor método para "cortar" los datos en partes seguras. Se supone que GCM debe contener un MAC, así que asumo que se encarga de la autenticación para mí. Se crea una instancia de una nueva instancia de cifrado para cada bloque de datos. Estoy asumiendo que el cifrado de android.init se encarga de la IV (nuevo para cada bloque). Después de cifrar. los datos se envían [longitud IV; IV; datos AES256 / GCM]. Por lo que he leído, el IV es como una sal que se usa para prevenir ataques precalculados. Normalmente, en una base de datos, la sal se almacena en texto plano, por lo que en este caso se transmite en formato plano. (Si no fuera así, se crea un problema de regresión infinita).
- B realiza el proceso inverso y envía una respuesta a A utilizando el método descrito anteriormente.
Se utiliza una nueva clave AES256 para cada sesión entre las 2 para el secreto hacia adelante. En términos de reproducción, los datos de texto sin formato tienen un número de secuencia. He visto fallas de descifrado de MAC en los registros al usar LTE al comienzo de la sesión. No he tenido una explicación plausible de por qué.