passlib.hash.scrypt - SCrypt¶
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")
print(h)
# > '$scrypt$ln=16,r=8,p=1$aM15713r3Xsvxbi31lqr1Q$nFNh2CVHVjNldFVKDHDlm4CbdRSCdEBsjjJxD+iCs5E'
# the same, but with an explicit number of rounds
hashed = scrypt.using(rounds=8).hash("password")
print(hashed)
# > '$scrypt$ln=8,r=8,p=1$WKs1xljLudd6z9kbY0wpJQ$yCR4iDZYDKv+iEJj6yHY0lv/epnfB6f/w1EbXrsJOuQ'
# verify password
print(scrypt.verify("password", h))
# > True
print(scrypt.verify("wrong", h))
# > False
Note
It is strongly recommended that you install scrypt when using this hash.
Tip
the generic PasswordHash usage examples
Interface¶
scrypt
¶
scrypt(block_size=None, **kwds)
This class implements an SCrypt-based password [#scrypt-home]_ hash, and follows the :ref:password-hash-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 :meth:~passlib.ifc.PasswordHash.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, default:None) –Optional block size to pass to scrypt hash function (the
rparameter). 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
pparameter). Defaults to 1. -
relaxed(bool) –By default, providing an invalid value for one of the other keywords will result in a :exc:
ValueError. Ifrelaxed=True, and the error can be corrected, a :exc:~passlib.exc.PasslibHashWarningwill be issued instead. Correctable errors includeroundsthat are too small or too large, andsaltstrings 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 :class:`~passlib.context.CryptContext` configuration.
encrypt
classmethod
¶
encrypt(*args, **kwds)
Legacy alias for :meth:hash.
.. deprecated:: 1.7
This method was renamed to :meth:!hash in version 1.7.
This alias will be removed in version 2.0, and should only
be used for compatibility with Passlib 1.3 - 1.6.
parsehash
classmethod
¶
parsehash(hash, checksum=True, sanitize=False)
[experimental method] parse hash into dictionary of settings.
this essentially acts as the inverse of :meth:hash: for most
cases, if hash = cls.hash(secret, **opts), then
cls.parsehash(hash) will return a dict matching the original options
(with the extra keyword checksum).
this method may not work correctly for all hashes, and may not be available on some few. its interface may change in future releases, if it's kept around at all.
Parameters:
-
hash–hash to parse
-
checksum–include checksum keyword? (defaults to True)
-
sanitize–mask data for sensitive fields? (defaults to False)
bitsize
classmethod
¶
bitsize(rounds=None, vary_rounds=0.1, **kwds)
[experimental method] return info about bitsizes of hash
default_salt_chars
¶
default_salt_chars()
charset used to generate new salt strings (defaults to salt_chars)
Scrypt Backends¶
This class will use the first available of two possible backends:
- Python stdlib's
hashlib.scryptmethod (only present for Python 3.6+ and OpenSSL 1.1+) - The C-accelerated scrypt package, if installed.
- 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.
Warning
Changed in 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 (aM15713r3Xsvxbi31lqr1Qin 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+iCs5Ein 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 its 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.
Tip
passlib.hash.argon2, a next generation memory-hard KDF designed as the
successor to SCrypt.
-
the SCrypt KDF homepage - http://www.tarsnap.com/scrypt.html ↩
-
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 ↩