Generador aleatorio de contraseñas
Un generador aleatorio de contraseña es un programa o un dispositivo hardware que toma entrada de un generador numérico aleatorio o pseudo-aleatorio y automáticamente genera una contraseña. La contraseñas aleatorias pueden ser generadas manualmente, usando fuentes de aleatoriedad como dados o monedas, o bien generadas usando un ordenador.
Aunque haya varios ejemplo de generadores de contraseña "aleatoria" en Internet, normalmente hay truco detrás, pues muchos programas imitan una aleatoriedad con una seguridad bastante débil. Una recomendación bastante común es la de usar herramientas de código abierto donde sea posible, ya que, permiten comprobaciones independientes de la calidad de los métodos usados. Darse cuenta de que el generar una contraseña aleatoria no asegura que esta tenga una fuerte seguridad, porque, aunque poco probable, se puede generar una contraseña que se pueda hackear con facilidad. En realidad, no hay necesidad de que una contraseña se genere por un proceso perfecto de generación: Simplemente tiene que ser difícil de adivinar.
Ejemplos en distintos lenguajes de programación
A continuación se muestran diferentes soluciones para la generación de contraseñas usando las diferentes lenguajes según el enfoque. No existe relación entre usar un lenguaje u otro en la generación de contraseñas, los ejemplos mostrados a continuación son orientativos.
Enfoque ingenuo
C
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
int
main(void)
{
/* Longitud de la contraseña */
unsigned short int length = 8;
/* La fuente del número aleatorio rand() */
srand((unsigned int) time(0) + getpid());
/* caracteres ASCII entre 33 y 126 */
while(length--) {
putchar(rand() % 94 + 33);
srand(rand());
}
printf("\n");
return EXIT_SUCCESS;
}
Este es un ejemplo de uso de semillas incorrectas para la generación de contraseñas en el lenguaje lenguaje C.
En este caso, la función C estándar rand, que es un generador de números pseudoaleatorios, se siembra inicialmente utilizando la función time de C que proporciona el tiempo actual (hora en milisegundo normalmente), pero las iteraciones posteriores usan rand en su lugar. De acuerdo con el estándar ANSI C, time devuelve un valor de tipo time , que es la implementación predefinida, que generalmente es un entero de 32 bits que contiene el número actual de segundos desde el 1 de enero de 1970 (ver: Tiempo Unix). Hay aproximadamente 31 millones de segundos en un año, por lo que un atacante que conoce el año (un asunto simple en situaciones donde los cambios frecuentes de contraseña son obligatorios por la política de contraseñas) y el identificador del proceso con el que se generó la contraseña se enfrenta a un número relativamente pequeño, según los estándares criptográficos, de elecciones para evaluar. Si el atacante sabe con más precisión cuándo se generó la contraseña, se enfrenta a un número aún menor de candidatos para probar, un defecto grave en esta implementación.
En situaciones donde el atacante puede obtener una versión encriptada de la contraseña, dicha prueba se puede realizar con la suficiente rapidez para que se puedan verificar unos pocos millones de contraseñas de prueba en cuestión de segundos. Ver: Password cracking.
La función rand presenta otro problema. Todos los generadores de números pseudoaleatorios tienen una memoria interna o estado. El tamaño de ese estado determina la cantidad máxima de valores diferentes que puede producir: un estado de n-bits puede producir como máximo valores diferentes. En muchos sistemas, rand tiene un estado de 31 o 32 bits, que ya es una limitación de seguridad significativa. La documentación de Microsoft no describe el estado interno de la implementación de Visual C ++ del rand de biblioteca estándar C, pero solo tiene 32767 salidas posibles (15 bits) por llamada.[1] Microsoft recomienda utilizar una función diferente y más segura, rand_s, en su lugar. La salida de rand_s es criptográficamente segura, según Microsoft, y no usa la semilla cargada por la función srand. Sin embargo, su interfaz de programación difiere del rand.[2]
PHP
function pass_gen($length = 8) {
$pass = array();
for ($i = 0; $i < $length; $i++) {
$pass[] = chr(mt_rand(32, 126));
}
return implode($pass);
}
En este caso, se usa la función PHP microtime,[3] que devuelve la marca de tiempo actual de Unix en microsegundos. Esto aumenta el número de posibilidades, pero alguien con una buena idea de cuándo se generó la contraseña, por ejemplo, la fecha en que un empleado comenzó a trabajar, todavía tiene un espacio de búsqueda razonablemente pequeño. Además, algunos sistemas operativos no ofrecen una resolución de microsegundos de tiempo, lo que reduce drásticamente la cantidad de opciones. Finalmente, la función rand[4] generalmente usa la función C rand subyacente y puede tener un espacio de estado pequeño, dependiendo de cómo se implemente. Un generador de números aleatorios alternativo, mt_rand, que se basa en el generador de números pseudoaleatorios Mersenne twister, está disponible en PHP, pero también tiene un límite de 32 bits. Hay propuestas para agregar una fuerte generación de números aleatorios a PHP.[5]
Métodos más fuertes
Existe una variedad de métodos para generar contraseñas aleatorias seguras y criptográficamente seguras. En plataformas Unix se usa comúnmente /dev/random y /dev/urandom , ya sea programáticamente o junto con un programa como makepasswd.[6] Los programadores de Windows pueden usar la función CryptGenRandom de la Interfaz de programación de aplicaciones criptográficas (Microsoft CryptoAPI). El lenguaje de programación Java incluye una clase llamada SecureRandom. Otra posibilidad es obtener aleatoriedad midiendo algún fenómeno externo, como la sincronización de la entrada del teclado del usuario.
Muchos sistemas informáticos ya tienen una aplicación (generalmente llamada "apg") para implementar FIPS 181.[7] FIPS 181-Automated Password Generator describe un proceso estándar para convertir bits aleatorios (desde un generador de números aleatorios de hardware) en "palabras" algo pronunciables, adecuadas para una frase de contraseña.[8] Sin embargo, en 1994 se descubrió un ataque al algoritmo FIPS 181, de modo que un atacante puede esperar, en promedio, entrar en el 1% de las cuentas que tienen contraseñas basadas en el algoritmo, después de buscar solo 1,6 millones de contraseñas. Esto se debe a la falta de uniformidad en la distribución de las contraseñas generadas, que pueden abordarse utilizando contraseñas más largas o modificando el algoritmo.[9][10]
Java
Aquí hay un ejemplo de código (adaptado de la clase PasswordGenerator r[11]) que usa SecureRandom para generar una contraseña de 10 caracteres hexadecimales:
String[] symbols = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
int length = 10;
Random random = SecureRandom.getInstanceStrong(); // as of JDK 8, this should return the strongest algorithm available to the JVM
StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; i++) {
int indexRandom = random.nextInt( symbols.length );
sb.append( symbols[indexRandom] );
}
String password = sb.toString();
Perl
Este ejemplo en lenguaje Perl utiliza el módulo Crypt::Random::Source para encontrar una fuente de números aleatorios fuertes (que depende de la plataforma).
use Crypt::Random::Source qw(get_strong);
while(length($out) < 15) {
my $a = get_strong(1);
$a =~ s/[^[:graph:]]//g;
$out .= $a;
}
print $out;
Python
El lenguaje Python incluye una clase SystemRandom que obtiene bits aleatorios de grado criptográfico de /dev/urandom en un sistema tipo Unix, incluidos Linux y Mac OS X, mientras que en Windows usa CryptGenRandom.[12][13] Aquí hay un script simple de Python 3 que demuestra el uso de esta clase:
#!/usr/bin/python
from secrets import SystemRandom
from string import printable
longitud = 20
ct = ""
for _ in range(longitud):
ct += "".join(SystemRandom().choice(printable[:-5]))
print(ct)
Métodos mecánicos
Otro método más es usar dispositivos físicos como los dados para generar la aleatoriedad. Una forma simple de hacerlo es utilizar una tabla de caracteres de 6 por 6. La primera tirada del dado selecciona una fila en la tabla y la segunda una columna. Entonces, por ejemplo, una tirada de 2 seguida de una tirada de 4 seleccionaría la letra "j" de la tabla de fraccionamiento, se muestra un ejemplo a continuación.[14] Para generar caracteres en mayúscula / minúscula o algunos símbolos, se puede usar un lanzamiento de una moneda, si esta muestra cara se usa mayúsculas, cruz la minúscula. Si se seleccionó un dígito en las tiradas de dados, un lanzamiento de la moneda con resultado de cara indica el símbolo que está sobre él en un teclado estándar, como el $ encima del '4'.
1 2 3 4 5 6 1 a b c d e f 2 g h i j k l 3 m n o p q r 4 s t u v w x 5 y z 0 1 2 3 6 4 5 6 7 8 9
Referencias
- ↑ [1]
- ↑ [2]
- ↑ microtime
- ↑ rand
- ↑ «Copia archivada». Archivado desde el original el 19 de octubre de 2008. Consultado el 27 de marzo de 2018.
- ↑ «Linux / UNIX: Generating Random Password With mkpasswd / makepasswd / pwgen». www.cyberciti.biz. Consultado el 25 de marzo de 2016.
- ↑ «StrongPasswords - Community Help Wiki». help.ubuntu.com. Consultado el 25 de marzo de 2016.
- ↑ NIST. Automated Password Generator standard FIPS <[https://web.archive.org/web/20130704152532/http://www.itl.nist.gov/fipspubs/fip181.htm# Archivado el 4 de julio de 2013 en Wayback Machine. 181]
- ↑ Shay, Richard; Kelley, Patrick Gage; Komanduri, Saranga; Mazurek, Michelle L.; Ur, Blase; Vidas, Timothy; Bauer, Lujo; Christin, Nicolas et al. (2012). Correct horse battery staple: Exploring the usability of system-assigned passphrases. SOUPS '12 Proceedings of the Eighth Symposium on Usable Privacy and Security. doi:10.1145/2335356.2335366.
- ↑ Ganesan, Ravi; Davies, Chris (1994). «A New Attack on Random Pronounceable Password Generators». Proceedings of the 17th {NIST}-{NCSC} National Computer Security Conference (NIST): 184-197. Consultado el 17 de diciembre de 2014.
- ↑ http://s13.zetaboards.com/Crypto/topic/7111906/1/?x=90
- ↑ «9.6. random — Generate pseudo-random numbers — Python 3.5.1 documentation». docs.python.org. Consultado el 25 de marzo de 2016.
- ↑ «16.1. os — Miscellaneous operating system interfaces — Python 3.5.1 documentation». docs.python.org. Consultado el 25 de marzo de 2016.
- ↑ Levine, John R., Ed.: Internet Secrets, Second edition, page 831 ff. John Wiley and Sons.