December 10: Python Cryptographic Service Modules

Shhh! 🤫 As part of the Python Standard Library traversal, after yesterday's look at file format modules, today is going to be all about secrets. Well, all about secrets and hmac and hashlib, to be precise.

Highlights

  • There's an awful lot of hash algorithms in hashlib.
  • The secrets module exists and is suitable for (reasonably) strong randomness, eg for generating long secret URLs.

hashlib

The hashlib module grants access to a ton of hash algorithms – not all of which are strong or safe. Please hash data responsibly and make sure you're up to date on safe choices etc etc. There is one constructor for each algorithm, named after the lower-cased algorithm. All of these return hash objects, which you feed (byte!) data with update() and get output with digest() or hexdigest(). You can pass usedforsecurity=False to every constructor to permit the use of insecure and blocked algorithms in restricted settings.

algorithms

Supported hash algorithms (on most platforms) are MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512 (plus the SHA3-* variants where appropriate), BLAKE2b, BLAKE2s, SHAKE-128 and SHAKE-256. algorithms_available will return a set of all currently available algorithms.

Apart from regular hashing functions, you can (and should!) be using key derivation functions for secure password hashing, which can be configured with a salt and a number of iterations and some other parameters. Use pbkdf2_hmac or scrypt.

hmac

hmac implements the HMAC RFC, which serves to verify both the data integrity and the authenticity of a given message. It relies on a secret cryptographic key, which you have to manage separately. As with all cryptography, make sure you know what you're doing, and that you wouldn't be better off using libraries to handle this for you. Use of the module is straightforward, but please remember to use compare_digest instead of == to protect against timing attacks.

secrets

If you want secure random numbers, eg for password hashing or secret storage, use secrets and not random! Use choice() to pick an element out of a secret, randbelow to pick a number between 0 and the argument, and randbits to get an integer with n random bits. Use token_bytes, token_hex or token_urlsafe to generate secure tokens, eg for hard-to-guess URLs or password resets. You can specify the length in bytes, or rely on Python to pick a safe (and increasing, over the years) default value.