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 ^ PHCArgon2::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
impl Argon2
Sourcepub const fn new(
algorithm: Algorithm,
version: Version,
params: Params,
) -> Argon2
pub const fn new( algorithm: Algorithm, version: Version, params: Params, ) -> Argon2
Build a hasher. params is already validated, so this cannot fail.
Sourcepub fn hasher(&self) -> Hasher
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);Sourcepub fn hash_into(
&self,
pwd: &[u8],
salt: &[u8],
out: &mut [u8],
) -> Result<(), Error>
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.
Sourcepub fn hash_into_with_ad(
&self,
pwd: &[u8],
salt: &[u8],
secret: &[u8],
ad: &[u8],
out: &mut [u8],
) -> Result<(), Error>
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
Sourcepub fn hash(&self, pwd: &[u8], salt: &[u8]) -> Result<Vec<u8>, Error>
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
Sourcepub fn hash_with_ad(
&self,
pwd: &[u8],
salt: &[u8],
secret: &[u8],
ad: &[u8],
) -> Result<Vec<u8>, Error>
pub fn hash_with_ad( &self, pwd: &[u8], salt: &[u8], secret: &[u8], ad: &[u8], ) -> Result<Vec<u8>, Error>
Sourcepub fn hash_encoded(&self, pwd: &[u8], salt: &[u8]) -> Result<String, Error>
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.
Sourcepub fn hash_encoded_with_ad(
&self,
pwd: &[u8],
salt: &[u8],
secret: &[u8],
ad: &[u8],
) -> Result<String, Error>
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.
Sourcepub fn verify(
&self,
pwd: &[u8],
salt: &[u8],
expected: &[u8],
) -> Result<(), Error>
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
Sourcepub fn verify_with_ad(
&self,
pwd: &[u8],
salt: &[u8],
secret: &[u8],
ad: &[u8],
expected: &[u8],
) -> Result<(), Error>
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
Sourcepub fn verify_encoded(
encoded: &str,
pwd: &[u8],
algorithm: Algorithm,
) -> Result<(), Error>
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.
Sourcepub fn verify_encoded_with_ad(
encoded: &str,
pwd: &[u8],
secret: &[u8],
ad: &[u8],
algorithm: Algorithm,
) -> Result<(), Error>
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.
Sourcepub fn hash_password_into(
&self,
pwd: &[u8],
salt: &[u8],
out: &mut [u8],
) -> Result<(), Error>
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
Sourcepub fn hash_password(&self, pwd: &[u8], salt: &[u8]) -> Result<String, Error>
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.
Sourcepub fn hash_password_with_random_salt(
&self,
pwd: &[u8],
) -> Result<String, Error>
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.
Sourcepub fn verify_password(
encoded: &str,
pwd: &[u8],
algorithm: Algorithm,
) -> Result<(), Error>
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.
Sourcepub fn verify_encoded_bounded(
encoded: &str,
pwd: &[u8],
algorithm: Algorithm,
ceiling: &Params,
) -> Result<(), Error>
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().
Sourcepub fn verify_encoded_bounded_with_ad(
encoded: &str,
pwd: &[u8],
secret: &[u8],
ad: &[u8],
algorithm: Algorithm,
ceiling: &Params,
) -> Result<(), Error>
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.