jueves, 15 de octubre de 2015

Jugando a los Dados

En muchas aplicaciones relacionadas con la seguridad es necesario generar información que no pueda ser adivinada por nuestros adversarios. Por ejemplo, cuando se crea un canal de comunicación seguro, protegido mediante algún algoritmo de cifrado tradicional, se emplea una clave de usar y tirar, llamada clave de sesión, que será válida solo para ese canal en concreto; si estamos creando un par de claves asimétricas, tendremos que emplear en el proceso unos parámetros únicos. Un atacante que fuera capaz de replicar de manera más o menos fiable esos valores, podría acceder a nuestras comunicaciones, incluso en el caso de que empleemos buena Criptografía.

Para obtener información que no pueda ser adivinada por otras personas necesitamos de los llamados generadores aleatorios. No obstante, existen diferentes tipos de generadores, en función de las propiedades que tengan los datos que se obtienen con cada uno de ellos. La primera gran distinción que podemos hacer es entre generadores pseudoaleatorios, y generadores aleatorios.

Los generadores pseudoaleatorios son aquellos que producen secuencias de valores a partir de una información inicial (llamada semilla). Para un mismo valor de la semilla, siempre se genera la misma secuencia. Muchos de estos generadores (como por ejemplo los congruenciales lineales, presentes en la mayoría de los lenguajes de programación) no están diseñados para aplicaciones criptográficas, por lo que únicamente generan secuencias que se comportan como si fueran aleatorias desde un punto de vista meramente estadístico. Por desgracia, con ellos resulta relativamente fácil deducir la totalidad de la secuencia a partir de un pequeño fragmento de la misma, por lo que si un atacante descubriera un valor que se ha empleado en el pasado, podría calcular cualquier otro valor, pasado o futuro.

Para que un generador pseudoaleatorio sea útil desde el punto de vista de la Criptografía, debe resultar indistinguible de un generador verdaderamente aleatorio para todos aquellos que desconozcan la semilla. Esto se traduce esencialmente en que, en ausencia de la semilla, la observación de un fragmento arbitrario de la secuencia no permite adivinar otro fragmento cualquiera (salvo que se prueben todas las semillas posibles, pero ese caso no cuenta, ya que su número es tan enorme que esa posibilidad queda fuera de cualquier computador o red de computadoras). Estos generadores, denominados criptográficamente aleatorios, pueden ser empleados incluso como base de un sistema de cifrado, pero de eso ya hablaremos otro día.

Los generadores aleatorios propiamente dichos carecen de semilla, y deben comportarse como si lanzáramos unos dados: las secuencias generadas sencillamente no pueden reproducirse. Por desgracia, las computadoras son máquinas deterministas, por lo que no se pueden producir secuencias verdaderamente aleatorias sin echar mano de elementos externos. Ya sea a través de hardware específico, a través de la actividad del usuario, o de cualquier elemento cuyo comportamiento pueda considerarse impredecible (microvariaciones en los tiempos de acceso a las pistas del disco duro, actividad de la red, etc.), el ordenador necesita emplear fuentes de entropía externas.

Pero de nada sirve tener unos dados, si esos dados están cargados. Si nuestra fuente de aleatoriedad genera unos u otros valores con diferentes probabilidades, aunque en efecto la secuencia sea aleatoria, un atacante podría realizar su búsqueda empezando por los valores más probables, reduciendo considerablemente el esfuerzo computacional promedio necesario para adivinar los valores de nuestro generador. Por eso no solo es importante  disponer de fuentes de aleatoriedad, sino que de alguna manera tenemos que limpiarlas para conseguir secuencias que sean aleatorias (impredecibles) y equiprobables (para que no se pueda priorizar una hipotética búsqueda).

La generación de números aleatorios es una tarea tan delicada como importante en aplicaciones relacionadas con la Seguridad. Llevarla a cabo incorrectamente puede hacer que nuestro sistema sea completamente inseguro, aunque luego utilicemos técnicas criptográficas fuertes