#crypto #hash #password #security

nightly passwors

Passwors is a simple password handling library that utilises Rust’s type system to enfore better password handling. Use it as a basic building block for more complex authentication systems.

2 releases

Uses old Rust 2015

0.1.1 Aug 30, 2016
0.1.0 Aug 30, 2016

#88 in #password

MIT license

51KB
591 lines

passwors

Passwors is a simple password handling library that utilises Rust's type system to enfore better password handling. Use it as a basic building block for more complex authentication systems.

Crates.io Latest Release Travis CI Build Status Dependency CI Status Clippy Linting Result MIT License

let pw      = ClearTextPassword::from_string(some_password_source).unwrap();
let salt    = HashSalt::new().unwrap();  // You should grab this from your database.
let a2hash  = Argon2PasswordHasher::default();
let pw_hash = pw.hash(&a2hash, &salt);

assert_eq!(pw_hash, stored_hash, "Login failed!");

View the Documentation

Table of Contents

Why?

More and more web applications are written in Rust, and all of them require password handling. In addition to that, there are still lots of web sites out there having exceptionally bad password management. This crate is designed to make good password handling easy by including best practices into its design as much as possible, so that anyone can just put Passwors into their projects without worrying too much about the details.

Now, what are such best practices?

  • Passwords should be hard to guess.
  • Passwords are secrets only their owners should know.
  • Passwords should be hashed using a strong algorithm, to keep the clear text password secret while still being able to compare and store "passwords".
  • Password hashes should be salted using random data.

Now, let's have a look at how Passwors helps achieving those goals.

Hard to Guess

Aka. measuring a password's "strength". Here, Passwors only enforces a minimum and a maximum password length. Before you get a heart attack: The maximum length is set very high, so that even the craziest passwords don't need to be truncated. The minimum is at least 14 characters, as advised by the NIST in 2016. Additionally, passwords are handled as blobs of raw bytes, which means that nothing stops you from supporting all of Unicode in your password fields. And you should support all of Unicode in your password fields. Add a complete character map next to your fields if you want to be extra fancy.

These features alone, however, don't make user's passwords more secure. Neither do character class requirements. To really ensure that only strong passwords will be accepted, you need a decent password strength calculator. I recommend using zxcvbn. It has its few flaws, but all in all it is the best meter I know.

Passwords are Secrets

Yes, your application has to receive a user's clear text password at some point in time, but it shouldn't be able to try reading it or getting any other kind of information like its length. All you are allowed to do is hash it and then forget it.

ClearTextPassword does exactly that. It prevents you from having unnecessary copies of clear text passwords around in memory and prevents you from reading, comparing, storing, or doing other nasty things with it. Once created, all you can do with it is hash it. And to get a HashedPassword, you need a ClearTextPassword enforcing these rules.

ClearTextPassword even goes so far that it zero-fills its own memory on drop, and that it zero-fills the sources where it got its password data from. This ensures that freeing memory cannot leak old clear text passwords for an uncertain amount of time.

As an extra note: Good private key storages use techniques that even prevent memory pages containing key data from being swapped to disk. I decided not to use this technique, at least for now, as clear text passwords are supposed to be very, very short-lived, especially compared to decrypted private keys, which makes it very unlikely to ever be hit by swapping.

Strong Password Hashes

This is the most security critical part. You choose a bad hashing algorithm like MD5 and your security is crap. You make unnecessary copies of the clear text password and your security might be weakened. You provided bad password hasher settings and your security is crap. You don't use a given salt and your security is crap. Your output hash is very small and your security is crap.

Therefore, a PasswordHasher's hash function is marked as being unsafe. Implementations should be chosen with caution. This is why Passwors optionally provides you a default implementation using argon2rs. Other good hashing algorithms are scrypt and bcrypt.

Salted Hashes

To have a good salt, you should have 16 bytes or more of good random data. Therefore, HashSalts are created using a CSPRNG provided by the operating system, and are at least 16 bytes in size.

Building Passwors

To compile passwors and use it in your own library or application, you first need a nightly installation of Rust. Add the following line to your project's Cargo.toml:

[dependencies]
passwors = "*"

And in your lib.rs or main.rs add this line:

extern crate passwors;

You can then use and use Passwors' types:

use passwors::{ClearTextPassword, HashedPassword, HashSalt, PasswordHasher};

As Passwors uses some not yet stable features of Rust, you need a nightly Rust installation. Speaking about features, there are two optional features extending Passwors' functionality. By default, Passwors provides a default PasswordHasher implementation using argon2rs and serialising HashSalts and HashedPasswords using serde. Disable the default features if you don't want to use Argon2i as your password hasher or SerDe to serialise data. You can then add each feature individually by adding use_argon2rs or use_serde to your Cargo.toml:

[dependencies.passwors]
version          = "*"
features         = ["use_serde", "use_argon2rs"]
default-features = false

Usage

There are four types involved when it comes to handling passwords:

  • ClearTextPassword is what you get from a user's inputs. This is a secret token that only its creator should know. As a secret token, you cannot compare or copy or read it.
  • HashedPassword is what you use to validate one's identity. It is there to be compared, stored, read, and what not.
  • HashSalt is a blob of random data, generated using strong CSPRNGs only. It should be uniquely generated for each of your users and is used to randomise the outcome of hashing a clear text password.
  • PasswordHasher is a trait for... well... password hashers. They are the only unsafe component here, as they are the only ones that are able to read a user's clear text password.

License

Passwors is licensed under the MIT license.

Copyright (c) 2016, Olaf "Evrey" Kukula

Dependencies

~1.5MB
~31K SLoC