Hash md5 en Python



@eduardo_gpg

Número de visitas 4876

Tiempo de lectura 4 min

28 Diciembre 2020

En términos simples, una función hash no es más que una función que, utilizando un algoritmo matemático, transforma un conjunto de datos en un código alfanumérico con longitud fija. Es decir, la salida de la función se comprenderá de números y letras, además que su longitud (tamaño de caracteres) siempre será la misma.

Cuando hablamos de un conjunto de datos, no podemos referir a, prácticamente cualquier tipo de tipo de contenido. Ya sea texto, imágenes, videos, archivos de audio etc ... 🤓

Para que una función pueda considerarse una función hash, debe cumplir con los siguientes 2 puntos.

  • Produce valores únicos y repetibles para cada entrada.
  • El valor de salida no proporciona pistas sobre la entrada que lo produjo.

Un uso muy común para las funciones hash es al momento de validar contraseñas. Como sabemos, las contraseñas son valores sensibles, los cuales no deben, por ningún motivo, ser almacenados en texto plano. Por ejemplo, si pretendes almacenar contraseñas en una base de datos, una muy buena ideas es aplicar un hash antes de almacenarlas. De esta forma, si tu base de datos se ve comprometida, no así las contraseñas de tus usuarios.

Otro ejemplo de dónde podemos implementar funciones hash, es cuando deseamos validar de forma rápida si un documento fue alterado o no. Al nosotros realizar un hash sobre un documento obtendremos una salida única. Si el documento fue alterado, ya sea porque se agrego o quito un solo byte, el nuevo hash será completamente diferente. 😎

Esto es bastante común, por ejemplo, cuando deseamos descargar archivos de internet.



Estos son solo 2 ejemplos de donde implementar funciones hash, sin embargo no son los únicos, existen cientos más, y el poder identificar dónde y cuándo implementarlos nos será de mucha utilidad en nuestra vida profesional, ya que podremos agilizar nuestro proceso de desarrollo, además por supuesto, que estaremos añadiendo una capa extra de seguridad.

Por todo esto, y mucho más, en esta ocasión aprenderemos a implementar funciones hash con Python. 🐍

Para este tutorial, y con fines únicamente prácticos, estaremos utilizando el algoritmo hash MD5. Sin embargo, es de suma importancia mencionar que: El algoritmo MD5 de encuentra obsoleto, y no debería ser usado en ninguna tipo operación que incluya datos sensibles o sea critico para el sistema. 🤯

Bien, una vez mencionada la introducción (y la advertencia), comencemos.

MD5 👩‍🔬

Actualmente existen múltiples algoritmos de hash en el mercado, de los cuales sin duda destaca el algoritmo MD5. Al implementar este algoritmo, obtendremos como resultad, una cadena alfanumérica de 32 caracteres hexadecimales. Ocupando siempre 16 Bytes de memoria.

MD5("Generando un MD5 de un texto") = 5df9f63916ebf8528697b629022993e8

Implementar este algoritmo en Python es bastante sencillo. Veamos un par de ejemplos.

Lo primero que debemos hacer será import el módulo hashlib. Este módulo ya se encuentra en la biblioteca estándar de Python, por lo cual no será necesario instalar absolutamente nada. 🤓

>>> import hashlib

Posteriormente haremos uso de la función md5. Esta función recibe como argumento el conjunto de datos que deseamos hashear. La función retorna como resultado un objeto de tipo HASH.utilizando el método hexdigest obtendremos nuestra cadena alfanumérica.

>>> md5 = hashlib.md5(b'Hola mundo desde PyWombat') 
>>> md5.hexdigest()
'167caf58fd96b9318d34eda22aea2b9b'

# Añadimos un punto
>>> md5 = hashlib.md5(b'Hola mundo desde PyWombat.') 
>>> md5.hexdigest()
 'd4f1f2ccbcad3d57467f492f4a1d971d'

>>> md5 = hashlib.md5(b'Nuevo mensaje') 
>>> md5.hexdigest()
'ab9c1e0426405f57408e8774ff379806'

Tal y como podemos observar, diferentes conjuntos de datos dan como resultado diferentes salidas.

Para este par de ejemplo he utilizado un arreglo de bytes, sin embargo si deseamos utilizar un string, será necesario apoyarnos del método encode.

>>> message = 'Hola mundo desde PyWombat.'

>>> md5 = hashlib.md5(message.encode()) 
>>> md5.hexdigest()
 'd4f1f2ccbcad3d57467f492f4a1d971d'

Bastante sencillo ¿no? pero ¿Qué pasa si a lo que deseamos aplicar el hash es en extremo extenso? Por ejemplo, quizás una conversación entre 2 interlocutores. En esos casos nos podemos apoyar del método update. Este método nos permite insertar chunks a nuestro conjunto de datos principal.

Simulemos una pequeña conversación entre Alice and Bob.

>>> md5 = hashlib.md5()
>>> md5.update('A: Hola, espero te encuentre muy bien.'.encode())
>>> md5.update('B: Hola, me encuentro bien, gracias.'.encode())
>>> md5.update('B: y tú?'.encode())

>>> md5.hexdigest()
'1765f1db413c599c4731499820883e86'

Una vez todo el contenido haya sido almacenado y actualizado, obtendremos el código alfanumérico con el método hexdigest, tal y como lo hemos hecho anteriormente. 😎

¿Y si probamos con algunos de los ejemplos anteriores? Hola mundo desde PyWombat. Por ejemplo.

>>> md5 = hashlib.md5()
>>> md5.update('Hola mundo '.encode())
>>> md5.update('desde PyWombat.'.encode())  

>>> md5.hexdigest()
 'd4f1f2ccbcad3d57467f492f4a1d971d'

Si tú practicas exactamente con estos mismos ejemplos, no importa tu versión de Python, tu sistema operativo o el tipo de hardware que utilice tu computadora, el resultado siempre será el mismo, ya que el algoritmo es universal. 😋

Por otro lado, como mencionamos anteriormente: Cuando hablamos de un conjunto de datos, no podemos referir a, prácticamente cualquier tipo de tipo de contenido ... así que, ¿Qué pasa si deseamos conocer el hash de un documento en particular? Para ello existen un par de soluciones.

En primera instancia se nos puede ocurrir algo como lo siguiente: obtener todo el contenido del archivo, y posteriormente generar el hash. Nuestro código pudiera quedar de las siguiente manera.

with open('models.py', 'rb') as f: 
    md5 = hashlib.md5(f.read()))
    print(md5.hexdigest())

Esto funciona, pero, ¿y si nuestro archivo es demasiado extenso para poder leerlo en una sola operación? Bueno, allí podemos implementar los chunks, e ir actualizando nuestro conjunto de datos.

with open('models.py', 'rb') as f: 
    md5 = hashlib.md5() 

    for chunk in iter(lambda: f.read(4096), b""): 
        md5.update(chunk)  
    print(md5.hexdigest()) 

Ojo, para que esto funcione, es importante obtener el contenido del archivo en formato: lectura binaria(rb).

Estos dos ejemplos funcionan bastante bien y si lo deseamos, podemos almacenarlos en funciones. De esta forma podremos reutilizarlos un n cantidad de veces, sin embargo, ¿Qué pasa si deseamos conocer el hash. ya no de un archivo, si no de un directorio completo? 🤔

Pues bien, es allí donde entra la librería checksumdir. A través de esta librería, en conjunto con su función dirhash seremos capaces de conocer el hash de un directorio en nuestro sistema.

Te comparto el oficial link para su instalación.

Esta función nos permite obtener el hash de, no solo un archivo, si no de un directorio completo. La función recibe 2 argumentos de forma obligatoria. El primer argumento será la ruta del directorio del cual queremos conocer el hash, y el segundo argumento será el algoritmo a implementar.

Opcionalmente podemos excluir ciertos archivos. 🤠

>>> from checksumdir import dirhash

>>> directory  = '/path/to/directory/'
>>> md5hash    = dirhash(directory, 'md5')
>>> sha1hash   = dirhash(directory, 'sha1', excluded_files=['package.json'])
>>> sha256hash = dirhash(directory, 'sha256', excluded_extensions=['pyc'])

Conclusión

Listo, ahora ya conoces las diferentes formas de cómo puedes implementar la función hash MD5 en Python, y de esta forma obtener hashes que puedes fácilmente comparar.

Antes de finalizar me gustaría compartir contigo un pequeño reto el cual implica monitorear cambios en nuestro sistema. Con todos los conocimientos que hemos adquirido en esta entrega, no tengo la menor duda que podrás finalizarlo antes del tiempo limite. 🍻

No olives compartir tu solución con la comunidad. 🥳


¿El contenido te resulto de ayuda?

Para poder dejar tu opinión es necesario ser un usuario autenticado. Login

Más Tips y Ejercicios 🐍

Adquiere una subscripción PyWombat por tan solo $3 USD. al mes.

Conoce los beneficios de ser usuario premium:
Niveles desbloqueados: Ten accesos a todos los niveles de ejercicios. 🔓
Nuevo límite: Incrementa tu límite de ejercicios por semana. 🚀
Contenido único: Recibe semanalmente recursos exclusivos de Python (Videos, Artículos y Capitulos del libro PyWombat, comienza como desarrollador Python. 🐍