Skip to main content

Argon2

Struct Argon2 

Source
pub struct Argon2 { /* private fields */ }
Expand description

A configured Argon2 hasher.

Bundles the algorithm, version and validated Params. The secret (key) and associated data are passed per call rather than stored, which keeps Argon2 free of lifetime parameters.

§Examples

use argon2_rust::{Algorithm, Argon2, Params, Version};

// m=19456 KiB, t=2, 1 lane, 32-byte tag: `Params::default()`, which is
// what a password store should start from. About 8 ms per hash in release,
// so this runs as a real doctest rather than only being compiled.
let params = Params::default();
let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);
let mut tag = [0u8; 32];
argon2.hash_into(b"password", b"somesalt", &mut tag)?;
assert_eq!(argon2.verify(b"password", b"somesalt", &tag), Ok(()));

§Two spellings

Three entry points carry a password-flavoured alias, and only three: Argon2::hash_password_into for Argon2::hash_into, Argon2::hash_password for Argon2::hash_encoded, and Argon2::verify_password for Argon2::verify_encoded. Each of those three is a pure delegation, same function and same bytes.

Six other entry points have a base name and nothing else: Argon2::hash, Argon2::verify, Argon2::hash_into_with_ad, Argon2::verify_encoded_with_ad, Argon2::verify_encoded_bounded and Argon2::verify_encoded_bounded_with_ad. One runs the other way: Argon2::hash_password_with_random_salt has a password name with no base twin, and it is not a delegation either. It draws a fresh salt from the OS before calling Argon2::hash_encoded, so two calls with one password do not return the same string.

Where the alias does exist, the two families do not spell the output format the same way:

                     raw -> caller buffer   raw -> Vec   PHC -> String
  base:              hash_into              hash         hash_encoded
  password:          hash_password_into     (none)       hash_password
                                  ^ raw                  ^ PHC

Argon2::hash_password_into writes a raw tag into out, byte for byte what Argon2::hash_into writes. Argon2::hash_password returns a PHC string, character for character what Argon2::hash_encoded returns. The only difference between those two names is _into, which reads as a destination and not as a format; in the base family the word encoded carries that distinction in the name, and in the password family nothing does. Verification is the same shape: Argon2::verify_password takes a PHC string, like Argon2::verify_encoded, not the raw expected tag that Argon2::verify takes.

There is no raw-Vec password spelling, which is the empty cell above; for that shape the only name is Argon2::hash.

use argon2_rust::{Algorithm, Argon2, Params, Version, params::Memory};

let params = Params::builder().memory(Memory::kib(1 << 8)).passes(1).build()?;
let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);

// `_into` picks the destination, and with it the raw format.
let mut raw = [0u8; 32];
argon2.hash_password_into(b"password", b"somesalt", &mut raw)?;

// No suffix at all, and the format changes to PHC.
let phc = argon2.hash_password(b"password", b"somesalt")?;
assert!(phc.starts_with("$argon2id$v=19$m=256,t=1,p=1$c29tZXNhbHQ$"));

// One tag underneath both: `raw` is the bytes the string base64s.
assert_eq!(argon2.hash(b"password", b"somesalt")?, raw);

Implementations§

Source§

impl Argon2

Source

pub const fn new( algorithm: Algorithm, version: Version, params: Params, ) -> Argon2

Build a hasher. params is already validated, so this cannot fail.

Source

pub const fn algorithm(&self) -> Algorithm

The configured algorithm.

Source

pub const fn version(&self) -> Version

The configured version.

Source

pub const fn params(&self) -> &Params

The configured parameters.

Source

pub fn hasher(&self) -> Hasher

A Hasher: this configuration plus scratch memory it keeps between calls.

Allocates nothing — the first hash allocates the arena, and every hash after that reuses it. Use this when one thread hashes repeatedly; keep using Argon2::hash_into and friends when it does not.

use argon2_rust::{Algorithm, Argon2, Params, Version, params::Memory};

let params = Params::builder().memory(Memory::kib(8)).passes(1).build()?;
let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);

let mut hasher = argon2.hasher();
let mut tag = [0u8; 32];
for salt in [&b"somesalt"[..], &b"othersaltx"[..]] {
    hasher.hash_into(b"password", salt, &mut tag)?;
}

// Same answer as the one-shot API, every time.
let mut once = [0u8; 32];
argon2.hash_into(b"password", b"somesalt", &mut once)?;
hasher.hash_into(b"password", b"somesalt", &mut tag)?;
assert_eq!(tag, once);
Source

pub fn hash_into( &self, pwd: &[u8], salt: &[u8], out: &mut [u8], ) -> Result<(), Error>

Derive a tag into out.

out.len() must equal Params::tag_len_bytes.

use argon2_rust::{Algorithm, Argon2, Error, Params, Version, params::Memory};

let params = Params::builder().memory(Memory::kib(64)).passes(1).build()?;
let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);

let mut tag = [0u8; 32];
argon2.hash_into(b"password", b"somesalt", &mut tag)?;

// Those 32 bytes are what the PHC string base64s, so pinning the string
// pins the tag without spelling out an array of hex.
assert_eq!(
    argon2.hash_encoded(b"password", b"somesalt")?,
    "$argon2id$v=19$m=64,t=1,p=1$c29tZXNhbHQ$cpx6VEQbwTVZvcpxNIxOVUWZ5xnAipUmAe1cg2GMG70",
);

// `out.len()` is checked against `Params::tag_len_bytes`, never used to
// size the tag: a buffer of the wrong length is an error, not a
// truncated hash.
let mut too_short = [0u8; 16];
assert_eq!(
    argon2.hash_into(b"password", b"somesalt", &mut too_short),
    Err(Error::OutPtrMismatch),
);
§Errors

Whatever Params::validate_for returns, Error::OutPtrMismatch if out.len() disagrees with params.tag_len_bytes(), or Error::MemoryAllocationError.

Source

pub fn hash_into_with_ad( &self, pwd: &[u8], salt: &[u8], secret: &[u8], ad: &[u8], out: &mut [u8], ) -> Result<(), Error>

Derive a tag into out, with a secret key and associated data.

For a C-style PHC string of a peppered tag, see Argon2::hash_encoded_with_ad.

§Errors

As Argon2::hash_into.

Source

pub fn hash(&self, pwd: &[u8], salt: &[u8]) -> Result<Vec<u8>, Error>

Derive a tag of Params::tag_len_bytes bytes.

use argon2_rust::{Algorithm, Argon2, Params, Version, params::Memory};

let params = Params::builder().memory(Memory::kib(64)).passes(1).build()?;
let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);

// The `Vec` is sized from the parameters, so there is no buffer to get
// wrong and no `Error::OutPtrMismatch` to handle.
let tag = argon2.hash(b"password", b"somesalt")?;
assert_eq!(tag.len(), argon2.params().tag_len_bytes());

// Byte for byte what `hash_into` writes into a buffer you own; this is
// the same function with the allocation moved inside.
let mut into = [0u8; 32];
argon2.hash_into(b"password", b"somesalt", &mut into)?;
assert_eq!(tag, into);
§Errors

As Argon2::hash_into.

Source

pub fn hash_with_ad( &self, pwd: &[u8], salt: &[u8], secret: &[u8], ad: &[u8], ) -> Result<Vec<u8>, Error>

Argon2::hash with a secret key and associated data.

§Errors

As Argon2::hash_into.

Source

pub fn hash_encoded(&self, pwd: &[u8], salt: &[u8]) -> Result<String, Error>

Derive a tag and format it as a PHC string.

Always emits $v=, exactly as encode_string() in the C does, even for Version::V0x10.

§Secret and associated data

This method never takes a secret (pepper) or ad, matching argon2_hash() (argon2.h:322): the C hardcodes context.secret = NULL; context.ad = NULL (argon2.c:139-142) and encode_string emits only $type$v=$m=,t=,p=$salt$hash.

Argon2::hash_encoded_with_ad hashes with a pepper and/or associated data, then emits that same C-style string — it does not write a data= field. The tag is peppered; the string is indistinguishable from an unpeppered one. Argon2::verify_encoded on it answers Error::VerifyMismatch rather than any “missing pepper” signal; use Argon2::verify_encoded_with_ad with the same secret and ad.

Foreign producers (@phc/format, node-argon2) may put associated data in a data= parameter and may write m, t, p in any order. Those strings are what crate::decode_phc reads. crate::decode_string stays C-strict ($m=,t=,p= only, no data=).

§Errors

As Argon2::hash_into, plus Error::EncodingFail.

Source

pub fn hash_encoded_with_ad( &self, pwd: &[u8], salt: &[u8], secret: &[u8], ad: &[u8], ) -> Result<String, Error>

Derive a peppered tag and format it as a C-style PHC string.

The secret and associated data feed the tag the same way Argon2::hash_into_with_ad does. They are not written into the string: encode_string has no field for either, so the result looks like any other $type$v=$m=,t=,p=$salt$hash record. Bindings that must interoperate with node-argon2 data= strings should hash here and verify through crate::decode_phc.

use argon2_rust::{Algorithm, Argon2, Params, Version, params::Memory};

let params = Params::builder().memory(Memory::kib(64)).passes(1).build()?;
let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);
let encoded = argon2.hash_encoded_with_ad(
    b"password",
    b"somesalt",
    b"pepper",
    b"ad",
)?;
assert!(encoded.starts_with("$argon2id$v=19$m=64,t=1,p=1$c29tZXNhbHQ$"));
assert!(!encoded.contains("data="));
assert_eq!(
    Argon2::verify_encoded_with_ad(
        &encoded,
        b"password",
        b"pepper",
        b"ad",
        Algorithm::Argon2id,
    ),
    Ok(()),
);
§Errors

As Argon2::hash_into, plus Error::EncodingFail.

Source

pub fn verify( &self, pwd: &[u8], salt: &[u8], expected: &[u8], ) -> Result<(), Error>

Recompute the tag and compare it with expected in constant time.

A length mismatch is a Error::VerifyMismatch, not a separate error: the C cannot reach that case, because decode_string sets context->outlen from the tag it just decoded.

use argon2_rust::{Algorithm, Argon2, Error, Params, Version, params::Memory};

let params = Params::builder().memory(Memory::kib(64)).passes(1).build()?;
let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);

// A raw tag stored earlier, alongside the salt that produced it. The
// parameters are yours to remember too, which is what the PHC string
// from `hash_encoded` saves you.
let expected = argon2.hash(b"password", b"somesalt")?;
assert_eq!(argon2.verify(b"password", b"somesalt", &expected), Ok(()));

// Wrong password.
assert_eq!(
    argon2.verify(b"wrong", b"somesalt", &expected),
    Err(Error::VerifyMismatch),
);
// Wrong salt: the tag is a function of both.
assert_eq!(
    argon2.verify(b"password", b"othersalt", &expected),
    Err(Error::VerifyMismatch),
);
// A truncated `expected` is that same error and not a length error,
// exactly as the paragraph above says.
assert_eq!(
    argon2.verify(b"password", b"somesalt", &expected[..16]),
    Err(Error::VerifyMismatch),
);
§Errors

As Argon2::hash_into, or Error::VerifyMismatch.

Source

pub fn verify_with_ad( &self, pwd: &[u8], salt: &[u8], secret: &[u8], ad: &[u8], expected: &[u8], ) -> Result<(), Error>

Argon2::verify with a secret key and associated data.

§Errors

As Argon2::hash_into, or Error::VerifyMismatch.

Source

pub fn verify_encoded( encoded: &str, pwd: &[u8], algorithm: Algorithm, ) -> Result<(), Error>

argon2_verify(): decode a PHC string and check pwd against it.

§Errors

Error::DecodingFail for a malformed string, Error::VerifyMismatch if the password is wrong, or any hashing error.

Source

pub fn verify_encoded_with_ad( encoded: &str, pwd: &[u8], secret: &[u8], ad: &[u8], algorithm: Algorithm, ) -> Result<(), Error>

argon2_verify_ctx(): decode a PHC string and check pwd against it, with a secret key and associated data.

§Errors

As Argon2::verify_encoded, plus the secret/ad validation errors of Argon2::hash_into_with_ad.

Source

pub fn hash_password_into( &self, pwd: &[u8], salt: &[u8], out: &mut [u8], ) -> Result<(), Error>

Derive a raw tag into out, not a PHC string.

argon2_hash() with hash != NULL (argon2.c:160). The same function as Argon2::hash_into: _into picks the destination, and the format that comes with it is bytes. out.len() must equal Params::tag_len_bytes. For the PHC string, Argon2::hash_password.

§Errors

As Argon2::hash_into.

Source

pub fn hash_password(&self, pwd: &[u8], salt: &[u8]) -> Result<String, Error>

Derive a tag and return the PHC string for it, not the raw bytes.

argon2_hash() with encoded != NULL (argon2.c:165). The same function as Argon2::hash_encoded; for the raw tag, its sibling Argon2::hash_password_into or Argon2::hash.

Always emits $v=, just like encode_string() in the C, even for Version::V0x10 — the v=0x10 reference strings in src/test.c predate that field, so they have no $v= and are one field shorter than what this returns. Both forms decode, see Argon2::verify_password.

§Errors

As Argon2::hash_into, plus Error::EncodingFail.

Source

pub fn hash_password_with_random_salt( &self, pwd: &[u8], ) -> Result<String, Error>

Derive a PHC string with a fresh salt from the OS entropy source.

Convenience for the common case where the caller does not manage its own salt. The salt is RANDOM_SALT_LEN bytes — the length RFC 9106 §4 recommends — and lands in the returned string, so verification needs nothing else kept alongside it.

The randomness comes straight from the OS, with the entry point chosen per platform (getrandom(2), getentropy, CCRandomGenerateBytes, ProcessPrng, WASI random_get, or /dev/urandom) and declared by hand, so this costs the crate no dependency. Callers who already run their own CSPRNG should keep passing their own salt to Argon2::hash_encoded.

Hashing many passwords? Hasher::hash_password_with_random_salt does this over a pooled arena.

§Errors

Error::OsRandom if every OS entropy source for this platform fails, plus the errors of Argon2::hash_encoded.

Source

pub fn verify_password( encoded: &str, pwd: &[u8], algorithm: Algorithm, ) -> Result<(), Error>

Check pwd against a PHC string, not against a raw tag.

argon2_verify() (argon2.c:249): decode encoded, then recompute and compare. The same function as Argon2::verify_encoded. The parameters come out of the string, so nothing on self is consulted, which is why this is an associated function. To check a raw expected tag with these parameters instead, Argon2::verify.

§Errors

Error::DecodingFail for a malformed string, Error::VerifyMismatch if the password is wrong, or any hashing error.

Source

pub fn verify_encoded_bounded( encoded: &str, pwd: &[u8], algorithm: Algorithm, ceiling: &Params, ) -> Result<(), Error>

Argon2::verify_encoded, refusing costs above ceiling before allocating anything.

§Why this exists

m_cost in a PHC string is up to ten decimal digits, and the decoder accepts everything the C accepts — up to MAX_MEMORY KiB, which is 4 TiB. Nothing in Argon2::verify_encoded sits between that number and the allocation, because nothing does in argon2_verify either; on a login endpoint, where the string is whatever a database row (or a request) contained, that is a one-line denial of service. t_cost is the same story in CPU time rather than bytes.

The plain entry points keep exact C parity and are the right choice when the string is trusted — a config file, a fixture, your own output. This one is for when it is not.

use argon2_rust::{Algorithm, Argon2, Params, Version, params::Memory};

let hostile = "$argon2id$v=19$m=4294967295,t=1,p=1$c29tZXNhbHQ$\
               CTFhFdXPJO1aFaMaO6Mm5c8y7cJHAph8ArZWb2GRPPc";
// 64 MiB, 8 passes, 4 lanes is far more than any sane stored hash.
let ceiling = Params::builder().memory(Memory::mib(64)).passes(8).lanes(4).build()?;

let err = Argon2::verify_encoded_bounded(
    hostile, b"password", Algorithm::Argon2id, &ceiling,
).unwrap_err();
// Rejected on the parameters, without ever asking for 4 TiB.
assert_eq!(err, argon2_rust::Error::MemoryTooMuch);
§What is bounded

Both the cost and the allocation. The length of encoded is checked against the longest string ceiling could have produced — with BOUNDED_MAX_SALT_LEN allowed for the salt — before the decoder runs, because the decoder sizes its salt and tag buffers from the input. Then the decoded parameters are held to all four of the ceiling’s numbers.

§Worker threads

ceiling.threads() bounds them, and it is a fifth, independent knob — none of the four checks above implies it. Decoding sets threads = lanes (C parity), so the string’s own p would otherwise choose how many OS threads this call spawns. A ceiling that leaves ParamsBuilder::threads unset has threads == lanes and so bounds them together; set it to allow wide strings without spawning wide:

use argon2_rust::{Params, params::Memory};
// Accept up to 256 lanes, but never run more than 2 workers.
let ceiling = Params::builder()
    .memory(Memory::mib(64))
    .passes(8)
    .lanes(256)
    .threads(2)
    .build()?;

Clamping is always safe: threads is a scheduling knob that cannot change the tag — only lanes can — so a bounded verify accepts exactly the same strings whatever the budget.

§Errors

The errors of Argon2::verify_encoded, plus — checked in this order, and reusing the C’s own codes rather than inventing new ones — Error::DecodingLengthFail if encoded is longer than ceiling could have produced, Error::OutputTooLong if the decoded tag is longer than ceiling.tag_len_bytes(), Error::MemoryTooMuch if the decoded m_cost exceeds ceiling.memory_kib(), Error::TimeTooLarge if t_cost exceeds ceiling.passes(), and Error::LanesTooMany if lanes exceeds ceiling.lanes().

Source

pub fn verify_encoded_bounded_with_ad( encoded: &str, pwd: &[u8], secret: &[u8], ad: &[u8], algorithm: Algorithm, ceiling: &Params, ) -> Result<(), Error>

Argon2::verify_encoded_with_ad with the cost ceiling of Argon2::verify_encoded_bounded.

A keyed deployment is more likely to be the one parsing untrusted strings, not less, so the bounded form exists for both.

§Errors

As Argon2::verify_encoded_bounded, plus the secret/ad validation errors of Argon2::hash_into_with_ad.

Trait Implementations§

Source§

impl Clone for Argon2

Source§

fn clone(&self) -> Argon2

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for Argon2

Source§

impl Debug for Argon2

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for Argon2

Source§

impl PartialEq for Argon2

Source§

fn eq(&self, other: &Argon2) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Argon2

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.