descargar - Python y claves aleatorias de 21 char max
python crypto (5)
¿Caracteres o bytes? Si requiere cadenas arbitrarias, puede usar los bytes y no preocuparse por expandirlos a caracteres legibles (para lo cual base64 sería mejor que hexadecimal de todos modos).
MD5 genera 16 caracteres si no usa la expansión hexadecimal de este. SHA1 genera 20 bajo la misma condición.
>>> import hashlib
>>> len(hashlib.md5(''foobar'').digest())
16
>>> len(hashlib.sha1(''foobar'').digest())
20
Pocos bytes adicionales son necesarios después de eso.
Estoy usando una API que toma el nombre de 21 char max para representar una sesión interna que tiene una vida útil de alrededor de "dos días". Me gustaría que el nombre no sea significativo si utilizo algún tipo de hash. md5 genera 40 caracteres, ¿hay algo más que pueda usar?
Por ahora uso ''userid [: 10]'' + tiempo de creación: ddhhmmss + random 3 chars.
Gracias,
¿Por qué no tomar los primeros 21 caracteres de md5 o SHA1 hash?
La representación hexadecimal de MD5 tiene una aleatoriedad muy pobre: solo obtiene 4 bits de entropía por carácter.
Usa caracteres aleatorios, algo así como:
import random
import string
"".join([random.choice(string.ascii_letters + string.digits + ".-")
for i in xrange(21)])
En la elección pon todos los personajes aceptables.
Si bien el uso de una función hash real, como SHA1, también obtendrá buenos resultados si se utiliza correctamente , la complejidad añadida y el consumo de CPU no parecen justificados para sus necesidades. Solo quieres una cadena aleatoria.
Si leo tu pregunta correctamente, quieres generar un token identificador arbitrario que debe tener un máximo de 21 caracteres. ¿Tiene que ser muy resistente a las adivinanzas? El ejemplo que proporcionó no es "criográficamente fuerte", ya que puede adivinarse buscando menos de la mitad de todo el espacio de claves posible.
No dice si los caracteres pueden ser todos 256 caracteres ASCII, o si debe limitarse a, por ejemplo, ASCII imprimible (33-127, inclusive), o algún rango más pequeño.
Hay un módulo de Python diseñado para UUID (Universal Unique IDentifiers). Es probable que desee uuid4, que genera un UUID aleatorio, y usa soporte de sistema operativo si está disponible (en Linux, Mac, FreeBSD y probablemente otros).
>>> import uuid
>>> u = uuid.uuid4()
>>> u
UUID(''d94303e7-1be4-49ef-92f2-472bc4b4286d'')
>>> u.bytes
''/xd9C/x03/xe7/x1b/xe4I/xef/x92/xf2G+/xc4/xb4(m''
>>> len(u.bytes)
16
>>>
16 bytes aleatorios es muy difícil de entender, y no es necesario utilizar los 21 bytes completos que permite su API, si lo único que desea es tener un identificador opaco inimaginable.
Si no puede usar bytes sin procesar como ese, lo cual es probablemente una mala idea porque es más difícil de usar en registros y otros mensajes de depuración y más difícil de comparar a simple vista, convierta los bytes en algo un poco más legible, como usar bases 64 codificación, con el resultado reducido a 21 (o lo que sea) bytes:
>>> u.bytes.encode("base64")
''2UMD5xvkSe+S8kcrxLQobQ==/n''
>>> len(u.bytes.encode("base64"))
25
>>> u.bytes.encode("base64")[:21]
''2UMD5xvkSe+S8kcrxLQob''
>>>
Esto le da una cadena aleatoria de muy alta calidad de longitud 21.
Puede que no te gusten los ''+'' o ''/'' que pueden estar en una cadena de base 64, ya que sin un escape adecuado podría interferir con las URL. Como ya piensas utilizar "caracteres aleatorios 3", no creo que esto sea una preocupación tuya. Si es así, puedes reemplazar esos caracteres por otra cosa (''-'' y ''.'' Podrían funcionar), o eliminarlos si están presentes.
Como han señalado otros, puede usar .encode ("hex") y obtener el equivalente hexadecimal, pero eso son solo 4 bits de aleatoriedad / carácter * 21 caracteres máximo le da 84 bits de aleatoriedad en lugar de dos veces eso. Cada bit dobla su espacio de claves, haciendo que el espacio de búsqueda teórico sea mucho, mucho más pequeño. Por un factor de 2E24 más pequeño.
Su espacio de claves aún tiene un tamaño de 2E24, incluso con codificación hexadecimal, por lo que creo que es más una preocupación teórica. No me preocuparía que las personas hagan ataques de fuerza bruta contra su sistema.
Editar :
PD: La función uuid.uuid4 usa libuuid si está disponible. Eso obtiene su entropía de os.urandom (si está disponible) o de la hora actual y la dirección MAC de ethernet local. Si libuuid no está disponible, la función uuid.uuid4 obtiene los bytes directamente de os.urandom (si está disponible); de lo contrario, utiliza el módulo aleatorio. El módulo aleatorio usa una semilla predeterminada basada en os.urandom (si está disponible) de lo contrario un valor basado en la hora actual. La prueba se lleva a cabo para cada llamada de función, por lo que si no tiene os.urandom, la sobrecarga es un poco más grande de lo que cabría esperar.
¿Llevar el mensaje a casa? Si sabes que tienes os.urandom, entonces podrías hacer
os.urandom(16).encode("base64")[:21]
pero si no quiere preocuparse por su disponibilidad, utilice el módulo uuid.
El módulo base64 puede hacer codificación segura para URL. Entonces, si es necesario, en lugar de
u.bytes.encode("base64")
Podrías hacerlo
import base64
token = base64.urlsafe_b64encode(u.bytes)
y, cómodamente, para convertir de nuevo
u = uuid.UUID(bytes=base64.urlsafe_b64decode(token))