rust-djangohashers alternatives and similar packages
Based on the "Cryptography" category.
Alternatively, view rust-djangohashers alternatives based on common mentions on social networks and blogs.
-
Ockam
Orchestrate end-to-end encryption, cryptographic identities, mutual authentication, and authorization policies between distributed applications – at massive scale. -
exonum
An extensible open-source framework for creating private/permissioned blockchain applications -
sodiumoxide
DISCONTINUED. [DEPRECATED] Sodium Oxide: Fast cryptographic library for Rust (bindings to libsodium) -
RustCrypto Elliptic Curves
Collection of pure Rust elliptic curve implementations: NIST P-224, P-256, P-384, P-521, secp256k1, SM2 -
miscreant
DISCONTINUED. Meta-repository for Miscreant: misuse-resistant symmetric encryption library with AES-SIV (RFC 5297) and AES-PMAC-SIV support -
orion
DISCONTINUED. Usable, easy and safe pure-Rust crypto [Moved to: https://github.com/orion-rs/orion] -
recrypt
A set of cryptographic primitives for building a multi-hop Proxy Re-encryption scheme, known as Transform Encryption. -
schannel-rs
Schannel API-bindings for rust (provides an interface for native SSL/TLS using windows APIs)
SaaSHub - Software Alternatives and Reviews
* Code Quality Rankings and insights are calculated and provided by Lumnify.
They vary from L1 to L5 with "L5" being the highest.
Do you think we are missing an alternative of rust-djangohashers or a related project?
README
Rust DjangoHashers
A Rust port of the password primitives used in Django Project.
Django's django.contrib.auth.models.User
class has a few methods to deal with passwords, like set_password()
and check_password()
; DjangoHashers implements the primitive functions behind those methods. All Django's built-in hashers are supported.
This library was conceived for Django integration, but is not limited to it; you can use the password hash algorithm in any Rust project (or FFI integration), since its security model is already battle-tested.
TL;DR
Content of examples/tldr.rs
:
extern crate djangohashers;
use djangohashers::*;
fn main() {
let encoded = make_password("K2jitmJ3CBfo");
println!("Hash: {:?}", encoded);
let is_valid = check_password("K2jitmJ3CBfo", &encoded).unwrap();
println!("Is valid: {:?}", is_valid);
}
Output:
$ cargo run --quiet --example tldr
Hash: "pbkdf2_sha256$30000$E2DtC4weM2DY$ZTso63dGXbq+QdVGUwq8Y05RgyUc3AsUSfswqUOZ3xc="
Is valid: true
Installation
Add the dependency to your Cargo.toml
:
[dependencies]
djangohashers = "^1.3"
Reference and import:
extern crate djangohashers;
// Everything (it's not much):
use djangohashers::*;
// Or, just what you need:
use djangohashers::{check_password, make_password, Algorithm};
Compiling Features
New in
0.3.0
.
By default all the hashers are enabled, but you can pick only the hashers that you need to avoid unneeded dependencies.
default
: all hashers.with_pbkdf2
: only PBKDF2 and PBKDF2SHA1.with_argon2
: only Argon2.with_bcrypt
: only BCrypt and BCryptSHA256.with_legacy
: only SHA1, MD5, UnsaltedSHA1, UnsaltedMD5 and Crypt.fpbkdf2
: enables Fast PBKDF2 (requires OpenSSL, see below).fuzzy_tests
: only for development, enables fuzzy tests.
Fast PBKDF2 Version
Unfortunately the crate pbkdf2
implementation is not properly optimized: it does not adhere to the loop inlines and buffering used in modern implementations. The package fastpbkdf2 uses a C-binding of a library that requires OpenSSL.
Installation
Add the dependency to your Cargo.toml
declaring the feature:
[dependencies.djangohashers]
version = "^1.2"
features = ["fpbkdf2"]
You need to install OpenSSL and set the environment variable to make it visible to the compiler; this changes depending on the operation system and package manager, for example, in macOS you may need to do something like this:
Via Homebrew:
$ brew install openssl
$ CFLAGS="-I/usr/local/opt/openssl/include" cargo ...
Via MacPorts:
$ sudo port install openssl
$ CFLAGS="-I/opt/local/include" cargo ...
For other OSs and package managers, follow the guide of how to install Python’s Cryptography dependencies, that also links against OpenSSL.
Performance
Method | Encode or Check | Performance |
---|---|---|
Django 2.2.4 on Python 3.7.4 | 69ms | Baseline |
djangohashers with pbkdf2 (default) | 86ms | 25% slower |
djangohashers with fastpbkdf2 | 42ms | 61% faster |
Replicate test above with Docker:
$ docker build -t rs-dj-hashers-profile .
...
$ docker run -t rs-dj-hashers-profile
Hashing time: 69ms (Python 3.7.4, Django 2.2.4).
Hashing time: 86ms (Vanilla PBKDF2).
Hashing time: 42ms (Fast PBKDF2).
Compatibility
DjangoHashers passes all relevant unit tests from Django 1.4 to 2.2, there is even a line-by-line translation of tests/auth_tests/test_hashers.py.
What is not covered:
- Upgrade/Downgrade callbacks.
- Any 3rd-party hasher outside Django's code.
- Some tests that makes no sense in idiomatic Rust.
Usage
API Documentation, thanks to docs.rs project!
Verifying a Hashed Password
Function signatures:
pub fn check_password(password: &str, encoded: &str) -> Result<bool, HasherError> {}
pub fn check_password_tolerant(password: &str, encoded: &str) -> bool {}
Complete version:
let password = "KRONOS"; // Sent by the user.
let encoded = "pbkdf2_sha256$24000$..."; // Fetched from DB.
match check_password(password, encoded) {
Ok(valid) => {
if valid {
// Log the user in.
} else {
// Ask the user to try again.
}
}
Err(error) => {
// Deal with the error.
}
}
Possible Errors:
HasherError::UnknownAlgorithm
: anything not recognizable as an algorithm.HasherError::BadHash
: Hash string is corrupted.HasherError::InvalidIterations
: number of iterations is not a positive integer.HasherError::EmptyHash
: hash string is empty.HasherError::InvalidArgon2Salt
: Argon2 salt should be Base64 encoded.
If you want to automatically assume all errors as "invalid password", there is a shortcut for that:
if check_password_tolerant(password, encoded) {
// Log the user in.
} else {
// Ask the user to try again.
}
Generating a Hashed Password
Function signatures:
pub fn make_password(password: &str) -> String {}
pub fn make_password_with_algorithm(password: &str, algorithm: Algorithm) -> String {}
pub fn make_password_with_settings(password: &str, salt: &str, algorithm: Algorithm) -> String {}
Available algorithms:
Algorithm::PBKDF2
(default)Algorithm::PBKDF2SHA1
Algorithm::Argon2
Algorithm::BCryptSHA256
Algorithm::BCrypt
Algorithm::SHA1
Algorithm::MD5
Algorithm::UnsaltedSHA1
Algorithm::UnsaltedMD5
Algorithm::Crypt
The algorithms follow the same Django naming model, minus the PasswordHasher
suffix.
Using default settings (PBKDF2 algorithm, random salt):
let encoded = make_password("KRONOS");
// Returns something like:
// pbkdf2_sha256$24000$go9s3b1y1BTe$Pksk4EptJ84KDnI7ciocmhzFAb5lFoFwd6qlPOwwW4Q=
Using a defined algorithm (random salt):
let encoded = make_password_with_algorithm("KRONOS", Algorithm::BCryptSHA256);
// Returns something like:
// bcrypt_sha256$$2b$12$e5C3zfswn.CowOBbbb7ngeYbxKzJePCDHwo8AMr/SZeZCoGrk7oue
Using a defined algorithm and salt (not recommended, use it only for debug):
let encoded = make_password_with_settings("KRONOS", "seasalt", Algorithm::PBKDF2SHA1);
// Returns exactly this (remember, the salt is fixed!):
// pbkdf2_sha1$24000$seasalt$F+kiWNHXbMBcwgxsvSKFCWHnZZ0=
Warning: make_password_with_settings
and make_password_core
will both panic if salt is not only letters and numbers (^[A-Za-z0-9]*$
).
Generating a Hashed Password based on a Django version
New in
0.2.1
.
Django versions can have different number of iterations for hashers based on PBKDF2 and BCrypt algorithms; this abstraction makes possible to generate a password with the same number of iterations used in that versions.
use djangohashers::{Django, DjangoVersion};
let django = Django {version: DjangoVersion::V1_8}; // Django 1.8.
let encoded = django.make_password("KRONOS");
// Returns something like:
// pbkdf2_sha256$20000$u0C1E8jrnAYx$7KIo/fAuBJpswQyL7pTxO06ccrSjGdIe7iSqzdVub1w=
// |||||
// ...notice the 20000 iterations, used in Django 1.8.
Available versions:
DjangoVersion::CURRENT
Current Django version (3.1
for DjangoHashers1.3.1
).DjangoVersion::V1_4
Django 1.4DjangoVersion::V1_5
Django 1.5DjangoVersion::V1_6
Django 1.6DjangoVersion::V1_7
Django 1.7DjangoVersion::V1_8
Django 1.8DjangoVersion::V1_9
Django 1.9DjangoVersion::V1_10
Django 1.10DjangoVersion::V1_11
Django 1.11DjangoVersion::V2_0
Django 2.0DjangoVersion::V2_1
Django 2.1DjangoVersion::V2_2
Django 2.2DjangoVersion::V3_0
Django 3.0DjangoVersion::V3_1
Django 3.1DjangoVersion::V3_2
Django 3.2
Verifying a Hash Format (pre-crypto)
Function signature:
pub fn is_password_usable(encoded: &str) -> bool {}
You can check if the password hash is properly formatted before running the expensive cryto stuff:
let encoded = "pbkdf2_sha256$24000$..."; // Fetched from DB.
if is_password_usable(encoded) {
// Go ahead.
} else {
// Check your database or report an issue.
}
Contributing
- Be patient with me, I’m new to Rust and this is my first project.
- Don't go nuts with your mad-rust-skillz, legibility is a priority.
- Please use rustfmt in your code.
- Always include some test case.
License
Rust DjangoHashers is released under the 3-Clause BSD License.
tl;dr: "free to use as long as you credit me".
*Note that all licence references and agreements mentioned in the rust-djangohashers README section above
are relevant to that project's source code only.