# argonautica-rs

[![Build Status](https://travis-ci.org/bcmyers/argonautica.svg?branch=master)](https://travis-ci.org/bcmyers/argonautica)
[![Crates.io](https://img.shields.io/crates/v/argonautica.svg)](https://crates.io/crates/argonautica)
[![Documentation](https://docs.rs/argonautica/badge.svg)](https://docs.rs/argonautica/)
[![Github.com](https://img.shields.io/badge/github-bcmyers%2Fargonautica-blue.svg)](http://www.github.com/bcmyers/argonautica)
![License](https://img.shields.io/crates/l/argonautica.svg)

## Overview

<b>argonautica</b> is a Rust crate for hashing passwords using the cryptographically-secure
[Argon2 hashing algorithm](https://tools.ietf.org/html/draft-irtf-cfrg-argon2-03).

[Argon2]((https://tools.ietf.org/html/draft-irtf-cfrg-argon2-03)) won the
[Password Hashing Competition](https://password-hashing.net/) in 2015, a several
year project to identify a successor to [bcrypt](https://en.wikipedia.org/wiki/Bcrypt),
[scrypt](https://en.wikipedia.org/wiki/Scrypt), and other common cryptographically-secure
hashing algorithms.

The <b>argonautica</b> crate was designed:
* to be easy to use,
* to have robust, beginner-friendly documentation, and
* to (as much as possible) follow the
  [Rust API guidelines](https://rust-lang-nursery.github.io/api-guidelines/)

<b>argonautica</b> was built with a simple use-case in mind: hashing passwords for storage in a
website's database. That said, it's also "feature-complete", meaning anything you can do with
the cannonical [C implementation](https://github.com/P-H-C/phc-winner-argon2) of Argon2
you can do with argonautica*.

<i>\* Indeed, argonautica has a feature that even the cannonical C implementation
lacks, i.e. hashing passwords with secret keys (the C implementation implements this, but
does not expose it publicly)</i>

## Hashing

Hashing passwords with <b>argonautica</b> is simple.  Just instantiate a default
[`Hasher`](struct.Hasher.html), provide it with a password and a secret key, and then
call the [`hash`](struct.Hasher.html#method.hash) method.
```rust
extern crate argonautica;

use argonautica::Hasher;

fn main() {
    let mut hasher = Hasher::default();
    let hash = hasher
        .with_password("P@ssw0rd")
        .with_secret_key("\
            secret key that you should really store in a .env file \
            instead of in code, but this is just an example\
        ")
        .hash()
        .unwrap();

    println!("{}", &hash);
    // 👆 prints a hash, which will be random since the default Hasher uses a random salt
}
```
## Verifying

Verifying passwords against a hash is equally as simple. Just instantiate a default
[`Verifier`](struct.Verifier.html), provide it with the password and the hash you would
like to compare, provide it with the secret key that was used to create the hash, and
then call the [`verify`](struct.Verifier.html#method.verify) method.
```rust
extern crate argonautica;

use argonautica::Verifier;

fn main() {
    let mut verifier = Verifier::default();
    let is_valid = verifier
        .with_hash("
            $argon2id$v=19$m=4096,t=192,p=4$\
            o2y5PU86Vt+sr93N7YUGgC7AMpTKpTQCk4tNGUPZMY4$\
            yzP/ukZRPIbZg6PvgnUUobUMbApfF9RH6NagL9L4Xr4\
        ")
        .with_password("P@ssw0rd")
        .with_secret_key("\
            secret key that you should really store in a .env file \
            instead of in code, but this is just an example\
        ")
        .verify()
        .unwrap();

    assert!(is_valid);
}
```
## Alternatives

If <b>argonautica</b> isn't your cup of tea, other Rust crates that will do Argon2 hashing for you
include [argon2rs](https://github.com/bryant/argon2rs) and
[rust-argon2](https://github.com/sru-systems/rust-argon2). If you're interesting
in password hashing with a different algorithm,
[rust-bcrypt](https://github.com/Keats/rust-bcrypt) might be worth checking out.

For what it's worth, besides API differences, <b>argonautica</b> has three key features that
other crates currently lack:
* The ability to use [SIMD](https://en.wikipedia.org/wiki/SIMD) instructions (even on stable),
  which can lead to significantly faster hashing times
    * For example, on default settings, argonautica with SIMD runs <b>over twice
      as fast</b> as other crates on the developer's early-2014 Macbook, which has access to
      [SIMD instructions](https://software.intel.com/sites/landingpage/IntrinsicsGuide/)
      through
      [AVX2](https://en.wikipedia.org/wiki/Advanced_Vector_Extensions#Advanced_Vector_Extensions)
    * <i>Note: SIMD instructions are specific to your CPU; so if you're compiling for
      machines other than your own, you should not turn on the SIMD feature</i>
* The ability to hash passwords with a secret key, which not even the
  [C implementation](https://github.com/P-H-C/phc-winner-argon2) exposes publicly
* The newest Argon2 variant: Argon2id

## Configuration

The default configurations for [`Hasher`](struct.Hasher.html) and
[`Verifier`](struct.Verifier.html) were chosen to be reasonably secure for the general
use-case of hashing passwords for storage in a website database, but if you want to use
<b>argonautica</b> for different reasons or if you just disagree with the chosen defaults,
customizing <b>argonautica</b> to meet your needs should hopefully be as easy and as intuitive
as using the defaults.

Here is an example that shows how to use [`Hasher`](struct.Hasher.html)'s custom
configuration options. It provides color on each of the options.
```rust
extern crate argonautica;
extern crate futures_cpupool;

use argonautica::Hasher;
use argonautica::config::{Backend, Variant, Version};
use futures_cpupool::CpuPool;

fn main() {
    let mut hasher = Hasher::default();
    hasher
        .configure_backend(Backend::C) // Default is `Backend::C`
        // 👆 argonautica was designed to support multiple backends (meaning multiple
        // implementations of the underlying Argon2 algorithm). Currently only the C backend
        // is supported, which uses the cannonical Argon2 library written in C to actually
        // do the work. In the future hopefully a Rust backend will also be supported, but,
        // for the moment, you must use `Backend::C`, which is the default. Using
        // `Backend::Rust` will result in an error (again, for the moment).
        .configure_cpu_pool(CpuPool::new(2))
        // 👆 There are two non-blocking methods on `Hasher` that perform computation on
        // a separate thread and return a `Future` instead of a `Result` (`hash_non_blocking`
        // and `hash_raw_non_blocking`). These methods allow argonautica to play nicely with
        // futures-heavy code, but need a `CpuPool` in order to work. The blocking
        // methods `hash` and `hash_raw` do not use a 'CpuPool'; so if you are using only
        // these blocking methods you can ignore this configuration entirely. If, however,
        // you are using the non-blocking methods and would like to provide your own `CpuPool`
        // instead of using the default, which is a lazily created `CpuPool` with the number
        // of threads equal to the number of logical cores on your machine, you can
        // configure your `Hasher` with a custom `CpuPool` using this method. This
        // might be useful if, for example, you are writing code in an environment which
        // makes heavy use of futures, the code you are writing uses both a `Hasher` and
        // a `Verifier`, and you would like both of them to share the same underlying
        // `CpuPool`.
        .configure_hash_len(16) // Default is `32`
        // 👆 The hash length in bytes is configurable. The default is 32. This is probably
        // a good number to use. 16 is also probably fine. You probably shouldn't go below 16
        .configure_iterations(192) // Default is `192`
        // 👆 Argon2 has a notion of "iterations" or "time cost". All else equal and generally
        // speaking, the greater the number of iterations, the longer it takes to perform the
        // hash and the more secure the resulting hash. More iterations basically means more
        // CPU load. This and "memory size" (see below) are the two primary parameters to
        // adjust in order to increase or decrease the security of your hash. The default is
        // 192 iterations, which was chosen because, along with the default memory size of
        // 4096, this leads to a hashing time of approximately 300 milliseconds on the
        // early-2014 Macbook Air that is the developer's machine. If you're going to use
        // argonautica in production, you should probably tweak this parameter (and the memory
        // size parameter) in order to increase the time it takes to hash to the maximum you
        // can reasonably allow for your use-case (e.g. to probably about 300-500 milliseconds
        // for the use-case of hashing user passwords for a website)
        .configure_lanes(2) // Default is number of logical cores on your machine
        // 👆 Argon2 can break up its work into one or more "lanes" during some parts of
        // the hashing algorithm. If you configure it with multiple lanes and you also
        // use multiple threads (see below) the hashing algorithm will performed its
        // work in parallel in some parts, potentially speeding up the time it takes to
        // produce a hash without diminishing the security of the result. By default,
        // the number of lanes is set to the number of logical cores on your machine
        .configure_memory_size(4096) // Default is `4096`
        // 👆 Argon2 has a notion of "memory size" or "memory cost" (in kibibytes). All else
        // equal and generally speaking, the greater the memory size, the longer it takes to
        // perform the hash and the more secure the resulting hash. More memory size basically
        // means more memory used. This and "iterations" (see above) are, again, generally
        // speaking, the two parameters to adjust in order to increase or decrease the
        // security of your hash. The default is 4096 kibibytes, which was chosen because,
        // again, along with the default iterations of 192, this leads to a hashing time of
        // approximately 300 milliseconds on the early-2014 Macbook Air that is the
        // developer's machine. If you're going to use argonautica in production, you should
        // probably tweak this parameter (and the iterations parameter) in order to increase
        // the time it takes to hash to the maximum you can reasonably allow for your use-case
        // (e.g. to probably about 300-500 milliseconds for the use-case of hashing user
        // passwords for a website)
        .configure_password_clearing(false) // Default is `false`
        // 👆 It is possible to have the underlying bytes of the password you provided
        // to `Hasher` be erased after each call to `hash`, `hash_raw` or their non-blocking
        // equivalents. If you want this extra security feature, set this configuration
        // to `true` (the default is `false`). If you set this configuration to `true`,
        // you will be required to provide `Hasher` with a mutable password (e.g.
        // a `String`, a `Vec<u8>`, a `&mut str`, or a `&mut [u8]` instead of a
        // `&str` or a `&[u8]`)
        .configure_secret_key_clearing(false) // Default is `false`
        // 👆 It is also possible to have the underlying bytes of the secret key you provided
        // to `Hasher` be erased after each call to `hash`, `hash_raw` or their non-blocking
        // equivalents. If you want this extra security feature, set this configuration
        // to `true` (the default is `false`). If you set this configuration to `true`,
        // you will be required to provide `Hasher` with a mutable secret key (e.g.
        // a `String`, a `Vec<u8>`, a `&mut str`, or a `&mut [u8]` instead of a `&str`
        // or a `&[u8]`)
        .configure_threads(2) // Default is number of logical cores on your machine
        // 👆 If you have configured `Hasher` to use more than one lane (see above), you
        // can get the hashing algorithm to run in parallel during some parts of the
        // computation by setting the number of threads to be greater than one as well,
        // potentially speeding up the time it takes to produce a hash without diminishing
        // the security of the result. By default, the number of threads is set to the number
        // of logical cores on your machine. If you set the number of threads to a number
        // greater than the number of lanes, `Hasher` will automatically reduce the number
        // of threads to the number of lanes
        .configure_variant(Variant::Argon2id) // Default is `Variant::Argon2id`
        // 👆 Argon2 has three variants: Argon2d, Argon2i, and Argon2id. Here is how these
        // variants are explained in the RFC: "Argon2 has one primary variant: Argon2id,
        // and two supplementary variants: Argon2d and Argon2i. Argon2d uses data-dependent
        // memory access, which makes it suitable for ... applications with no threats from
        // side-channel timing attacks. Argon2i uses data-independent memory access, which
        // is preferred for password hashing and password-based key derivation. Argon2id
        // works as Argon2i for the first half of the first iteration over the memory, and
        // as Argon2d for the rest, thus providing both side-channel attack protection and
        // brute-force cost savings due to time-memory tradeoffs." If you do not know which
        // variant to use, use the default, which is Argon2id
        .configure_version(Version::_0x13) // Default is `Version::_0x13`
        // 👆 Argon2 has two versions: 0x10 and 0x13. The latest version is 0x13 (as of 5/18).
        // Unless you have a very specific reason not to, you should use the latest
        // version (0x13), which is also the default
        .opt_out_of_secret_key(true); // Default is `false`
        // 👆 As an extra security measure, if you want to hash without a secret key, which
        // is not recommended, you must explicitly declare that this is your intention
        // by calling this method and setting the `opt_out_of_secret_key` configuration to
        // `true` (by default, it is set to `false`); otherwise hashing will return an error
        // when you fail to provide a secret key

    let hash = hasher
        .with_password("P@ssw0rd")
        .with_salt("somesalt")
        .hash()
        .unwrap();
        // 👆 Note: We are able to hash witout a secret key because we explicitly
        // set `opt_out_of_secret_key` to `true` above

    assert_eq!(
        &hash,
        "$argon2id$v=19$m=4096,t=192,p=2$c29tZXNhbHQ$sw41ZsxebJmOJ6vSHe6BGQ",
    );
}
```
## Installation

<b>argonautica</b> should be relatively straightforward to include in your Rust project:
* Place `extern crate argonautica;` in your code (typically in either `lib.rs` or `main.rs`)
* In the `[dependencies]` section of your `Cargo.toml`, place ...
    * ... if you're building for your own machine ...
        * `argonautica = { version = "0.1.0", features = ["simd"] }`, or
        * `argonautica = { version = "0.1.0", features = ["serde", "simd"] }`
    * ... if you're building for a different machine ...
        * `argonautica = "0.1.0"`, or
        * `argonautica = { version = "0.1.0", features = ["serde"] }`

That said, <b>argonautica</b> uses [cc](https://github.com/alexcrichton/cc-rs) and
[bindgen](https://github.com/rust-lang-nursery/rust-bindgen) to compile the cannonical
[C implemenation](https://github.com/P-H-C/phc-winner-argon2) of Argon2 into a
static archive during the build process. This means you need a C compiler on your
machine in order to build <b>argonautica</b>. More specifically, you need:
* [LLVM/Clang](https://llvm.org/) (version 3.9 or higher)
    * Mac OS: `brew install llvm`, which requires [Homebrew](https://brew.sh/)
    * Debian-based linux: `apt-get install clang llvm-dev libclang-dev`
    * Arch linux: `pacman -S clang`
    * Windows: Download a pre-built binary [here](http://releases.llvm.org/download.html)

<b>argonautica</b> runs on stable Rust version 1.26.0 or greater.

## License

<b>argonautica</b> is licensed under either of:
* [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0), or
* [The MIT license](http://opensource.org/licenses/MIT)

at your option.
