Las funciones hash como alternativa al cifrado para garantizar la autenticidad de los mensajes

Introducción
La técnica más sencilla de utilizar para garantizar la autenticidad de un texto que será enviado a través de una red es simplemente cifrarlo con una clave secreta, compartida únicamente por emisor y receptor. Con ello, se garantiza que el emisor es genuino, pues el receptor sólo puede descifrar el mensaje con la clave compartida con ese único emisor. Un oponente no puede enviar un mensaje, pues no tiene clave con la cual cifrarlo.
Una técnica un poco más avanzada es la de no cifrar el mensaje original, y, en cambio, sólo enviar un pequeño bloque de bits al final de los textos como referencia de autentificación. Sin embargo, así no se proporciona la confidencialidad, y cualquier oponente podrá leer los mensajes. Por ello, este enfoque se usa sólo en ciertas circunstancias, como cuando un mensaje tiene receptores múltiples, o un receptor es tan lento que gastaría muchos recursos al estar descifrando mensajes.
Aunque como tal no es un cifrado, pues no es reversible (haciéndolo más seguro), existe una técnica que utiliza una clave secreta, compartida por ambas partes, para crear un Código de Autentificación de Mensajes (MAC), el cual se calcula con dicha clave y el mensaje, y se añade al mismo. El receptor hace el mismo proceso, y con ello descubre dos cosas básicas: que el emisor es el indicado y que el mensaje no se ha alterado.
Puede obtenerse únicamente un resumen del mensaje, el cual será enviado anexo al mismo mensaje -tal como el MAC-, utilizando la técnica del cifrado; por dos métodos: uno con cifrado simétrico y otro con asimétrico. Con este último, se cumple la función de una firma digital: el mensaje sólo puede ser descifrado con la clave pública del emisor, quien ha cifrado el texto con su clave privada.
Sin embargo, se han buscado técnicas que eviten no sólo cifrar el texto, sino tampoco cifrar siquiera el resumen del mismo. Existe una técnica más sencilla pero más avanzada, pues implica un costo de hardware menor, un software más rápido, y un menor uso de algoritmos de cifrado, evitando cierto tipo de problemas: el uso de funciones hash, las cuales son el objeto de este escrito.

Desarrollo
Una función hash recibe un mensaje, de tamaño variable, y produce un resumen del mensaje, de tamaño fijo, el cual es enviado junto con el mensaje. Las funciones hash, en lugar de usar claves secretas, como un cifrado, utilizan un valor secreto común S. Un emisor concatena dicho valor con el mensaje, calcula la función hash determinada con esos valores, y envía dicho texto con el mensaje original. El receptor hace lo mismo, y con ello, al igual que con MAC, verifica que el mensaje no se ha alterado y que el emisor es el indicado.
Existen al menos seis características de una función hash. Las primeras tres determinan su facilidad de uso e implementación: pueden aplicarse a un bloque de datos de cualquier tamaño, producen una salida de tamaño fijo, y son relativamente fáciles de calcular, haciendo que tanto las implementaciones de hardware como de software sean prácticas.
Otras dos características son que es imposible encontrar el valor secreto dado el resumen del mensaje (propiedad unidireccional), y que es imposible encontrar un mensaje alternativo con el mismo valor hash que un mensaje dado. Si una función tiene los cinco atributos anteriores, se clasifica como función débil, mientras que tener la siguiente la clasifica como robusta: que es imposible que dos mensajes diferentes den resúmenes hash iguales.
Existen varias funciones hash, como las simples, SHA-1, MD5, RIPEMD-160, y HMAC. En todas ellas, el mensaje original es una secuencia de bloques de n bits, el cual es procesado bloque a bloque de forma iterativa para producir una función hash de n bits. A continuación, se describirá cada una de ellas.
En las funciones hash simples, todo el bloque de entrada se separa en varios bloques de longitudes iguales, y se obtiene un bit final de todos ellos, los cuales, al concatenarse, constituirán el código hash final. El bit final de cada bloque se calcula realizando un XOR entre todos los bits de ese bloque: ((1 XOR 2) XOR 3) XOR n.
La probabilidad de que un error en los datos resulte en un valor hash inalterable es 2-n, donde n es el número de bits; sin embargo, con datos más predecibles la función es menos efectiva (como cuando siempre el primer bit de un byte es 0, reduciendo su efectividad de 2-128 a 2-112.)
Para mejorar la seguridad del proceso anterior, se puede rotar un bit a la izquierda cada vez que se agregue un bit al valor hash final. Sin embargo, si el texto original es claro, este último paso no es significativo, pues sería relativamente fácil producir un mensaje diferente que produzca ese mismo código hash: le basta al atacante con crear el mensaje deseado y añadir un bloque de n bits que haga que el mensaje nuevo y el bloque produzcan el código hash deseado.
Una técnica más avanzada, propuesta por la NSA (National Standard Agency), consistía en realizar un XOR consecutivo de cada bloque de bits, en lugar de por cada bit de cada bloque, obteniéndose el código hash final. Por último, se realizaba un CBC con cada bloque del texto original y el código hash final, obteniéndose varios bloques.
En 1993, el NIST (National Institute of Standards and Technology) propuso un método mejor, el SHA-1, el cual toma un mensaje con una longitud máxima menor que 264 bits, la procesa en bloques de 512 bits, y produce un resumen de mensaje de 160 bits. Este algoritmo consta de cinco pasos fundamentales.
En el primer paso, se añade un bloque de relleno, aunque no sea necesario, para que el mensaje tenga una longitud igual a 64 bits menor que un múltiplo de 512 (448 mod 512); el primer bit de relleno es un 1, y el resto son 0.  Como segundo paso, se añade un bloque de 64 bits, que contiene la longitud del mensaje original sin relleno. Con esto, se tiene un mensaje con longitud igual a un múltiplo de 512 bits. El tercer paso es inicializar cinco bloques de 32 bits, conocido como búfer MD, con los cuales se obtendrán valores intermedios y finales de la función hash.
El cuarto paso, o función de compresión, es el más importante y complejo, en donde se procesan los bits. Consta de 4 etapas, de 20 pasos cada una, aunque cada una usa una función lógica diferente para tratar los datos. En cada etapa se toma un bloque de 512 bits y el valor del búfer de 160 bits, el cual se actualiza en cada etapa. También se usa una constante diferente en cada etapa. La salida de 160 bits.
Es poco probable que, con el SHA-1, dos mensajes aleatorios, aunque tengan regularidades similares, tengan el mismo código hash. A menos que este algoritmo tenga alguna debilidad secreta, la dificultad de dar con dos mensajes con el mismo resumen es del orden de 280 operaciones, mientras la dificultad de encontrar un mensaje con un resumen dado es del orden de 2160 operaciones.

Figura 1. Algoritmo SHA-1. Tomada de Fundamentos de Seguridad en Redes.

Otro algoritmo importante es el MD5, desarrollado por Ron Rivest. Era el algoritmo más utilizado hasta el surgimiento del SHA-1, pues éste toma una entrada de 512 bits y devuelve una salida de 128, a comparación de los 160 del SHA-1, garantizando menor seguridad debido al constante aumento de la velocidad de los procesadores. Se necesitan 264 operaciones para encontrar 2 mensajes iguales, y 2128 para obtener un mensaje a partir de su resumen, cantidades menores que aquellas del SHA-1.
El RIPEMD-160 fue desarrollado en el proyecto RIPE en Europa, por un grupo de hackers que lograron encontrar debilidades en el MD5. Su versión original fue modificada luego de que un programador ajeno al proyecto lograra encontrar debilidades en él. Es muy similar al SHA-1, pues recibe datos en bloques de 512 bits y devuelve resúmenes de 160.
El último algoritmo, HMAC, fue desarrollado para implementar un código hash criptográfico, es decir, que utilicen una clave secreta. De hecho, se le ha dado un mayor interés a este tipo de funciones, pues son más fáciles de implementar que un cifrado convencional, están disponibles en librerías, y no tienen restricciones de exportación, como ciertos algoritmos de cifrado.
Debido a ello, se creó tal algoritmo, HMAC, para satisfacer ciertos objetivos derivados de lo anterior, como usar las funciones hash que se ejecutan bien en software, con código gratis y fácil de conseguir, sin modificaciones; permitir la sustitución fácil de funciones en caso de que se encuentren o necesiten más rápidas o seguras; preservar el funcionamiento original de funciones sin incurrir en modificaciones significativas; usar y manejar claves de forma sencilla; entre otras.
El algoritmo del HMAC se resume en la siguiente fórmula:
HMACK (M) = H[K+ XOR opad)||H[K+ XOR ipad)||M]]
Lo que se traduce, muy burdamente, como la aplicación de la función hash a la concatenación de una clave rellena de ceros XOR la constante opad, con la concatenación de dicha clave XOR la constante ipad y el mensaje original.

Figura 2. Algoritmo HMAC. Tomada de Fundamentos de Seguridad en Redes.

Conclusión
En mi opinión, es más fácil la utilización de las funciones hash si el objetivo es únicamente garantizar que el emisor de un mensaje es quien dice ser, pues, si también se desea asegurar la confidencialidad de la información, las funciones hash no nos sirven de nada, pues sólo generan un resumen final de los datos, más no cifran como tal el texto.
Aunque el cifrar todo el texto, ya sea con cifrado simétrico (clave secreta) o asimétrico (claves privada y pública), garantiza que el emisor de un texto es auténtico, pues dicho texto no podría ser descifrado con una clave que no sea la secreta compartida o la privada del emisor, respectivamente, el uso de una función hash es, como ya se ha señalado, una alternativa mucho más viable, pues se evita la actividad de compartir claves, se reducen costos de hardware y tiempos de software, y se cumple con el objetivo de la autenticación.
A mí me gustaría haber visto este tema un poco más a detalle, pues se me hace interesante y más sencillo que la mayoría de los algoritmos de cifrado; pero, a pesar de ello, creo que aún prefiero el uso de dichos algoritmos, pues son más seguros y complejos para lograr su cometido de autenticar usuarios.

Fuentes bibliográficas
  • Stallings, Williams. Fundamentos de Seguridad en Redes: Aplicaciones y Estándares (segunda edición). Pearson Educación, S.A. Madrid, 2004. Págs. 59-71.
  • www.segu-info.com.ar/proyectos/p1_hash.htm
  • www.uco.es/servicios/biblioteca/CursosP/practicahash2.pdf
  • www.criptored.upm.es/intypedia/docs/es/video14/DiapositivasIntypedia014.pdf

Comentarios

Entradas populares de este blog

Kerberos: una de las aplicaciones más utilizadas como servicio de autentificación

El cifrado simétrico y asimétrico como mecanismo de seguridad para garantizar la confidencialidad, autentificación e integridad de los datos

El cifrado asimétrico: características, ventajas y algoritmos que lo utilizan