Arminius mencionó la simplicidad del hex, y creo que vale la pena expandirse.
Los generadores de números aleatorios generalmente funcionan en bits, por lo que el rango de números que pueden generar es una potencia de dos. Un rango de caracteres como [0-9a-zA-Z]
tiene 62 caracteres, lo que equivale a una potencia de dos (64), por lo que la computadora tiene que hacer algunas conversiones entre los rangos.
Se puede hacer, pero es fácil hacerlo mal. La forma "estándar" es tomar el número real, dividirlo por el rango que desea y tomar el resto como su número aleatorio. Eso introduce un sesgo sin embargo. Para un ejemplo simple, supongamos que genera números en [0-3]
pero que los quiere en [0-2]
. El rango [0-3]
se asignaría al rango [0-2]
de la siguiente manera:
0 => 0 mod 3 => 0
1 => 1 mod 3 => 1
2 => 2 mod 3 => 2
3 => 3 mod 3 => 0
Observe cómo puede obtener un 0
de dos maneras diferentes: 0
y 3
ambos van a 0
. El enfoque está sesgado hacia la generación de 0
s, lo que hará que tu contraseña sea más fácil de adivinar.
La forma correcta consiste en calcular el relleno correcto para que lo que genera se ajuste de manera uniforme al rango, lo cual es complicado y potencialmente podría hacer que su contraseña sea mucho más larga dependiendo de cómo se compara su rango de salida con eso del generador de números aleatorios.
Un enfoque más fácil es usar un rango que ya es una potencia de dos para que pueda ignorar el sesgo por completo. La mayoría tiene problemas.
- Base-2 (binario) produce cadenas extremadamente largas.
- Base-4 (cuaternario) no es mucho mejor.
- Base-8 (octal) es mejor pero aún es largo.
- Base-16 (hex) es un poco largo, pero razonable. También codifica 4 bits por carácter, lo cual es bastante conveniente cuando las computadoras prefieren múltiplos de 8.
- La base 32 codifica 5 bits por carácter, lo que no es conveniente si las computadoras prefieren múltiplos de 8.
- La base 64 codifica 6 bits por carácter, lo cual es incómodo (pero un poco menos, ya que al menos es un número par).
- La base 96 es popular, pero no tiene una potencia de 2, por lo que tiene el mismo problema que
[0-9a-zA-Z]
.
- Base-128 y, sobre todo, símbolos que no se pueden escribir fácilmente en un teclado de consulta típico.
Para ampliar un poco sobre por qué la base-64 es un problema, considere qué sucede cuando intenta codificar un solo byte (8 bits). No puedes hacerlo con un solo carácter base-64 ya que solo obtiene 6 de los 8 bits. Pero si usa dos caracteres, debe descubrir cómo rellenar su byte de 8 bits en una salida de 12 bits sin introducir sesgos o sugerir que podría haber un byte adicional.
Hex, en contraste, es casi trivial para codificar bytes. Simplemente busque cada byte en una tabla de 256 elementos para obtener dos caracteres y escupirlos. Proporciona contraseñas razonablemente cortas, no usa símbolos extraños y es fácil de implementar. Es la mejor opción para generadores de contraseñas conscientes de la seguridad.
Quizás lo mejor de todo es que la mayoría de los lenguajes de programación admiten hexadecimales fuera de la caja. La biblioteca C tiene printf()
, que puede formatearse como octal, decimal o hexadecimal. Del mismo modo, C ++ tiene manipuladores IO que utilizan los mismos formatos. Sin embargo, no hay soporte incorporado para otras bases (ni siquiera base-64), así que debes hacerlo tú mismo (complicado) o encontrar una biblioteca que lo haga correctamente (violar la regla NIH (y posiblemente también mucho trabajo para verificarla)). Es mucho más fácil simplemente usar lo que está en la biblioteca estándar, especialmente cuando funciona.
Es cierto que se obtiene menos seguridad por carácter con hexadecimal que con otras codificaciones, pero como Eric Lagergren señaló en los comentarios, hex(random_bytes)
es tan seguro como solo random_bytes
. Es solo que más tiempo es todo. De hecho, todo lo que necesita son 16 bytes (codificados como 32 dígitos hexadecimales) para tener una contraseña tan fuerte que cualquier atacante quemará toda la energía del sistema solar antes de que tengan una mínima posibilidad de adivinarlo. La mayoría de los sitios web aceptan con gusto contraseñas de 32 caracteres, por lo que no hay problemas para usarlas.