Mejores prácticas de seguridad: Cifrado simétrico con AES en Java y Android

Patrick Favre-Bulle
6 de enero, 2018 – 11 min read

En este artículo te pondré al día sobre el Estándar de Cifrado Avanzado (AES), los modos de bloque comunes, por qué necesitas vectores de relleno e inicialización y cómo proteger tus datos contra la modificación. Finalmente te mostraré cómo implementar esto fácilmente con Java evitando la mayoría de los problemas de seguridad.

Lo que todo ingeniero de software debe saber sobre AES

AES, también conocido por su nombre original Rijndael, fue seleccionado por el NIST en el año 2000 para encontrar un sucesor para el anticuado Data Encryption Standard(DES). AES es un cifrado por bloques, lo que significa que el cifrado se realiza en grupos de bits de longitud fija. En nuestro caso, el algoritmo define bloques de 128 bits. AES soporta longitudes de clave de 128, 192 y 256 bits.

Cada bloque pasa por muchos ciclos de rondas de transformación. Omitiré aquí los detalles del algoritmo, pero se remite al lector interesado al artículo de Wikipedia sobre AES. Lo importante es que la longitud de la clave no afecta al tamaño del bloque, sino al número de repeticiones de las rondas de transformación (la clave de 128 bits son 10 ciclos, la de 256 bits son 14)

Hasta mayo de 2009, los únicos ataques publicados con éxito contra el AES completo eran ataques de canal lateral en algunas implementaciones específicas. (Fuente)

¿Quieres encriptar más de un bloque?

Así que AES sólo encriptará 128 bits de datos, pero si queremos encriptar mensajes enteros necesitamos elegir un modo de bloque con el que se puedan encriptar múltiples bloques a un único texto cifrado. El modo de bloque más sencillo es el libro de códigos electrónico o ECB. Utiliza la misma clave inalterada en cada bloque así:

Imagen de Wikpedia

Esto es particularmente malo ya que bloques de texto plano idénticos son encriptados a bloques de texto cifrado idénticos.

La imagen encriptada con ECB El modo de bloque revela patrones del original (pruébalo tú mismo)

Recuerda que nunca debes elegir este modo a no ser que sólo encriptes datos menores de 128 bits. Desgraciadamente, todavía se utiliza mal a menudo porque no requiere que proporciones un vector inicial (más sobre esto más adelante) y, por lo tanto, parece ser más fácil de manejar para un desarrollador.

Sin embargo, hay que manejar un caso con los modos de bloque: ¿qué pasa si el último bloque no es exactamente de 128 bits? Ahí es donde entra en juego el padding, es decir, rellenar los bits que faltan del bloque. Lo más sencillo es rellenar los bits que faltan con ceros. Prácticamente no hay ninguna implicación de seguridad en la elección del relleno en AES.

Encadenamiento de bloques de cifrado (CBC)

Entonces, ¿qué alternativas a ECB hay? Por un lado, está el CBC, que XORiza el bloque de texto plano actual con el bloque de texto cifrado anterior. De este modo, cada bloque de texto cifrado depende de todos los bloques de texto plano procesados hasta ese momento. Utilizando la misma imagen que antes el resultado sería un ruido no distinguible de los datos aleatorios:

La imagen encriptada con el modo de bloque CBC parece aleatoria

¿Y qué pasa con el primer bloque? La forma más fácil es usar un bloque lleno de, por ejemplo, ceros, pero entonces cada cifrado con la misma clave y texto plano daría como resultado el mismo texto cifrado. Además, si se reutiliza la misma clave para diferentes textos planos, sería más fácil recuperar la clave. Una forma mejor es utilizar un vector de inicialización (IV) aleatorio. Esto es sólo una palabra elegante para los datos aleatorios que son del tamaño de un bloque (128 bits). Piénsalo como la sal del cifrado, es decir, un IV puede ser público, debe ser aleatorio y sólo se utiliza una vez. Tenga en cuenta, sin embargo, que no conocer el IV sólo dificultará el descifrado del primer bloque, ya que el CBC XORs el texto cifrado no el texto plano de la anterior.

Al transmitir o persistir los datos es común para sólo preagregar el IV al mensaje de cifrado real. Si estás interesado en cómo utilizar correctamente AES-CBC consulta la parte 2 de esta serie.

Modo de contador (CTR)

Otra opción es utilizar el modo CTR. Este modo de bloque es interesante porque convierte un cifrado de bloque en un cifrado de flujo, lo que significa que no se necesita relleno. En su forma básica todos los bloques se numeran de 0 a n. Cada bloque será ahora cifrado con la clave, el IV (también llamado nonce aquí) y el valor del contador.

Imagen de Wikpedia

La ventaja es, a diferencia de CBC, el cifrado puede hacerse en paralelo y todos los bloques dependen del IV, no sólo el primero. Una gran advertencia es que un IV nunca debe ser reutilizado con la misma clave porque un atacante puede calcular trivialmente la clave utilizada a partir de ella.

¿Puedo estar seguro de que nadie ha alterado mi mensaje?

La dura verdad: el cifrado no protege automáticamente contra la modificación de datos. De hecho, es un ataque bastante común. Lee aquí una discusión más profunda sobre este tema.

¿Entonces qué podemos hacer? Simplemente añadimos un Código de Autenticación de Mensaje (MAC) al mensaje encriptado. Un MAC es similar a una firma digital, con la diferencia de que la clave verificadora y la autentificadora son prácticamente la misma. Hay diferentes variaciones de este método, el modo que recomiendan la mayoría de los investigadores se llama Encrypt-then-Mac. Es decir, después del cifrado se calcula una MAC sobre el texto cifrado y se añade. Normalmente se utiliza el código de autenticación de mensajes basado en Hash (HMAC) como tipo de MAC.

Así que ahora empieza a complicarse. Para la integridad/autenticidad tenemos que elegir un algoritmo MAC, elegir un modo de etiqueta de cifrado, calcular el mac y anexarlo. Esto también es lento ya que todo el mensaje debe ser procesado dos veces. El lado opuesto tiene que hacer lo mismo pero para desencriptar y verificar.

Encriptación autenticada con GCM

¿No sería genial si hubiera modos que manejaran todo el tema de la autenticación por ti? Afortunadamente existe una cosa llamada encriptación autenticada que proporciona simultáneamente garantías de confidencialidad, integridad y autenticidad sobre los datos. Uno de los modos de bloque más populares que admite esto se llama Modo Galois/Contador o GCM para abreviar (por ejemplo, también está disponible como un conjunto de cifrado en TLS v1.2)

GCM es básicamente el modo CTR que también calcula una etiqueta de autenticación secuencialmente durante el cifrado. Esta etiqueta de autenticación se suele añadir al texto cifrado. Su tamaño es una propiedad de seguridad importante, por lo que debe tener una longitud mínima de 128 bits.

También es posible autenticar información adicional no incluida en el texto plano. Estos datos se denominan datos asociados. ¿Por qué son útiles? Por ejemplo, los datos encriptados tienen una metapropiedad, la fecha de creación, que se utiliza para comprobar si el contenido debe volver a ser encriptado. Un atacante podría ahora cambiar trivialmente la fecha de creación, pero si se añade como dato asociado, GCM también verificará esta pieza de información y reconocerá el cambio.

Una discusión acalorada: ¿Qué tamaño de clave usar?

Pues la intuición dice: cuanto más grande mejor – es obvio que es más difícil forzar un valor aleatorio de 256 bits que uno de 128 bits. Con nuestros conocimientos actuales, forzar todos los valores de una palabra de 128 bits requeriría una cantidad astronómica de energía, que no es realista para nadie en un tiempo sensato (mirándote a ti, NSA). Así que la decisión es básicamente entre infinito e infinito veces 2¹²⁸.

AES en realidad tiene tres tamaños de clave distintos porque ha sido elegido como un Algoritmo Federal de EE.UU. Apto para ser utilizado en varias áreas bajo el control del gobierno federal de EE.UU. . (…) Así que a los finos cerebros militares se les ocurrió que debía haber tres «niveles de seguridad», de modo que los secretos más importantes se cifraran con los métodos pesados que merecían, pero los datos de menor valor táctico pudieran cifrarse con algoritmos más prácticos, aunque más débiles. (…) Así que el NIST decidió seguir formalmente la normativa (pedir tres tamaños de clave) pero también hacer lo más inteligente (el nivel más bajo debía ser irrompible con tecnología previsible)(Fuente)

El argumento es el siguiente: un mensaje encriptado con AES probablemente no se romperá por fuerza bruta de la clave, sino por otros ataques menos costosos (no conocidos actualmente). Estos ataques serán tan dañinos para el modo de clave de 128 bits como para el modo de 256 bits, por lo que elegir un tamaño de clave mayor no ayuda en este caso.

Así que básicamente la clave de 128 bits es suficiente seguridad para la mayoría de los casos de uso con la excepción de la protección de los ordenadores cuánticos. Además, el uso de 128 bits encripta más rápido que 256 bits y el esquema de claves de 128 bits parece estar mejor protegido contra los ataques de claves relacionadas (sin embargo, esto es irrelevante para la mayoría de los usos del mundo real).

Como una nota lateral: ataques de canal lateral

Los ataques de canal lateral son ataques que tienen como objetivo explotar los problemas específicos de ciertas implementaciones. Los esquemas de cifrado en sí mismos no pueden estar protegidos intrínsecamente contra ellos. Las implementaciones simples de AES pueden ser propensas a ataques de sincronización y de caché, entre otros.

Como ejemplo muy básico: un algoritmo simple que es propenso a ataques de sincronización es un método equals() que compara dos matrices de bytes secretas. Si el equals() tiene un retorno rápido, es decir, después del primer par de bytes que no coinciden termina el bucle, un atacante puede medir el tiempo que tarda el equals() en completarse y puede adivinar byte por byte hasta que todos coincidan.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *