Hash data and authenticate messages

Compute a hash

A cryptographic hash (or digest) is a short, fixed-size fingerprint of some data: it is practically impossible to find two different inputs with the same hash. Use it, for instance, to check that a downloaded file is intact, or to identify content.

Use SHA-256:

from Crypto.Hash import SHA256

h = SHA256.new(b"Hello")
print(h.hexdigest())    # 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969

digest() returns the hash as 32 bytes, hexdigest() as a hexadecimal string.

To hash a large file, or data that arrives in pieces, call update() several times:

h = SHA256.new()
with open("large_file.bin", "rb") as f:
    while chunk := f.read(1024 * 1024):
        h.update(chunk)
print(h.hexdigest())

Other good choices are SHA-3 (a different design, as a backup for SHA-2) and BLAKE2 (faster in software). They have the same API. Do not use MD5 or SHA-1 for anything related to security: they are broken.

A hash alone does not protect against an attacker who can modify the data, because the attacker can just recompute the hash. For that, use a MAC or a signature.

Warning

Do not use a hash to store passwords. See Work with passwords.

Hash a massive amount of data

SHA-256 processes data sequentially, on a single CPU core. For very large inputs (for instance, files of many gigabytes), KangarooTwelve (K12) is much faster: it is usually faster than SHA-256 even on one core, and it can hash independent parts of the data on several cores at the same time. Pass threads=0 to use all the cores available, and read the data in large chunks (each thread processes at least 256 KiB of a single update() call):

from Crypto.Hash import KangarooTwelve as K12

h = K12.new(threads=0)
with open("large_file.bin", "rb") as f:
    while chunk := f.read(16 * 1024 * 1024):
        h.update(chunk)
print(h.read(32).hex())

The result does not depend on the number of threads. K12 is an extendable-output function: instead of digest(), you call read() with the length of the output you need (32 bytes is a good default).

K12 (RFC 9861) is newer and less widely supported than SHA-256: choose it when you control both the side that computes the hash and the side that checks it.

Authenticate a message with a secret key (MAC)

A Message Authentication Code (MAC) is a tag that only the holders of a secret key can compute. The recipient recomputes the tag over the message it received, with the same key, and compares it with the tag it received.

Use HMAC with SHA-256:

from Crypto.Hash import HMAC
from Crypto.Random import get_random_bytes

key = get_random_bytes(32)      # shared in advance by the two parties
message = b"Transfer 100 EUR to Alice"

# The sender
tag = HMAC.new(key, message, digestmod=SHA256).digest()

# The recipient
try:
    HMAC.new(key, message, digestmod=SHA256).verify(tag)
    print("The message is authentic")
except ValueError:
    print("The message or the tag were modified")

Always check a tag with verify() (or hexverify()), and not with ==: verify() takes the same time whatever the input, so it does not leak information about the correct tag.

Note

If you also want to encrypt the message, don’t add a MAC yourself: use authenticated encryption (see Encrypt data with a secret key), which includes it.

If the recipient must be able to verify the message without being able to create a valid tag (for instance, because there are many recipients), use digital signatures instead (see Sign data and verify signatures).

See also

  • Crypto.Hash package, for all hash functions and MACs (including KMAC, CMAC, and the extendable-output functions SHAKE).