{"id":7492,"library":"pbkdf2","title":"PBKDF2 (PKCS#5 v2.0 PBKDF2 Module)","description":"The `pbkdf2` library provides a Python implementation of the Password-Based Key Derivation Function 2 (PBKDF2), as specified in RSA PKCS#5 v2.0. It is designed to derive cryptographic keys from a password and a salt, leveraging iterative hashing to increase the computational cost for brute-force attacks. The library's last release was in June 2011, and while functional, modern Python applications are generally advised to use the built-in `hashlib.pbkdf2_hmac` function, which offers better performance and active maintenance.","status":"abandoned","version":"1.3","language":"en","source_language":"en","source_url":"https://github.com/dlitz/python-pbkdf2","tags":["security","cryptography","password","hashing","pbkdf2","key-derivation"],"install":[{"cmd":"pip install pbkdf2","lang":"bash","label":"Install stable release"}],"dependencies":[],"imports":[{"symbol":"PBKDF2","correct":"from pbkdf2 import PBKDF2"},{"note":"A utility function for simpler password hashing, wraps PBKDF2.","symbol":"crypt","correct":"from pbkdf2 import crypt"}],"quickstart":{"code":"import os\nfrom pbkdf2 import PBKDF2\n\npassword = b\"mysecretpassword\"\nsalt = os.urandom(16) # Always use a unique, random salt\niterations = 100000 # Choose a high iteration count for security\ndklen = 32 # Desired key length in bytes\n\n# Derive a key using the PBKDF2 class\nderived_key = PBKDF2(password, salt, iterations).read(dklen)\n\nprint(f\"Salt: {salt.hex()}\")\nprint(f\"Derived Key: {derived_key.hex()}\")\n\n# Or use the simpler 'crypt' function (defaults to HMAC-SHA1 and specific format)\n# NOTE: 'crypt' often uses a lower default iteration count and HMAC-SHA1, consider explicit PBKDF2 for modern security standards.\npwhash = PBKDF2.crypt(password.decode(), salt.decode(), iterations)\nprint(f\"Password Hash (using .crypt): {pwhash}\")","lang":"python","description":"This quickstart demonstrates deriving a key using the `PBKDF2` class with a randomly generated salt and a high iteration count. It also shows the `crypt` helper function, though explicit use of `PBKDF2` is often preferred for control over the hashing algorithm and iterations."},"warnings":[{"fix":"Migrate to `hashlib.pbkdf2_hmac` for new projects and consider for existing ones. Example: `from hashlib import pbkdf2_hmac; key = pbkdf2_hmac('sha256', password_bytes, salt_bytes, iterations, dklen=32)`.","message":"This `pbkdf2` package has not been updated since 2011. Python's standard library `hashlib` module provides `hashlib.pbkdf2_hmac`, which is the recommended, actively maintained, and often more performant way to perform PBKDF2.","severity":"deprecated","affected_versions":"1.0 - 1.3"},{"fix":"Always explicitly specify a strong hash function like SHA-256 or SHA-512 when using PBKDF2, especially if migrating to `hashlib.pbkdf2_hmac`. The `pbkdf2` library (dlitz/python-pbkdf2) does not offer a direct way to change the HMAC algorithm for the `PBKDF2` class itself; this is another reason to prefer `hashlib.pbkdf2_hmac`.","message":"The `pbkdf2` library's default hashing algorithm for `PBKDF2` can be HMAC-SHA1 if not explicitly specified, which is less secure than SHA-256 or SHA-512 for password hashing in modern applications.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Always use a high iteration count, typically hundreds of thousands, and increase it over time as computing power grows. `iterations = 600000` or higher is a good starting point for 2026.","message":"Using a low iteration count (rounds) severely weakens the security against brute-force attacks. Older examples or default values might be dangerously low for current computing power.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Generate a unique salt for each password using `os.urandom(16)` (or more bytes) and store it securely with the derived key/hash. Never use a fixed or easily guessable salt.","message":"Failing to use a unique, cryptographically secure random salt for each password or not storing the salt alongside the hash is a critical security vulnerability. Reusing salts or using predictable salts enables rainbow table attacks.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Ensure all PBKDF2 parameters (password, salt, iterations, desired key length, and HMAC hash algorithm) are identical across implementations. Convert passwords and salts to byte strings consistently (e.g., `password.encode('utf-8')`). Explicitly set the hash algorithm, e.g., 'sha256'. Confirm the derived key length (`dklen`) is the same. Python's `hashlib.pbkdf2_hmac` is often easier to synchronize.","cause":"Inconsistent parameters (hash algorithm, salt encoding, iteration count, key length) or byte-string handling between implementations. Forgetting that `pbkdf2` often defaults to SHA-1 or different byte representations.","error":"PBKDF2 output differs across platforms/languages (e.g., Python vs C#)"},{"fix":"Verify the correct installation with `pip show pbkdf2` and check the import: `from pbkdf2 import PBKDF2` or `from pbkdf2 import crypt`. If `pbkdf2.py` is directly in the path, it might be picked up instead of the installed package. Consider using the fully qualified name `pbkdf2.PBKDF2` or `pbkdf2.crypt` if `from pbkdf2 import ...` causes issues due to other modules named `pbkdf2`.","cause":"Incorrect import statement or a different `pbkdf2` package being installed/imported. Some systems might have other `pbkdf2` related modules or older versions where `PBKDF2` might be nested.","error":"AttributeError: 'module' object has no attribute 'PBKDF2' or 'crypt'"},{"fix":"Encode the password and salt to byte strings before passing them to `PBKDF2` or `crypt`. For example: `password.encode('utf-8')` and `salt.encode('utf-8')` (if salt is a string) or `os.urandom(16)` for binary salt.","cause":"The `pbkdf2` functions expect byte strings for `password` and `salt`, but a Python 3 `str` (unicode) object was provided. This is a common Python 2 to 3 migration issue.","error":"TypeError: ('expected bytes, got str',)"}]}