fernando_acero (fernando_acero) wrote,
fernando_acero
fernando_acero

Jugando con números aleatorios en Linux





En este mundo altamente digitalizado, nuestra seguridad lógica depende en gran medida de la calidad de los números aleatorios que se utilizan para generar claves criptográficas y para otras funciones relacionadas con la seguridad de los sistemas y de las comunicaciones. Los números aleatorios están presentes en los cajeros automáticos, en los chips inteligentes, cifradores, routers, etc. Por ello, no es de extrañar, que tras desvelarse las oscuras maniobras de la NSA para espiar a todo el mundo, rápidamente se sospechase de la seguridad real de los sistemas de generación de números aleatorios, tanto de software como de hardware. Pero este no es el único problema que tenemos que tener en cuenta en relación con los números aleatorios, puesto que además de la calidad, también afecta a nuestra seguridad la cantidad de números aleatorios a los que podemos acceder en un determinado momento.


LAS PISCINAS DE ENTROPÍA

Hay casos documentados de ataques exitosos a sistemas por un mal diseño de un generador de números aleatorios. Uno de los más famosos, es el que comenta Kevin Mitnick en el primer capítulo de su libro "El arte de la intrusión". Es una historia real en la que unos amigos realizando ingeniería inversa de varias máquinas de casino, descubren que el generador de números aleatorios utilizado en las mismas, es realmente una secuencia muy larga de números y que tarde o temprano se repite. De esta forma, logran predecir el momento exacto en el que la máquina dará el premio. Este descubrimiento les permitió entrar en los casinos y ganar grandes sumas de dinero, lo que se prolongó varios años hasta que uno de ellos fue pillado en un casino usando el ordenador que hacía los cálculos escondido entre su ropa.

Otro caso famoso, fue el fallo del navegador NETSCAPE a la hora de generar los números aleatorios necesarios para las sesiones SSL. Este fallo que hacía predecibles los números aleatorios usados, permitía que un atacante pudiera ver el tráfico cifrado entre el servidor y dicho navegador sin el conocimiento del usuario.

Cuando trabajamos con Linux, los números aleatorios están disponibles en dos dispositivos, también denominados piscinas de entropía, denominados /dev/random y /dev/urandom. Recordemos que Linux tiene el honor de ser el primer sistema operativo que disponía de un generador aleatorio integrado en el kernel del sistema, aunque también es cierto, que hay algunos estudios del año 2013 que sostienen que el generador de números aleatorios de Linux no es tan bueno como debiera. Estos estudios se basan en que un ordenador determinista y un programa no son la mejor forma de lograr números aleatorios. Es decir los ordenadores están diseñados para no ser aleatorios, más bien todo lo contrario, no deben serlo y ante una determinada entrada, siempre deben proporcionar de forma previsible una misma salida, lo que evidentemente no es demasiado aleatorio. Pero como veremos hay métodos para comprobar lo buenos que son nuestros números aleatorio y para mejorar su generación.

Para intentar paliar el problema del determinismo, el sistema operativo Linux recopila entropía de los contradores de dispositivo y de otras fuentes, como el teclado, ratón o el reloj del sistema y posteriormente, aplica algoritmos de hash para intentar generar unos números aleatorios, o lo que es lo mismo, impredecibles. Sin embargo, mediante este método, la cantidad disponible de números aleatorios es limitada. Es decir, cuando la fuente de entropía /dev/random está vacía, las lecturas de este dispositivo se bloquearán hasta que se logre llenar de nuevo con más números aleatorios. Es decir, /dev/random se comporta como una especie de "one-time-pad" que garantiza que los números aleatorios ya utilizados no se pueden volver a utilizar.

Por estas características el dispositivo /dev/random está pensado para ser usado cuando se requieran unos números aleatorios de elevada calidad. Como por ejemplo, cuando es necesario generar claves criptográficas, o cuando se desea borrar un disco o un archivo de forma segura mediante sobreescritura aleatoria bit a bit. El comportamiento de /dev/random lo podemos comprobar introduciendo el siguiente mandato en una consola:

hexdump -C /dev/random

Tras pulsar la tecla Enter, veremos que aparecen una serie de números aleatorios en hexadecimal, pero que al poco tiempo el listado en pantalla se para. Esto se debe a que se han gastado los números aleatorios disponibles en dicha piscina de entropía. Para continuar, tendremos que añadir más entropía al sistema, lo que se suele hacer moviendo el ratón por la pantalla, pero ¿es una buena fuente de entropía adicional el movimiento del ratón?. Luego veremos unas posibles soluciones al problema.

Si queremos saber la cantidad de entropía disponible en nuestro dispositivo /dev/random, debemos usar este mandato desde la consola:

cat /proc/sys/kernel/random/entropy_avail
568

Evidentemente, con el avance del tiempo, al aumentar el tamaño de las claves y con el uso de sistemas mas seguros que hacen un uso extensivo de funciones criptográficas, también han aumentado las necesidades de números aleatorios. De esta forma, en una Mandriva de 2010, lo normal era que el mandato anterior diera valores inferiores a 200, mientras que en una Ubuntu 14.04 LTS, la entropía disponible rondará un valor entre 650 y 780, aunque como veremos, puede que este valor sea pequeño para algunos usos, Un caso típico sería generar una clave RSA de 4096 bits.

Por otra parte, el dispositivo /dev/urandom devolverá tantos bytes como se soliciten. Como resultado, si no hay suficiente entropía, es decir, si no hay suficientes números en dicho dispositivo, la salida no se bloqueará y seguirá proporcionando valores, lo que puede provocar que no sean tan aleatorios como pensamos y haciéndolos vulnerables a determinados ataques.

Por este motivo, /dev/urandom no se debe utilizar cuando la seguridad sea fundamental, por ejemplo, cuando deseamos generar una clave de larga duración GPG o SSL. No es así, por ejemplo, cuando lo que queremos es crear un programa de simulación que necesite una entrada de valores razonablemente aleatorios. Usando /dev/urandom nos aseguramos de que el programa no se detiene por la falta de números aleatorios. Como en el caso anterior, podemos abrir una consola y usar el mandato para ver su comportamiento:

hexdump -C /dev/urandom

Como hemos anticipado, en este caso el listado de números no se detiene, pero también es posible que la calidad de los datos aleatorios generados no sea muy buena.


PROBANDO NUESTROS GENERADORES ALEATORIOS

¿Cómo podemos medir la calidad de nuestros números aleatorios generados por /dev/random y /dev/urandom?. El proceso es relativamente sencillo. Para ello podemos usar el mandato Linux ent, que se encarga de medir la entropía de archivos binarios. Para ello, generaremos dos archivos a partir de los valores de /dev/random y /dev/urandom. pero para que los datos estén generados en las mismas condiciones en las dos piscinas, lo primero que debemos hacer es comprobar la cantidad de entropía que tenemos disponible en /dev/random, lo que haremos mediante el mandato:

cat /proc/sys/kernel/random/entropy_avail
1100

Si usamos este mandato varias veces, veremos que la cifra cambia. Para no superar el valor de entropía disponible en /dev/random elegiremos un tamaño de archivo con un valor inferior a todos los valores obtenidos tras realizar varias pruebas. En este caso usaremos un valor de 1000 caracteres, que es inferior a 1100:

dd if=/dev/random of=rnd.test bs=1c count=1000
1000+0 registros leídos
1000+0 registros escritos
1000 bytes (1,0 kB) copiados, 0,0695683 s, 14,4 kB/s

Seguido del mandato:

dd if=/dev/urandom of=urnd.test bs=1c count=1000
1000+0 registros leídos
1000+0 registros escritos
1000 bytes (1,0 kB) copiados, 0,0739844 s, 13,5 kB/s

Una vez que hemos creado los archivos rnd.test y urnd.test de 1K de tamaño cada uno de ellos, usaremos los mandatos siguientes:

ent rnd.test
Entropy = 7.820170 bits per byte.

Optimum compression would reduce the size
of this 1000 byte file by 2 percent.

Chi square distribution for 1000 samples is 227.26, and randomly
would exceed this value 75.00 percent of the times.

Arithmetic mean value of data bytes is 131.8870 (127.5 = random).
Monte Carlo value for Pi is 2.915662651 (error 7.19 percent).
Serial correlation coefficient is 0.013190 (totally uncorrelated = 0.0).

Seguido de:

ent urnd.test
Entropy = 7.790775 bits per byte.

Optimum compression would reduce the size
of this 1000 byte file by 2 percent.

Chi square distribution for 1000 samples is 255.94, and randomly
would exceed this value 50.00 percent of the times.

Arithmetic mean value of data bytes is 129.5400 (127.5 = random).
Monte Carlo value for Pi is 3.349397590 (error 6.61 percent).
Serial correlation coefficient is 0.009675 (totally uncorrelated = 0.0).

Como podemos ver, el valor de la entropía es superior en el caso del archivo rnd.test. El nivel de compresión que permiten ambos archivos de un 2%, siendo lo ideal para una entropía absoluta una compresión de un 0%. Este valor es muy dependiente del tamaño del archivo, por lo que es más probable que se logre una compresión del 0% en archivos de mayor tamaño.

Asimismo, veremos los valores de la distribución Chi cuadrado (distribución de Pearson). Esta función es la prueba más utilizada para comprobar que una serie de datos es aleatoria y es muy sensible a los errores que se producen en con los generadores pseudoaleatorios. Esta función se calcula a partir de la secuencia de bytes del archivo y se expresa en la forma de un valor y de un porcentaje, que indica lo frecuente que un valor verdaderamente aleatorio debería exceder el valor calculado.

Dicho valor se debe interpretar como el porcentaje de veces en la que la secuencia probada es sospechosa de no ser aleatoria. Es decir, si el porcentaje es mayor de 99% o menor del 1% podemos decir que la secuencia no es aleatoria. Si el porcentaje está entre el 99% y el 95% o entre el 1% y el 5%, podemos decir que la secuencia es posiblemente no aleatoria. Porcentajes entre el 90% y el 95% o entre el 5% y el 10% nos indican que la secuencia podría ser no aleatoria.

Como referencia, estos son los valores que muestra dicha función, ante una secuencia procedente de un generador de números aleatorios reales basado en la descomposición radiactiva.

Chi square distribution for 32768 samples is 237.05, and randomly
would exceed this value 75.00 percent of the times.

Si comparamos este valor, procedente de un generador aleatorio de alta seguridad, con los valores que acabamos de obtener anteriormente con nuestros /dev/random y /dev/urandom, veremos que nuestros generadores aleatorios no son nada malos en base a los valores obtenidos para la distribución de Pearson.

Al margen de lo anterior, los valores obtenidos en este caso para la media aritmética, el valor de Pi (Monte Carlo) y para el coeficiente de correlación de la serie, aparentemente son mejores para la piscina de entropía /dev/urandom. Hay que señalar, que estos resultados comparativos no son demasiado significativos si solamente se obtienen una vez, sobre todo, si los ambos generadores son medianamente buenos, como parece que es el caso. Estos valores pueden cambiar de forma significativa entre pruebas consecutivas, por lo que se recomienda realizar varias mediciones y efectuar un análisis estadístico de las mismas, si queremos evaluar con más precisión o certeza la bondad de nuestros generadores de números aleatorios.

Como hemos visto, el mandato ent solamente sirve para archivos binarios, sin embargo, en ocasiones podemos disponer de listados de números aleatorios en formato hexadecimal en modo texto ASCII procedente de otras fuentes, por ejemplo de la página Random.org,, que es un servicio que proporciona números aleatorios con fines científicos o didácticos. Para poder verificar la calidad de los mismos, es necesario pasarlos a binario, para lo que podemos utilizar la utilidad SFK o en castellano, la "navaja suiza para ficheros".

Otro mandato que nos vendrá muy bien para convertir volcados hexadecimales de números aleatorios a binario y viceversa, es xxd. Por ejemplo, para convertir un binario a hexadecimal plano, debemos usar el mandato:

xxd -p RANDOM.BIN > RANDOM.TXT

La opción -p es la que indica que lo que deseamos es un volcado hexadecimal en formato plano, es decir, sin equivalencia de caracteres, espacios, ni posición en el archivo. Para la operación inversa usaremos el mandato:

xxd -p -r RANDOM.TXT > RANDOM.BIN

En este caso la opción -p indica que el origen es un volcado plano y la opción -r, que lo queremos es realizar la operación inversa, es decir, convertir un archivo de texto en binario.

También podemos concatenar archivos convertidos a texto o a binario usando >> en lugar de > en dichos mandatos y modificando el archivo de origen de forma sucesiva.

Este mandato nos será de mucha utilidad cuando trabajemos con los generadores de números aleatorios de las tarjetas inteligentes.


COMPROBANDO Y FILTRANDO UN FLUJO DE DATOS ALEATORIOS CON RNGTEST

Alternativamente, para comprobar nuestro generador de números pseudoaleatorios /dev/urandom, podemos usar el mandato rngtest, que está disponible en el paquete rng-tools de Linux, mediante el mandato:

cat /dev/urandom | rngtest -c 1
rngtest 2
Copyright (c) 2004 by Henrique de Moraes Holschuh
This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

rngtest: starting FIPS tests...
rngtest: bits received from input: 20032
rngtest: FIPS 140-2 successes: 1
rngtest: FIPS 140-2 failures: 0
rngtest: FIPS 140-2(2001-10-10) Monobit: 0
rngtest: FIPS 140-2(2001-10-10) Poker: 0
rngtest: FIPS 140-2(2001-10-10) Runs: 0
rngtest: FIPS 140-2(2001-10-10) Long run: 0
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
rngtest: input channel speed: (min=18.626; avg=18.626; max=18.626)Gibits/s
rngtest: FIPS tests speed: (min=136.239; avg=136.239; max=136.239)Mibits/s
rngtest: Program run time: 189 microseconds

En el mandato anterior hemos usado la opción -c 1, que limita el análisis a un único bloque, ya que se necesita como mínimo un bloque de 20.000 bits para pasar las pruebas FIPS 140-2 (monobit, póquer, rachas y rachas largas y ejecución continua).

En este caso, el mandato rngtest ejecuta una serie de pruebas estadísticas diseñadas por la NSA y publicadas por el NIST, que deben pasar con éxito los generadores de números pseudoaleatorios para considerarse seguros.

Una cosa interesante de este mandato, es que también lo podemos usar para mejorar nuestros generadores de números pseudoaleatorios mediante la opción -p que activa el modo "pipe" y que envía a la salida estándar solamente los bloques de 20.000 bits que han pasado con éxito las pruebas FIPS, lo que podemos probar mediante el mandato:

cat /dev/urandom | rngtest -p -c 10 | hexdump

Veamos ahora la forma en la que se realizan cada uno de estos tests FIPS:

a) Test monobit

Se cuenta el número de bits iguales a uno en una secuencia de datos aleatorios de como mínimo 20.000 bits. El test se pasa si dicho número está entre los valores 9.275 y 10.275.

b) Test póquer

En este caso se divide una secuencia de 20.000 bits en 5.000 segmentos contiguos de 4 bits. Después se cuenta y se almacena el número que ocurre cada uno de los 16 valores posibles, siendo f(v) el número de veces que apareció el valor v 0<=v<=15. Luego se calcula la expresión X = (16/5000) * ( f(1)^2 + f(2)^2 + ... + f(15)^2) – 5000. El test se pasa con éxito si 2,16 < X < 46,17.

c) Test de rachas

Una racha se define como una subsecuencia máxima de bits consecutivos de unos o de ceros y que forman parte de la secuencia inicial de 20.000 bits. Para el test se cuentan las ocurrencias para las rachas de 1 a 6 bits. El test se pasa si el número de rachas que ocurren (de longitudes 1 a 6) están en los intervalos especificados en la siguiente tabla, lo que se deberá verificar tanto para las rachas de ceros y de unos. Las rachas de longitud superior a 6 se considerarán de longitud 6.

Longitud Número de ocurrencias
1 2.343 - 2.657
2 1.135 - 1.365
3 542 - 708
4 251 - 373
5 111 - 201
6 111 - 201

d) Test de rachas largas

Una racha larga se define como una racha de longitud 26 o más, con independencia de que sea de ceros o de unos, el test se pasa si en el bloque de 20.000 bits no hay rachas largas.

e) Test de ejecución continua

Para este test se divide el flujo de entrada en bloques de como mínimo 16 bits, adaptándose al tamaño de bloque del generador si es superior a 16 bits. Para el test, el primer bloque de 16 bits se compara con el segundo bloque de 16 bits, el segundo bloque será válido si no es idéntico al primero, de otro modo se considerará un fallo del generador. El segundo bloque de 16 bits será comparado con el tercero y así sucesivamente hasta terminar todos los bits de entrada.


EL PROBLEMA DE LO ESTÁTICO

Cuando un sistema Linux arranca sin mucha interación con el operador, el almacén de entropía puede estar en un estado relativamente predecible, por la reducción en la cantidad de "ruido" presente en el sistema y que es lo que se usa principalmente para generar números aleatorios. Para evitar este problema, podemos usar varios trucos aprovechando que los dispositivos /dev/random y /dev/urandom son de lectura y escritura. Por ejemplo, podemos guardar la información que habría presente en la piscina de entropía para ser usada como "semilla" en el siguiente arranque. Para ello podemos hacer un script que se ejecute durante el apagado del sistema con los mandatos siguientes:

dd if=/dev/urandom of=/var/semilla_urandom count=1
dd if=/dev/random of=/var/semilla_andom count=1

Con ello hemos creado en el directorio del sistema /var/ dos archivos con el estado de /dev/random y /dev/urandom en el momento de apagar el sistema.

Después añadiremos otro script para el arranque del sistema con los mandatos:

if [ -f /var/semilla_urandom]; then
cat /var/semilla_urandom > /dev/urandom
fi
dd if=/dev/urandom of=/var/semilla_urandom count=1

if [ -f /var/semilla_random]; then
cat /var/semilla_random > /dev/random
fi
dd if=/dev/random of=/var/semilla_random count=1

Dicho script comprueba la existencia de los archivos /var/semilla_urandom y /var/semilla_random y en caso afirmativo, los copia en los dispositivos /dev/urandom y /dev/random y en caso contrario los crea adecuadamente.

Evidentemente este problema de seguridad relacionado con la falta de enotropía es especialmente grave en los sistemas "live", en los sistemas creados con herramientas para realizar un "snapshot" de sistemas, como Gost o similar, y en las imágenes virtualizadas, cuando se realizan arranques sucesivos. En todos estos casos las piscinas de entropía empiezan desde la misma situación inicial una y otra vez, por lo que los sistemas que las usan son vulnerables hasta que se genere entropía nueva, lo que puede tardar un poco si hay poca interacción con el usuario.

En estas situaciones y sobre todo, si vamos a usar dichas imágenes de los sistemas para tareas relacionadas con la seguridad o la criptografía, como generar claves criptográficas, acceder a páginas web seguras, o cualquier otra tarea que requiera disponer números aleatorios de cierta calidad, deberíamos obtener un archivo con entropía de calidad desde otro sistema e inyectarla en las piscinas de entropía del sistema estático, escribiendo sobre ellas, antes de comenzar a usar el sistema.


JUGANDO CON GENERADORES DE HARDWARE

Una forma sencilla de acceder a un generador de números aleatorios por hardware es mediante el uso de una tarjeta inteligente, puesto que todas ellas llevan uno integrado para la generación de claves. Para mis pruebas he usado una tarjeta CERES modelo "krirptonita" de la FNMT, ya que es una tarjeta que tiene unos controladores que funcionan perfectamente bajo mi Ubuntu 14.04 y que además, son compatibles con el dnie. Como es lógico, para que esto funcione también es necesario disponer de un lector de tarjetas inteligentes conectado a nuestro sistema y con sus controladores adecuadamente instalados.

Una vez insertada la tarjeta en el lector, usaremos el mandato siguiente para conectar con ella:

opensc-explorer --reader 0 -c dnie

En este mandato usamos el lector 0 y el controlador dnie, que es el que se corresponde al de la tarjeta CERES,

En el prompt que nos aparece, escribiremos el mandato random 128, puesto que este es el mayor número de números aleatorios que puede generar esta tarjeta cada vez. Cuando queramos salir del entorno de opensc-explorer, escribiremos exit seguido de intro:

OpenSC Explorer version 0.12.3-svn
OpenSC [3F00]> random 128
00000000: F2 AC 2A 78 C5 C2 B1 30 A4 41 B6 28 31 7F 46 C4 ..*x...0.A.(1.F.
00000010: FB A4 E9 AC 01 B4 B8 36 36 57 E3 84 7F 23 17 2F .......66W...#./
00000020: D9 28 70 7D 7F 56 85 99 80 58 E8 E7 10 C0 C1 64 .(p}.V...X.....d
00000030: CE 07 EB BB 3D 1A 29 B9 49 CF DE F6 66 97 EC 66 ....=.).I...f..f
00000040: 3B 74 2E 01 0B E9 5A CD D2 07 11 0C 78 DA 12 69 ;t....Z.....x..i
00000050: 26 E5 7F 7F 4D 18 C4 2C 84 89 18 BC B1 7F 11 0B &...M..,........
00000060: 21 4A E2 EB C1 F5 7B 14 27 12 8E 39 55 A4 EB B6 !J....{.'..9U...
00000070: E7 CA A1 1C 85 9A 6F 90 89 19 D8 F0 BF 6B D0 80 ......o......k..
OpenSC [3F00]> exit

Ahora podemos generar varios bloques y jugar con la opción -p (plain) del mandato xxd para generar un archivo de mayor tamaño, Por ejemplo,yo he concatenado 10 bloques random y he generado este archivo:

900a522fd7a1f317eecdd7d645938e7fbe6a8ceda037d7750bd6af9c7d0d
712ddf4d3aca9ecb7b9eec364df34416590e21b8bcc6a1706b807b0222bc
564406e5a21c13aa8c9a3d5d5df106ad45dd6a13092372a70d1d22a081ca
6a264ad08eca022d5b2f4f15829f4d856b5282d0d3932e2f41ac15ffdc9e
352f94165ad12cfffa20bd47c5a3f99dac69e4bcf135140338d32d12632e
9a3b60eb99e1c404cbe620ec09df62cb49080442d889e8849f7eb9840d17
4d62fc51e4423e7349f254bea443ab2f2c31f67aa97bd8f249d2ecac4d65
fa47be7f163ef5242456001e3b40606cafe54b4c14e3d547659526af973c
6f9438079404ef1fba5245d081d866576baf89d9b0313c47bd11566d38e3
8585a06f223bddcdba4dcb96c6b2469d5b0aae37dd4d2dd1365b59abf4a6
d115b273e6cfb6883cd0ac5fee64c93228109b4a2e5ee2d0bd287f53a97c
cefcfb82364b797fcc94c5400b97a4bb625f71c859e49bfd3632aecb8642
e6492cdfe9ed816e257c5c7e3a0c261a611faff7f81991f7819c9fbc8575
fc52644efdebc8e0eb5683396a9ae3c26c22aded3f9ad97c9f2133d902ef
b61284271f106cafb983413ff388992396b5cfcb4caf0c19994dc4ef7620
690142af8ce359d1916308781a366cef594ccf2177c1337327cab55c67fe
48183e2e8c96364a5b39d867da7846b4d55199844377f452e13f4f877b30
7edf4098ffd956fcafc75c317708d4a4bcd73bfe3c3e2eaa3062190d2196
c1117e25df37971432f41673f60b130b6ec369e5e02206ec38b06525ee12
8040b394f507e050dcc95fa11e8fbbd0535f611d836a0f21933dd9a4e634
f8aa8332f08a78ed5b985f023799c0cf7bff14040675b47d5f540e804a9f
de23027014a9258ba1472587d01c9d1befda8042f85ca471495426a0800b
e745552d8c33fca90120bead2bdf2dbab5c8a848518e53f3708de54bbcdb
2f0de596fc3a61d8e5112382f2a88d5cdc20d90bbcaeeaa4b43258adca88
e1b7a12f96d3b4e29b445873b05d870c532ab75a5f0662c28f89866f05a2
0b4a487f4c61752284aa559a0f7ba94581ae94f8d12e1f6956a4017be043

Posteriormente, he usado el mandato xxd con las opciones -r y -p para generar un binario que podemos analizar con el mandato ent:

ent fnmt_random.bin
Entropy = 7.889725 bits per byte.

Optimum compression would reduce the size
of this 1952 byte file by 1 percent.

Chi square distribution for 1952 samples is 326.03, and randomly
would exceed this value 0.50 percent of the times.

Arithmetic mean value of data bytes is 125.0840 (127.5 = random).
Monte Carlo value for Pi is 3.089230769 (error 1.67 percent).
Serial correlation coefficient is 0.002788 (totally uncorrelated = 0.0).

Hay que señalar, que si la muestra obtenida con el generador no es lo suficientemente grande, es posible que los resultados del análisis no sean demasiado buenos. Alternativamente, si concatenamos suficientes bloques de 128 números aleatorios (8 bits), como para poder obtener más de 20.000 bits lo podemos analizar en base a las pruebas FIPS con el mandato rngtest:

cat fnmt_random.bin | rngtest


AUMENTANDO LA CANTIDAD DE ENTROPÍA DISPONIBLE

Como hemos dicho, tan problemático es disponer de una entropía de calidad, como el disponer de una cantidad suficiente de entropía en la piscina /dev/random. Una solución al problema podría ser la utilización de un generador de entropía basado en hardware, entre los distintos modelos que hay en el mercado. De hecho, teniendo en cuenta los problemas para obtener números aleatorios de calidad a partir de soluciones de software, algunos fabricantes comenzaron a añadir en sus placas base dispositivos de generación de números aleatorios. Un ejemplo lo tenemos en el chip Bull Mountain. La polémica aparece, cuando en pleno debate sobre el espionaje de la NSA, se descubre que dicho chip cuando funciona en Linux no se usa realmente para aumentar la entropía de la piscina de Linux y mejorar su calidad. En su lugar, Intel añadió al núcleo de Linux una función denominada RdRand, que permite acceder directamente al chip, lo que algunos consideraron una amenaza al no poder auditar el chip.

Por cierto, si no queremos que el núcleo de Linux use esta función para obtener números aleatorios de una fuente no auditable, solamente tenemos que añadir en la configuración de grub el parámetro "norand" para el arranque del núcleo. Para ello, editaremos el archivo /etc/default/grub y modificaremos la línea GRUB_CMDLINE_LINUX, para que aparezca como GRUB_CMDLINE_LINUX="norand", tras grabar este archivo, la próxima vez que arranquemos el sistema ya no usará el generador de números aleatorios por hardware.

Visto lo anterior, una solución muy interesante y elegante podría ser la utilización en nuestro sistema de un generador aleatorio basado en hardware abierto, evitando así las dudas existentes con otros dispositivos de hardware cerrados.

Alternativamente también tenemos una solución por software que nos permitirá aumentar la entropía del sistema y mejorarla al considerar otras fuentes de ruido. Se trata del demonio Linux haveged, que como su nombre indica, se basa en el algoritmo havege. Dicho algoritmo se basa en el hecho de que el tiempo de ejecución de una pieza determinada de software no se puede repetir incluso en una máquina en reposo.

Para su funcionamiento usa algunas capacidades ocultas de los procesadores, tales como instrucciones ocultas y el caché de datos, así como las tablas de translación de memoria virtual asociadas. Havege usa las diferencias en el contador de tiempo de ejecución del procesador durante la ejecución de un bloque determinista de código, que recolecta estas variaciones en el sistema. El bucle está diseñado para que ejecute instrucciones y para que afecte al caché de datos, aumentando así la variación de la entropía.

Para usarlo, solamente hay que instalar el paquete haveged y posteriormente editar como root el archivo /etc/default/haveged para que genere la cantidad de entropía que queramos. Por ejemplo, para generar una piscina de entropía de 1024 usaremos el mandato:

DAEMON_ARGS="-w 1024"

Una vez definido este valor habrá que asegurarnos de que haveged tiene en cuenta estos cambios en el siguiente arranque, para lo que usaremos el siguiente mandato en una consola como root:

update-rc.d haveged defaults

Seguido de lo siguiente, también como root:

cd /etc/init.d
./haveged restart

Ahora notaremos dos cambios importantes, si usamos el mandato:

cat /proc/sys/kernel/random/entropy_avail

Veremos que ha aumentado el tamaño de nuestra piscina de entropía, asimismo, si usamos el mandato siguiente:

hexdump -C /dev/random

Es posible que el listado no se pare como ocurría antes de activar el demonio haveged. Asimismo, si probamos la calidad de los números aleatorios generados usando los métodos descritos anteriormente, es posible que podamos comprobar que la calidad de los mismos es mayor.


"Copyleft Fernando Acero Martín. Se permite la copia textual, la traducción y la distribución de este artículo entero en cualquier medio, a condición de que este aviso sea conservado. Se permite la cita. El autor no reclamará ninguna cantidad por el ejercicio de las dos autorizaciones anteriores. No autorizo a ninguna Entidad de Derechos de Autor a reclamar cantidad alguna en mi nombre."

Tags: entropía, haveged, linux, números aleatorios, random, urandom
  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 0 comments