hashlib - Hashing Crittografico

Scopo: hash crittografici ed impronte di messaggi

Il modulo hashlib definisce una API per accedere a diversi algoritmi crittografici. Per lavorare con uno specifico algoritmo, si usi l'appropriata funzione costruttore oppure new() per creare un oggetto hash. Da qui, gli oggetti usano la stessa API, non importa quale algoritmo venga usato.

Algoritmi Hash

Visto che hashlib è supportata da OpenSSL, tutti gli algoritmi forniti da quella libreria sono disponibili, compresi:

  • md5
  • sha1
  • sha224
  • sha256
  • sha384
  • sha512

Alcuni algoritmi sono disponibili su tutte le piattaforme, ed alcuni dipendono dalle librerie sottostanti. Per una lista di ognuno, si cerchi rispettivamente in algorithms_guaranteed e algorithms_avaliable.

# hashlib_algorithms.py


import hashlib


print('Garantiti:\n{}\n'.format(
    ', '.join(sorted(hashlib.algorithms_guaranteed))))
print('Disponibili:\n{}'.format(
    ', '.join(sorted(hashlib.algorithms_available))))
$ python3 hashlib_algorithms.py

Garantiti:
blake2b, blake2s, md5, sha1, sha224, sha256, sha384, sha3_224, sha3_256, sha3_384, sha3_512, sha512, shake_128, shake_256

Disponibili:
blake2b, blake2s, md4, md5, md5-sha1, ripemd160, sha1, sha224, sha256, sha384, sha3_224, sha3_256, sha3_384, sha3_512, sha512, sha512_224, sha512_256, shake_128, shake_256, sm3, whirlpool

Dati Campione

Tutti gli esempi in questa sezione usano gli stessi dati campione.

# hashlib_data.py


import hashlib

lorem = '''Lorem ipsum dolor sit amet, consectetur adipisicing
elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis
aute irure dolor in reprehenderit in voluptate velit esse cillum
dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt
mollit anim id est laborum.'''

Esempio MD5

Per calcolare l'hash MD5, o digest (impronta di messaggio), per un blocco di dati (qui una stringa unicode convertita in stringa di byte), prima si crei l'oggetto hash, poi si aggiungano i dati e si chiami digest() oppure hexdigest().

# hashlib_md5.py

import hashlib

from hashlib_data import lorem

h = hashlib.md5()
h.update(lorem.encode('utf-8'))
print(h.hexdigest())

Questo esempio usa il metodo hexdigest() invece che digest() visto che il risultato è formattato in modo che possa essere stampato con chiarezza. Se è accettabile un valore di digest binario si usi digest().

$ python3 hashlib_md5.py

3f2fd2c9e25d60fb0fa5d593b802b7a8

Esempio SHA1

Una impronta di messaggio SHA1 viene calcolata nello stesso modo.

# hashlib_sha1.py

import hashlib

from hashlib_data import lorem

h = hashlib.sha1()
h.update(lorem.encode('utf-8'))
print(h.hexdigest())

Il valore dell'impronta di messaggio è diverso in questo esempio, visto che l'algoritmo è passato da MD5 a SHA1.

$ python3 hashlib_sha1.py

ea360b288b3dd178fe2625f55b2959bf1dba6eef

Creare un hash per Nome

Talvolta è più conveniente riferirsi all'algoritmo per nome in una stringa in luogo di usare la funzione costruttore direttamente. E' utile, ad esempio, essere in grado di conservare il tipo di hash in un file di configurazione. In questi casi, si usi new() per creare un calcolatore di hash.

# hashlib_new.py

import argparse
import hashlib
import sys

from hashlib_data import lorem


parser = argparse.ArgumentParser('demo hashlib')
parser.add_argument(
    'hash_name',
    choices=hashlib.algorithms_available,
    help="il nome dell'algoritmo da usare per l'hash",
)
parser.add_argument(
    'data',
    nargs='?',
    default=lorem,
    help="i dati in input per l'hash, predefinito lorem ipsum",
)
args = parser.parse_args()

h = hashlib.new(args.hash_name)
h.update(args.data.encode('utf-8'))
print(h.hexdigest())

Quando eseguito con diversi argomenti:

$ python3 hashlib_new.py sha1

ea360b288b3dd178fe2625f55b2959bf1dba6eef
$ python3 hashlib_new.py sha256

3c887cc71c67949df29568119cc646f46b9cd2c2b39d456065646bc2fc09ffd8
$ python3 hashlib_new.py sha512

a7e53384eb9bb4251a19571450465d51809e0b7046101b87c4faef96b9bc904cf7f90035f444952dfd9f6084eeee2457433f3ade614712f42f80960b2fca43ff
$ python3 hashlib_new.py md5

3f2fd2c9e25d60fb0fa5d593b802b7a8

Aggiornamenti Incrementali

Il metodo update() dei calcolatori di hash può essere chiamato ripetutamente. Ogni volta, l'impronta di messaggio viene aggiornata in base al testo addizionale inserito. L'aggiornamento incrementale è più efficiente rispetto alla lettura dell'intero file in memoria, e produce lo stesso risultato.

# hashlib_update.py

import hashlib

from hashlib_data import lorem

h = hashlib.md5()
h.update(lorem.encode('utf-8'))
all_at_once = h.hexdigest()


def chunkize(size, text):
    "Ritorna parti di testo con incrementi in base alla dimensione."
    start = 0
    while start < len(text):
        chunk = text[start:start + size]
        yield chunk
        start += size
    return


h = hashlib.md5()
for chunk in chunkize(64, lorem.encode('utf-8')):
    h.update(chunk)
line_by_line = h.hexdigest()

print('Tutto in una volta:', all_at_once)
print('Riga per Riga     :', line_by_line)
print('Verifica          :', (all_at_once == line_by_line))

Questo esempio dimostra come aggiornare in modo incrementale una impronta di messaggio mano a mano che i dati vengono letti o prodotti in altro modo.

$ python3 hashlib_update.py

Tutto in una volta: 3f2fd2c9e25d60fb0fa5d593b802b7a8
Riga per Riga     : 3f2fd2c9e25d60fb0fa5d593b802b7a8
Verifica          : True

Vedere anche:

hashlib
La documentazione della libreria standard per questo modulo.
hmac
Il modulo hmac
OpenSSL
Un pacchetto di strumenti open source per la crittografia.
Cryptography
Un pacchetto Python che fornisce primitivi e ricette crittografiche.
Voidspace: IronPython and hashlib
Un wrapper per hashlib che funziona con IronPython.