passlib.hash.scrypt - SCrypt

New in version 1.7.

This is a custom hash scheme provided by Passlib which allows storing password hashes generated using the SCrypt [1] key derivation function, and is designed as the of a new generation of “memory hard” functions.

Warning

Be careful when using this algorithm, as the memory and CPU requirements needed to achieve adequate security are generally higher than acceptable for heavily used production systems [2]. This is because (unlike many password hashes), increasing the rounds value of scrypt will increase the memory required as well as the time.

Unless you know what you’re doing, You probably want argon2 instead.

This class can be used directly as follows:

>>> from passlib.hash import scrypt

>>> # generate new salt, hash password
>>> h = scrypt.hash("password")
>>> h
'$scrypt$ln=16,r=8,p=1$aM15713r3Xsvxbi31lqr1Q$nFNh2CVHVjNldFVKDHDlm4CbdRSCdEBsjjJxD+iCs5E'

>>> # the same, but with an explicit number of rounds
>>> scrypt.using(rounds=8).hash("password")
'$scrypt$ln=8,r=8,p=1$WKs1xljLudd6z9kbY0wpJQ$yCR4iDZYDKv+iEJj6yHY0lv/epnfB6f/w1EbXrsJOuQ'

>>> # verify password
>>> scrypt.verify("password", h)
True
>>> scrypt.verify("wrong", h)
False

Note

It is strongly recommended that you install scrypt when using this hash.

See also

the generic PasswordHash usage examples

Interface

class passlib.hash.scrypt

This class implements an SCrypt-based password [1] hash, and follows the PasswordHash API.

It supports a variable-length salt, a variable number of rounds, as well as some custom tuning parameters unique to scrypt (see below).

The using() method accepts the following optional keywords:

Parameters:
  • salt (str) – Optional salt string. If specified, the length must be between 0-1024 bytes. If not specified, one will be auto-generated (this is recommended).
  • salt_size (int) – Optional number of bytes to use when autogenerating new salts. Defaults to 16 bytes, but can be any value between 0 and 1024.
  • rounds (int) –

    Optional number of rounds to use. Defaults to 16, but must be within range(1,32).

    Warning

    Unlike many hash algorithms, increasing the rounds value will increase both the time and memory required to hash a password.

  • block_size (int) – Optional block size to pass to scrypt hash function (the r parameter). Useful for tuning scrypt to optimal performance for your CPU architecture. Defaults to 8.
  • parallelism (int) – Optional parallelism to pass to scrypt hash function (the p parameter). Defaults to 1.
  • relaxed (bool) – By default, providing an invalid value for one of the other keywords will result in a ValueError. If relaxed=True, and the error can be corrected, a PasslibHashWarning will be issued instead. Correctable errors include rounds that are too small or too large, and salt strings that are too long.

Note

The underlying scrypt hash function has a number of limitations on it’s parameter values, which forbids certain combinations of settings. The requirements are:

  • linear_rounds = 2**<some positive integer>
  • linear_rounds < 2**(16 * block_size)
  • block_size * parallelism <= 2**30-1

Todo

This class currently does not support configuring default values for block_size or parallelism via a CryptContext configuration.

Scrypt Backends

This class will use the first available of two possible backends:

  1. Python stdlib’s hashlib.scrypt() method (only present for Python 3.6+ and OpenSSL 1.1+)
  2. The C-accelerated scrypt package, if installed.
  3. A pure-python implementation of SCrypt, built into Passlib.

Warning

If hashlib.scrypt() is not present on your system, it is strongly recommended to install the external scrypt package. The pure-python backend is intended as a reference and last-resort implementation only; it is 10-100x too slow to be usable in production at a secure rounds cost.

Changed in version 1.7.2: Added support for using stdlib’s hashlib.scrypt()

Format & Algorithm

This Scrypt hash format is compatible with the PHC Format and Modular Crypt Format, and uses $scrypt$ as the identifying prefix for all its strings. An example hash (of password) is:

$scrypt$ln=16,r=8,p=1$aM15713r3Xsvxbi31lqr1Q$nFNh2CVHVjNldFVKDHDlm4CbdRSCdEBsjjJxD+iCs5E

This string has the format $scrypt$ln=logN,r=R,p=P$salt$checksum, where:

  • logN is the exponent for calculating SCRYPT’s cost parameter (N), encoded as a decimal digit, (logN is 16 in the example, corresponding to n = 2**16 = 65536).
  • R is the value of SCRYPT’s block size parameter (r), encoded as a decimal digit, (r is 8 in the example).
  • P is the value of SCRYPT’s parallel count parameter (p), encoded as a decimal digit, (p is 1 in the example).
  • salt - this base64 encoded salt bytes passed into the SCRYPT function (aM15713r3Xsvxbi31lqr1Q in the example).
  • checksum - this is the base64 encoded derived key bytes returned from the SCRYPT function. This hash currently always uses 32 bytes, resulting in a 43-character checksum. (nFNh2CVHVjNldFVKDHDlm4CbdRSCdEBsjjJxD+iCs5E in the example).

All byte strings are encoded using the standard base64 encoding, but without any trailing padding (“=”) chars. The password is encoded into UTF-8 if not already encoded, and run throught the SCRYPT function; along with the salt, and the values of n, r, and p. The first 32 bytes of the returned result are encoded as the checksum.

See http://www.tarsnap.com/scrypt.html for the canonical description of the scrypt kdf.

Security Issues

SCrypt is the first in a class of “memory-hard” key derivation functions. Initially, it looked very promising as a replacement for BCrypt, PBKDF2, and SHA512-Crypt. However, the fact that it’s N parameter controls both time and memory cost means the two cannot be varied completely independantly. This eventually proved to be problematic, as N values required for even BCrypt levels of security resulting in memory requirements that were unacceptable on most production systems.

See also

argon2, a next generation memory-hard KDF designed as the successor to SCrypt.

Footnotes

[1](1, 2) the SCrypt KDF homepage - http://www.tarsnap.com/scrypt.html
[2]posts discussing security implications of scrypt’s tying memory cost to calculation time - http://blog.ircmaxell.com/2014/03/why-i-dont-recommend-scrypt.html, http://security.stackexchange.com/questions/26245/is-bcrypt-better-than-scrypt, http://security.stackexchange.com/questions/4781/do-any-security-experts-recommend-bcrypt-for-password-storage