Passlib
A Ruby password hashing library inspired by Python's Passlib. It provides a unified interface for creating and verifying password hashes across a wide range of algorithms and auto-detects the algorithm from any stored hash string, making it easy to support multiple formats or migrate between them.
Currently supported algorithms include argon2, balloon hashing, bcrypt, bcrypt-sha256, LDAP-style digests (salted and unsalted MD5, SHA-1, SHA-256, SHA-512, SHA3-256, and SHA3-512), MD5-crypt (including Apache variant), phpass, PBKDF2 (with SHA1, SHA256, SHA512, SHA3-256, and SHA3-512), scrypt, SHA1-crypt, SHA2-crypt (SHA-256 and SHA-512 variants), and yescrypt. The library is designed to be extensible, so support for additional algorithms can be added in the future.
Table of Contents
- Passlib
- Table of Contents
- Installation
- Features
- Create and verify hashes
- Recreating hashes
- Isolated contexts
- Upgrading password hashes
- Check algorithm availability at runtime
- Integration with other tools, libraries, and frameworks
- Devise
- Configuration
- Global configuration
- Preferred scheme
- Per-algorithm settings
- Configuration inheritance
- Thread safety
- Supported hash formats and algorithms
argon2balloonbcryptbcrypt_sha256ldap_digestmd5_cryptpbkdf2phpassscryptsha1_cryptsha2_cryptyescrypt- License
Installation
The passlib gem includes built-in support for all hash formats that only require OpenSSL (md5_crypt, sha1_crypt, sha2_crypt, pbkdf2, ldap_digest). Algorithms backed by an external gem are optional and loaded on demand, so you can install only the ones you need.
gem install passlib
# Optional algorithm dependencies (install any combination):
gem install bcrypt
gem install argon2
gem install scrypt
gem install balloon_hashing
gem install yescrypt
To install passlib together with all optional dependencies at once, use passlib-all:
gem install passlib-all
With Bundler, add only what you need:
# Gemfile
gem "passlib"
# Optional, add any combination:
gem "bcrypt"
gem "argon2"
gem "scrypt"
gem "balloon_hashing"
gem "yescrypt"
Or pull in everything at once:
# Gemfile
gem "passlib-all"
Features
Create and verify hashes
All hash classes share the same interface. Call .create to hash a new password, .load to parse a stored hash string, and #verify to verify a plaintext against a loaded hash.
# Hash a new password (uses the configured default algorithm)
hash = Passlib.create("hunter2")
hash.to_s # => "$argon2id$..."
hash.verify("hunter2") # => true
hash.verify("wrong") # => false
# Load a stored hash and verify
hash = Passlib.load("$argon2id$...")
hash.verify("hunter2") # => true
Passlib.load auto-detects the algorithm from the hash string, so you can verify hashes without knowing which algorithm produced them:
Passlib.load("$2a$12$...").verify("hunter2") # bcrypt
Passlib.load("$argon2id$...").verify("hunter2") # argon2
Passlib.load("{SSHA512}...").verify("hunter2") # LDAP
For the common case of verifying a stored hash, Passlib.verify combines load and match in one call:
Passlib.verify("hunter2", "$argon2id$...") # => true
The verify methods are also aliased as matches?, valid_password?, valid_secret?, and on Password instances as ===, which allows usage in case statements:
hash = Passlib.load("$argon2id$...")
case "hunter2"
when hash then puts "Password is correct"
else puts "Password is incorrect"
end
Recreating hashes
Most algorithms also support #create_comparable, which re-hashes a plaintext using the same parameters (salt, rounds, etc.) as an existing hash. Not all algorithms implement it, so check with respond_to? before calling it directly. Note that comparing the resulting strings with == is vulnerable to timing attacks; use Passlib.secure_compare instead:
if hash.respond_to?(:create_comparable)
rehashed = hash.create_comparable("hunter2")
Passlib.secure_compare(rehashed, hash) # => true if passwords match
end
Isolated contexts
Passlib::Context lets you create isolated configuration contexts, each with its own preferred algorithm and settings, without touching the global Passlib configuration. This is useful in multi-tenant applications or libraries that want to avoid interfering with the host app's configuration.
context = Passlib::Context.new(preferred_scheme: :bcrypt)
hash = context.create("hunter2")
hash.class # => Passlib::BCrypt
context.verify("hunter2", hash) # => true
A context can inherit from another context or configuration object, so you can share a base setup and override only what you need:
base = Passlib::Context.new(preferred_scheme: :bcrypt)
context = Passlib::Context.new(base)
context.create("hunter2").class # => Passlib::BCrypt
You can also reconfigure a context after creation using configure:
context = Passlib::Context.new
context.configure { |c| c.preferred_scheme = :bcrypt }
A context exposes the same interface as the Passlib module.
Upgrading password hashes
As hashing standards evolve, stored hashes may need to be migrated to a stronger algorithm or higher cost parameters. Passlib.upgrade? checks whether a hash needs upgrading, and Passlib.upgrade performs the upgrade during login when the plaintext password is available.
Passlib.config.preferred_scheme = :bcrypt
Passlib.config.bcrypt.cost = 12
# Check whether a hash is outdated
Passlib.upgrade?("$2a$04$...") # => true (cost 4 is below the configured 12)
Passlib.upgrade?("$2a$12$...") # => false (already at cost 12)
Passlib.upgrade?("{SSHA512}...") # => true (wrong algorithm)
upgrade combines verification and re-hashing in one step, returning a new hash when an upgrade is needed or nil when no change is required. Call it at login time and, when it returns a new hash, persist it in place of the old one:
def login(user, password)
return false unless Passlib.verify(password, user.password_hash)
if new_hash = Passlib.upgrade(password, user.password_hash)
user.update(password_hash: new_hash.to_s)
end
true
end
Or a simple one-line upgrade:
hash = Passlib.upgrade(password, hash) || hash
upgrade verifies the password before re-hashing by default. Pass verify: false to skip verification:
new_hash = Passlib.upgrade(password, stored_hash, verify: false)
The upgrade? method on Passlib (or any other context) returns true in two cases:
- The hash uses a different algorithm than the configured preferred scheme.
- It uses the right algorithm but with cost parameters that don't exactly match the current configuration.
For the second case, an exact match is required, so a hash with higher costs than configured is also considered outdated (allowing a downgrade when parameters were set too high for acceptable performance).
Check algorithm availability at runtime
Since some algorithms depend on optional gems, Passlib.available? lets you check at runtime whether a given algorithm can be used:
Passlib.available?(:argon2) # => true if the argon2 gem is installed, false otherwise
Passlib.available?(:bcrypt) # => true if the bcrypt gem is installed, false otherwise
Passlib.available?(:unknown) # => nil (unrecognized algorithm)
Integration with other tools, libraries, and frameworks
Devise
Use the devise-passlib gem to integrate Passlib with Devise:
# app/models/user.rb
class User < ApplicationRecord
devise :database_authenticatable, :passlib
end
It will respect the global Passlib configuration, but you can also specify options that only apply to devise hashes:
# config/initializers/devise.rb
Devise.setup do |config|
config.passlib.preferred_scheme = :argon2
config.passlib.argon2.profile = :rfc_9106_high_memory
end
This is a drop-in replacement for Devise's default bcrypt implementation, so you can use it with any of the supported algorithms and change the configuration without needing to modify your models or database. With the above configuration, it will automatically upgrade existing bcrypt hashes to argon2 on login.
Configuration
Global configuration
Passlib.config (also aliased as Passlib.configuration) returns the global Passlib::Configuration object. Changes to it affect all calls made through the Passlib module.
Passlib.config.preferred_scheme = :argon2
Passlib.create("hunter2") # => #<Passlib::Argon2 "$argon2id$...">
Use Passlib.configure (or its alias Passlib.setup) to apply several settings in one block:
Passlib.configure do |c|
c.preferred_scheme = :bcrypt
c.bcrypt.cost = 14
end
Preferred scheme
preferred_scheme= sets the single algorithm used for new hashes. preferred_schemes= accepts an ordered list: Passlib picks the first one whose optional gem is available. This lets you specify a preference order without requiring every gem to be installed:
Passlib.config.preferred_schemes = [:argon2, :bcrypt, :sha2_crypt]
Passlib.create("hunter2") # => argon2 if available, otherwise bcrypt, etc.
preferred_scheme (the reader, without =) returns the first available scheme from the list, or the configured single value.
Default setting
The default preference order is:
The last option should be available in all environments since it only depends on OpenSSL, and works with older OpenSSL versions that don't support SHA3.
[!NOTE] As you can see, bcrypt-sha256 is not included in the default, even though it improves security for long passwords. This is because it is not supported by any other Ruby library, but most environments come with bcrypt loaded by default, and adding it above bcrypt would cause all passwords to be re-hashed in a format that creates a hard dependency on Passlib.
Per-algorithm settings
Each algorithm has its own configuration namespace under Passlib.config. Algorithm-specific options (cost, rounds, variant, etc.) are set there:
Passlib.configure do |config|
config.bcrypt.cost = 14
config.argon2.t_cost = 4
config.argon2.m_cost = 18 # 2^18 = 256 MiB
config.sha2_crypt.rounds = 800_000
config.pbkdf2.rounds = 40_000
config.scrypt.ln = 17
end
The full list of options for each algorithm is documented in the Supported hash formats and algorithms section.
Configuration inheritance
Passlib::Configuration objects can inherit from a parent. A child reads the parent's value for any option it has not set itself, and changes to the parent propagate until the child is frozen.
base = Passlib::Configuration.new(preferred_scheme: :bcrypt)
base.bcrypt.cost = 12
child = Passlib::Configuration.new(base)
child.preferred_scheme # => :bcrypt (inherited)
child.bcrypt.cost # => 12 (inherited)
child.bcrypt.cost = 14
child.bcrypt.cost # => 14 (overridden)
base.bcrypt.cost # => 12 (unchanged)
freeze snapshots all values from the parent chain into the child and prevents further mutation. The parent itself is not frozen:
child.freeze
base.bcrypt.cost = 16
child.bcrypt.cost # => 14 (snapshot is unaffected)
base.frozen? # => false
Thread safety
The global configuration uses Concurrent::Map for its options store and is safe to read concurrently. Writes should be done at application startup before any concurrent access. For runtime isolation, create a Passlib::Context (see isolated contexts) per request or tenant instead of mutating the global config.
Supported hash formats and algorithms
argon2
Uses the argon2 gem, which is a wrapper around the reference C implementation of the Argon2 password hashing algorithm. This is the OWASP recommended password hashing algorithm, and is the winner of the Password Hashing Competition. It is designed to be resistant to GPU cracking attacks, and is highly configurable in terms of memory usage, time cost, and parallelism.
hash = Passlib::Argon2.hash("password") # => #<Passlib::Argon2 "$argon2id$...">
hash.to_s # => "$argon2id$..."
hash.verify("password") # => true
# Pass options to argon2 gem:
Passlib::Argon2.hash("password", t_cost: 4, m_cost: 16) # => #<Passlib::Argon2 "$argon2id$...">
# Change the default options:
Passlib.config.argon2.profile = :rfc_9106_high_memory
# Set argon2 to be the default for new hashes:
Passlib.config.default_scheme = :argon2
Passlib.create("password") # => #<Passlib::Argon2 "$argon2id$...">
Generated hashes are in the Modular Crypt Format (MCF), using argon2id identifier.
It is also possible to load hashes with the IDs argon2i and argon2d.
Hash format:
"$argon2#d$v=#{v}$m=#{m},t=#{t},p=#{p}$#{salt}$#{digest}"
The implementation does not (currently) support recreating the exact same hash.
balloon
Uses the balloon_hashing gem. Balloon hashing is a memory-hard password hashing function designed to be resistant to GPU and ASIC attacks.
hash = Passlib::Balloon.create("password") # => #<Passlib::Balloon "$balloon$...">
hash.verify("password") # => true
# With options:
Passlib::Balloon.create("password", s_cost: 1024, t_cost: 3, algorithm: "sha256")
Generated hashes are in the Modular Crypt Format (MCF).
Hash format:
"$balloon$v=1$alg=#{algorithm},s=#{s_cost},t=#{t_cost}$#{salt}$#{checksum}"
Options:
:s_cost— space cost (memory usage):t_cost— time cost (iterations):algorithm— digest algorithm name (e.g."sha256")
bcrypt
Standard hashing algorithm used by Rails and Devise. Uses the bcrypt gem. It uses the Blowfish cipher internally, and is designed to be slow and resistant to brute-force attacks. It is widely supported and has been around for a long time, but is no longer considered the best choice for password hashing due to its relatively low memory usage.
hash = Passlib::BCrypt.create("password", cost: 12)
hash.verify("password") # => true
hash.to_s # => "$2a$12$..."
Generated hashes are in the Modular Crypt Format (MCF), using the $2a$ identifier. Hashes with the IDs $2b$, $2x$, and $2y$ are also accepted on load.
Hash format:
"$2a$#{cost}$#{salt}#{checksum}"
Recreating the exact same hash is supported via :salt.
Options:
:cost— bcrypt cost factor, 4–31 (default:BCrypt::Engine::DEFAULT_COST):salt— custom bcrypt salt string (normally auto-generated, must include the cost factor in standard bcrypt format)
bcrypt_sha256
A hybrid scheme that works around bcrypt's 72-byte password truncation limit. The password is first run through HMAC-SHA256 (keyed with the bcrypt salt), the 32-byte result is base64-encoded, and that string is then hashed with standard bcrypt. Passwords of any length are handled correctly. Uses the bcrypt gem.
This format is compatible with Python's passlib.hash.bcrypt_sha256.
hash = Passlib::BcryptSHA256.create("password", cost: 12)
hash.verify("password") # => true
hash.to_s # => "$bcrypt-sha256$v=2,t=2b,r=12$..."
# Long passwords are not truncated:
long = "a" * 100
Passlib::BcryptSHA256.create(long).verify(long) # => true
Passlib::BcryptSHA256.create(long).verify("a" * 99 + "b") # => false
Generated hashes are in the Modular Crypt Format (MCF), using the $bcrypt-sha256$ identifier.
Hash format:
$bcrypt-sha256$v=2,t=2b,r=#{cost}$#{salt22}$#{digest31}
Options:
:cost— bcrypt cost factor, 4–31 (default:BCrypt::Engine::DEFAULT_COST):salt— custom bcrypt salt string in$2b$NN$<22chars>format (normally auto-generated)
ldap_digest
[!WARNING] Not all of the supported variants are considered secure by modern standards. Moreover, even the ones that are aren't suitable for new hashes due to their low iteration count and lack of memory hardness (they aren't key derivation functions). They are supported here to verify existing hashes and migrate users to a stronger scheme on next login. Do not use them for new password hashes.
LDAP RFC 2307-style password hashes using digest algorithms. Implemented using OpenSSL, no additional gem dependencies.
Plain (unsalted) and salted variants are supported for MD5, SHA-1, SHA-256, SHA-512, SHA3-256, and SHA3-512. MD5 and SHA-1 hashes may be stored in hex encoding (as produced by some LDAP implementations) or standard base64, both are detected automatically on load.
hash = Passlib::LdapDigest.create("password", variant: "SSHA512")
hash.verify("password") # => true
hash.to_s # => "{SSHA512}..."
Supported variants (LDAP scheme names):
| Variant | Algorithm | Salted |
|---|---|---|
MD5 |
MD5 | no |
SMD5 |
MD5 | yes |
SHA |
SHA-1 | no |
SSHA |
SHA-1 | yes |
SHA256 |
SHA-256 | no |
SSHA256 |
SHA-256 | yes |
SHA512 |
SHA-512 | no |
SSHA512 |
SHA-512 | yes |
SHA3-256 |
SHA3-256 | no |
SSHA3-256 |
SHA3-256 | yes |
SHA3-512 |
SHA3-512 | no |
SSHA3-512 |
SHA3-512 | yes |
Hash format:
"{#{variant}}#{checksum_b64}" # base64 encoding (default)
"{#{variant}}#{checksum_hex}" # hex encoding (MD5 and SHA only)
Default variant: SSHA512.
Options:
:variant— LDAP scheme name (case-insensitive, symbols accepted, underscores may substitute dashes):salt— raw binary salt (only used for salted schemes, default: 4 random bytes for MD5/SHA-1, 8 for others):hex— encode as hex instead of base64, only applicable toMD5andSHAschemes (default:false)
md5_crypt
[!WARNING] MD5-crypt is a legacy algorithm with a fixed, low round count that is vulnerable to brute-force attacks with modern hardware. It is supported here to verify existing hashes and migrate users to a stronger scheme. Do not use it for new hashes.
MD5-crypt was designed by Poul-Henning Kamp for FreeBSD in 1994 and was for many years the default password scheme on Linux systems. It runs 1000 rounds of an MD5-based mixing function. Implemented using OpenSSL, no additional gem dependencies.
Apache's variant ($apr1$) is also supported. The two variants are algorithmically identical and differ only in their MCF identifier. Both are auto-detected on load.
hash = Passlib::MD5Crypt.create("hunter2")
hash.verify("hunter2") # => true
hash.to_s # => "$1$...$..."
apr = Passlib::MD5Crypt.create("hunter2", variant: :apr)
apr.to_s # => "$apr1$...$..."
Hash format:
"$1$#{salt}$#{checksum}" # standard MD5-crypt
"$apr1$#{salt}$#{checksum}" # Apache APR variant
salt— 0-8 characters from./0-9A-Za-z(default: 8 random characters)checksum— 22-character encoding of the 16-byte MD5 digest
Options:
:variant— selects the MCF identifier::standard(default, produces$1$) or:apr(produces$apr1$):salt— custom salt string, 0-8 characters (default: 8 random characters)
pbkdf2
PBKDF2 hashes via OpenSSL, no additional gem dependencies. New hashes are always produced in the Modular Crypt Format (MCF). Two additional formats are accepted on load and normalized to MCF: LDAP-style hashes and Cryptacular's cta_pbkdf2_sha1 format.
hash = Passlib::PBKDF2.create("password", variant: "pbkdf2-sha256", rounds: 29_000)
hash.verify("password") # => true
hash.to_s # => "$pbkdf2-sha256$29000$...$..."
# Load and normalize an LDAP hash to MCF:
Passlib::PBKDF2.load("{PBKDF2-SHA256}29000$...$...").to_s
# => "$pbkdf2-sha256$29000$...$..."
# Load and normalize a Cryptacular cta_pbkdf2_sha1 hash to MCF:
Passlib::PBKDF2.load("$p5k2$2710$...$...").to_s
# => "$pbkdf2$10000$...$..."
Hash format (MCF, used for new hashes):
"$#{variant}$#{rounds}$#{salt_ab64}$#{dk_ab64}"
Cryptacular cta_pbkdf2_sha1 format (accepted on load, normalized to MCF):
"$p5k2$#{rounds_hex}$#{salt_b64url}$#{dk_b64url}"
Supported variants:
| MCF variant | LDAP variant | Digest | Default rounds | Key length |
|---|---|---|---|---|
pbkdf2 |
PBKDF2 |
SHA-1 | 131,000 | 20 bytes |
pbkdf2-sha256 |
PBKDF2-SHA256 |
SHA-256 | 29,000 | 32 bytes |
pbkdf2-sha512 |
PBKDF2-SHA512 |
SHA-512 | 25,000 | 64 bytes |
pbkdf2-sha3-256 |
PBKDF2-SHA3-256 |
SHA3-256 | 29,000 | 32 bytes |
pbkdf2-sha3-512 |
PBKDF2-SHA3-512 |
SHA3-512 | 25,000 | 64 bytes |
Default variant: pbkdf2-sha3-512 if the OpenSSL build supports SHA3, otherwise pbkdf2-sha512.
Options:
:variant— digest variant (case-insensitive, symbols accepted, underscores may substitute dashes):rounds— iteration count (default: variant-specific, see table above):salt— raw binary salt (default: 16 random bytes):key_len— derived key length in bytes (default: variant-specific, see table above)
phpass
[!WARNING]
phpassis a legacy algorithm based on MD5 and should not be used for new hashes. It is supported here to verify existing hashes and migrate users to a stronger scheme on next login.
The phpass Portable Hash, widely used by PHP applications such as WordPress, Drupal, and phpBB as a fallback password scheme. It applies iterated MD5 with a configurable round count. Implemented using OpenSSL, no additional gem dependencies.
Both the standard $P$ identifier and the phpBB3 $H$ variant are recognized on load. New hashes are always produced with $P$.
hash = Passlib::PHPass.create("password", rounds: 19)
hash.verify("password") # => true
hash.to_s # => "$P$H..."
# Load and verify a $H$ (phpBB3) hash without any conversion:
Passlib::PHPass.load("$H$9IQRg...").verify("password")
Hash format:
"$P$#{rounds}#{salt}#{checksum}"
rounds— single character from the phpass alphabet encodinglog2(iterations), 7–30salt— 8-character salt using the phpass alphabet./0-9A-Za-zchecksum— 22-character encoding of the 16-byte MD5 digest
Options:
:rounds— base-2 log of the iteration count, 7–30, clamped if out of range (default: 19, i.e. 2^19 = 524 288 iterations):salt— custom 8-character salt using the phpass alphabet (normally auto-generated)
scrypt
Uses the scrypt gem. scrypt is a memory-hard key derivation function designed to be expensive in both CPU and memory, making it resistant to brute-force attacks with custom hardware.
hash = Passlib::SCrypt.create("password", ln: 14)
hash.verify("password") # => true
hash.to_s # => "$scrypt$ln=14,r=8,p=1$...$..."
Generated hashes are in the Modular Crypt Format (MCF). Two hash formats are accepted on load:
"$scrypt$ln=#{ln},r=#{r},p=#{p}$#{salt}$#{checksum}" # Passlib MCF
"#{n_hex}$#{r_hex}$#{p_hex}$#{salt_hex}$#{checksum_hex}" # scrypt gem native (normalized to MCF on load)
New hashes are always produced in the Passlib MCF format.
Options:
:ln— CPU/memory cost as a base-2 log (default:16, meaning N=65536), mutually exclusive with:n:n— CPU/memory cost as an integer power of two (converted to:lninternally):r— block size (default:8):p— parallelization factor (default:1):salt— custom salt as a binary string (default: 16 random bytes):key_len— derived key length in bytes (default:32)
sha1_crypt
[!WARNING]
sha1_cryptis a legacy algorithm and should not be used for new hashes. It is supported here to verify existing hashes and migrate users to a stronger scheme on next login.
NetBSD's crypt-sha1 algorithm designed by Simon Gerraty. It applies iterated HMAC-SHA1 and supports passwords of any length. Implemented using OpenSSL, no additional gem dependencies.
hash = Passlib::SHA1Crypt.create("password", rounds: 480_000)
hash.verify("password") # => true
hash.to_s # => "$sha1$480000$...$..."
Hash format:
"$sha1$#{rounds}$#{salt}$#{checksum}"
rounds— decimal iteration count, 1–4,294,967,295salt— 1–64 characters from./0-9A-Za-z(default: 8 random characters)checksum— 28-character encoding of the 20-byte HMAC-SHA1 digest
Options:
:rounds— iteration count, 1–4,294,967,295, clamped if out of range (default: 480,000):salt— custom salt string, up to 64 characters (default: 8 random characters)
sha2_crypt
Pure-Ruby implementation of the SHA-crypt algorithm as specified by Ulrich Drepper. Implemented using OpenSSL, no additional gem dependencies.
Generated hashes are in the Modular Crypt Format (MCF). Both SHA-256 ($5$) and SHA-512 ($6$) variants are supported and auto-detected on load.
hash = Passlib::SHA2Crypt.create("password", bits: 512, rounds: 10_000)
hash.verify("password") # => true
hash.to_s # => "$6$rounds=10000$...$..."
Hash format:
"$#{id}$rounds=#{rounds}$#{salt}$#{checksum}" # explicit rounds
"$#{id}$#{salt}$#{checksum}" # implicit rounds (5,000)
| Variant | id |
Digest | Default rounds | Checksum length |
|---|---|---|---|---|
| SHA-256 | 5 |
SHA-256 | 535,000 | 43 characters |
| SHA-512 | 6 |
SHA-512 | 656,000 | 86 characters |
Rounds are clamped to the range 1,000–999,999,999. If no rounds= parameter appears in the hash string, 5,000 rounds are assumed (per spec).
Options:
:bits— selects the SHA variant:256or512(default:512):rounds— number of hashing rounds (default: variant-specific, see table above):salt— custom salt string, up to 16 characters (default: random)
yescrypt
Uses the yescrypt gem. yescrypt is the successor to scrypt, used as the default password hashing scheme in several modern Linux distributions.
hash = Passlib::Yescrypt.create("password")
hash.verify("password") # => true
hash.to_s # => "$y$..."
Generated hashes are in the Modular Crypt Format (MCF).
Hash format:
"$y$#{params}$#{salt}$#{checksum}"
Options:
:n_log2— base-2 log of the memory/CPU cost factor:r— block size:p— parallelization factor:t— additional time parameter:flags— algorithm flags bitmask:salt— custom salt (normally auto-generated)
License
Passlib is released under the MIT License. See MIT-LICENSE for details.