"Los números aleatorios no deberían ser generados por un método elegido aleatoriamente". Donald E. Knuth

En Bash, podemos obtener números enteros aleatorios:

$ echo $RANDOM
20684

Random number

Cada vez que se referencia el parámetro RANDOM, éste devuelve un valor entre 0 y 32767, es decir, 2^15^-1. Podemos inicializar la secuencia de números aleatorios asignando un valor a RANDOM. Debemos tener en cuenta que si le asignamos un valor vacío a RANDOM se pierden sus propiedades especiales, aunque después lo inicialicemos.

Podemos poner a prueba la calidad de esos números aleatorios:

$ a=()
$ freq=10
$ max=327680
$ for ((i=0; i < $max; i++)); do
>    # progress bar
>    test $((i%($max/$freq))) -eq 0 && echo -n "."
>    j=$RANDOM
>    a[$j]=$((a[$j]+1))
> done
$ for ((i=0; i < $max/$freq; i++)); do
>    echo "$i: ${a[$i]}";
> done | less

Más números

Podemos obtener el módulo aleatorio de un número aleatorio.

$ echo $((RANDOM%RANDOM))
4530

¿Afectará de alguna manera realizar el módulo aleatorio sobre un número aleatorio como variable aleatoria?

Dilbert

Sí, ya que en el mejor caso, el módulo será mayor que el primer número y, por lo tanto, no afecta al resultado. Pero en el peor caso, el módulo será menor que el primer número, con lo que es mayor la probabilidad de obtener un número menor.

$ a=()
$ freq=10
$ max=327680
$ for ((i=0; i < $max; i++)); do
>    # progress bar
>    test $((i%($max/$freq))) -eq 0 && echo -n "."
>    j=$((RANDOM%RANDOM))
>    a[$j]=$((a[$j]+1))
> done
$ for ((i=0; i < $max/$freq; i++)); do echo "$i: ${a[$i]}"; done

Números aleatorios binarios, octales y hexadecimales:

$ b=2
$ for ((i=0; i < RANDOM%RANDOM; i=i+RANDOM%b)); do echo -n $((i%b)); done
000010001111101001010001111101001011111
$ b=8
$ for ((i=0; i < RANDOM%RANDOM; i=i+RANDOM%b)); do echo -n $((i%b)); done
04743654506265435353610222054150
$ a="01234566789ABCDEF"
$ for ((i=0; i < RANDOM%RANDOM; i++ )); do echo -n ${a:$RANDOM%${#a}:1}; done
0150633894AD8DEF81671B06694C6B5

Debemos tener en cuenta que si queremos utilizar estos números, el prefijo, en Bash, para los números binarios es 2#, para los números octales es 0 y para los números hexadecimales, 0x. Por ejemplo, el número 10 es 2#1010, 012 y 0x10.

Y letras

Podemos crear una secuencia de números y letras aleatoria:

$ a=$(echo $((echo -n {a..z}; echo -n {A..Z}; echo -n {0..9};) | sed 's/ //g'))
$ for ((i=0; i < RANDOM%RANDOM; i++)); do echo -n ${a:$RANDOM%${#a}:1}; done
3keV1cLFGdxO2S5nvJGzoq9EyZeryLjkVgP64Dn0z

Fuentes de aleatoriedad

  • /dev/random
  • /dev/urandom
  • /proc/interrupts

Los dos primeros son ficheros especiales que permiten acceso al generador de números aleatorios del kernel. El kernel recoge ruido ambiental desde los controladores de dispositivos (como por ejemplo, el ratón) y otras fuentes y lo usa como fuente de aleatoriedad. También tiene en cuenta el número de bits que se pueden crear aleatoriamente con un nivel de entropía tal que no sean vulnerables a ataques criptográficos. /dev/random se debería utilizar para crear claves criptográficas, para todo lo demás, podemos usar /dev/urandom.

Estas fuentes proporcionan bits aleatorios, no caracteres, por lo que antes de utilizarlos para mostrar una cadena de caracteres deberemos pasarlos por alguna función como:

  • md5sum
  • shasum
  • sha1sum
  • sha224sum
  • sha256sum
  • sha384sum
  • sha512sum
  • grep -o '[[:alnum:]]'
  • tr -dc a-zA-Z0-9
  • xxd -ps
  • od -An -td | sed 's/\s_\(._\)\s/\1/g'
  • o cualquier otra combinación que filtre los caracteres

/proc/interrupts registra el número de interrupciones de cada dispotivo de entrada/salida, por lo que debería funcionar bien como fuente de aleatoriedad.

Cadenas de caracteres aleatorios:

$ strings /dev/urandom | grep -o '[[:alnum:]]' | head -n 12 | tr -d '\n'; echo
tUqWq9fqem9C1gKbTpCcVJg6DNvxMG
$ < /dev/urandom tr -dc _a-zA-Z0-9 | head -c12
1G0gNNXM3RkT
$ dd if=/dev/random bs=1 count=5 2>/dev/null | xxd -ps
3e3206ff95

Generando entropía

Si la fuente de entropía no da abasto y necesitamos generar más entropía más rápido, por ejemplo, cuando creamos claves RSA muy largas, poner a trabajar el equipo podría servir. Algo como:

$ ls -lRh /
$ find / -name \*

Sin embargo, existe un programa que sirve para esto. rng-tools ayuda a generar entropía. Una vez instalado desde los respositorios, modificamos el fichero /etc/default/rng-tools para que contenga:

HRNGDEVICE=/dev/urandom

Y reiniciamos el servicio:

$ sudo service rng-tools restart

Si ahora volvemos a crear una clave, notaremos que el tiempo necesario para conseguir la entropía necesaria es mucho menor.


Actualizado el 25 de septiembre de 2016

Otro servicio que sirve para esto es haveged: systemctl enable haveged systemctl start haveged


Otros programas

Podemos instalar estos programas desde los repositorios.

makepasswd

Para crear contraseñas.

$ makepasswd --char=12

mkpasswd

Otro para crear contraseñas.

$ mkpasswd

openssl

Permite obtener una serie de bytes hexadecimales aleatorios; por cada byte hexadecimal se imprimen dos caracteres hexadecimales:

$ openssl rand -hex 16
5666b2215534c6d4c3be4101219cd0b1

También permite obtener caracteres en base64:

$ openssl rand -base64 12
ymwU0wtOZ6wMgAfr

pwgen

Otro más para crear contraseñas

$ pwgen 12

rand

Trabaja con números y caracteres. Por ejemplo, podemos obtener números decimales aleatorios.

$ rand -f
0.04691

No sólo letras y números

Podemos crear una dirección MAC aleatoria:

$ echo $(cat /proc/interrupts | md5sum | sed -r 's/^(.{10}).*$/00\1/; s/([0-9a-f]{2})/\1:/g; s/:$//;')
00:6d:b6:2f:46:1d
$ openssl rand -hex 6 | sed -r 's/^(.{10}).*$/00\1/; s/([0-9a-f]{2})/\1:/g; s/:$//;'
00:8d:e6:98:ca:d2

Podemos crear un fichero o un directorio temporal, cuyo nombre es aleatorio:

$ mktemp
/tmp/tmp.WBABktXDHZ
$ mktemp -d
/tmp/tmp.lHuPARC0YC

Podemos mostrar un fichero aleatorio:

$ find ~ -maxdepth 1 | shuf -n1 --random-source=/dev/random
./bash_aliases

Podemos poner una imagen de fondo de escritorio aleatoria en Gnome:

$ f=$(find ~/Imágenes/ | shuf -n1 | egrep 'gif|jpe?g|png')
$ while test -n "$f"; do f=$(find ~/Imágenes/ | shuf -n1); done
$ gconftool-2 -t str --set /desktop/gnome/background/picture_filename "$f"

Podemos generar una contraseña a partir de 4 palabras aleatorias:

$ printf '%s %s %s %s' $(\grep -v "'" /usr/share/dict/american-english | shuf -n 4 | tr '[:upper:]' '[:lower:]')
meters haven backtracking subordinates

Podemos mostrar una línea aleatoria de un fichero:

$ shuf -n1 /etc/passwd

O también podemos mostrar un número de líneas aleatorio de un archivo aleatorio del código fuente de Linux:

$ f=$(find /usr/src/linux-source-2.6.32 -type f -name \* | shuf -n1)
$ n=$(wc -l $f | awk '{print $1}')
$ cat $f | sed -n $((RANDOM%n)),$((RANDOM%n))p

        if (!zalloc_cpumask_var(&vec->mask, gfp))
            goto cleanup;
    }

    for_each_possible_cpu(i)
        cp->cpu_to_pri[i] = CPUPRI_INVALID;
    return 0;

cleanup:
    for (i--; i >= 0; i--)
        free_cpumask_var(cp->pri_to_cpu[i].mask);
    return -ENOMEM;
}

Internet

En Internet, hay servicios cuyas respuestas aleatorias podemos utilizar en nuestra vida cotidiana:

Obtener una excusa de BOFH aleatoria:

$ telnet towel.blinkenlights.nl 666
=== The BOFH Excuse Server ===
We didn't pay the Internet bill and it's been cut off.

Obtener un hecho aleatorio:

$ curl -s http://randomfunfacts.com | grep -Eo ".*" | sed -r 's/([^< ]+)<\/i>< \/strong>/\1/'
Donkeys kill more people annually than plane crashes.

Obtener un mensaje aleatorio para un commit:

$ curl -s http://whatthecommit.com | grep "" | sed -r 's/([^$]+)$/\1/'
Fucking egotistical bastard. adds expandtab to vimrc

Obtener una frase de Futurama aleatoria desde Slashdot:

$ curl -Is slashdot.org | sed -n '5p' | sed 's/^X-//'
Bender: I'm one of those lazy, homeless bums I've been hearing about.

Obtener una excusa de programador aleatoria:

curl -s https://api.githunt.io/programmingexcuses

Además de números y letras, también podemos obtener números de lotería, imágenes, secuencias, fechas, horas, coordenadas geográficas, música, testimonios... todo aleatorio en random.org

$ curl -s "https://www.random.org/passwords/?num=1&len=8&format=html&rnd=new"

Entradas relacionadas


Published

Category

dev

Tags

Contacto