argon2/
argon2.rs

1// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use crate::config::Config;
10use crate::context::Context;
11use crate::core;
12use crate::encoding;
13use crate::memory::Memory;
14use crate::result::Result;
15use crate::variant::Variant;
16use crate::version::Version;
17
18use constant_time_eq::constant_time_eq;
19
20/// Returns the length of the encoded string.
21///
22/// # Remarks
23///
24/// The length is **one** less that the original C version, since no null
25/// terminator is used.
26///
27/// # Examples
28///
29/// ```rust
30/// use argon2::{self, Variant};
31///
32/// let variant = Variant::Argon2i;
33/// let mem = 4096;
34/// let time = 10;
35/// let parallelism = 10;
36/// let salt_len = 8;
37/// let hash_len = 32;
38/// let enc_len = argon2::encoded_len(variant, mem, time, parallelism, salt_len, hash_len);
39/// assert_eq!(enc_len, 86);
40/// ```
41#[rustfmt::skip]
42pub fn encoded_len(
43    variant: Variant,
44    mem_cost: u32,
45    time_cost: u32,
46    parallelism: u32,
47    salt_len: u32,
48    hash_len: u32
49) -> u32 {
50    ("$$v=$m=,t=,p=$$".len() as u32)  +
51    (variant.as_lowercase_str().len() as u32) +
52    encoding::num_len(Version::default().as_u32()) +
53    encoding::num_len(mem_cost) +
54    encoding::num_len(time_cost) +
55    encoding::num_len(parallelism) +
56    encoding::base64_len(salt_len) +
57    encoding::base64_len(hash_len)
58}
59
60/// Hashes the password and returns the encoded hash.
61///
62/// # Examples
63///
64/// Create an encoded hash with the default configuration:
65///
66/// ```
67/// use argon2::{self, Config};
68///
69/// let pwd = b"password";
70/// let salt = b"somesalt";
71/// let config = Config::default();
72/// let encoded = argon2::hash_encoded(pwd, salt, &config).unwrap();
73/// ```
74///
75///
76/// Create an Argon2d encoded hash with 4 lanes:
77///
78/// ```
79/// use argon2::{self, Config, Variant};
80///
81/// let pwd = b"password";
82/// let salt = b"somesalt";
83/// let mut config = Config::default();
84/// config.variant = Variant::Argon2d;
85/// config.lanes = 4;
86/// let encoded = argon2::hash_encoded(pwd, salt, &config).unwrap();
87/// ```
88pub fn hash_encoded(pwd: &[u8], salt: &[u8], config: &Config) -> Result<String> {
89    let context = Context::new(config.clone(), pwd, salt)?;
90    let hash = run(&context);
91    let encoded = encoding::encode_string(&context, &hash);
92    Ok(encoded)
93}
94
95/// Hashes the password and returns the hash as a vector.
96///
97/// # Examples
98///
99/// Create a hash with the default configuration:
100///
101/// ```
102/// use argon2::{self, Config};
103///
104/// let pwd = b"password";
105/// let salt = b"somesalt";
106/// let config = Config::default();
107/// let vec = argon2::hash_raw(pwd, salt, &config).unwrap();
108/// ```
109///
110///
111/// Create an Argon2d hash with 4 lanes:
112///
113/// ```
114/// use argon2::{self, Config, Variant};
115///
116/// let pwd = b"password";
117/// let salt = b"somesalt";
118/// let mut config = Config::default();
119/// config.variant = Variant::Argon2d;
120/// config.lanes = 4;
121/// let vec = argon2::hash_raw(pwd, salt, &config).unwrap();
122/// ```
123pub fn hash_raw(pwd: &[u8], salt: &[u8], config: &Config) -> Result<Vec<u8>> {
124    let context = Context::new(config.clone(), pwd, salt)?;
125    let hash = run(&context);
126    Ok(hash)
127}
128
129/// Verifies the password with the encoded hash.
130///
131/// # Examples
132///
133/// ```
134/// use argon2;
135///
136/// let enc = "$argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ\
137///            $iWh06vD8Fy27wf9npn6FXWiCX4K6pW6Ue1Bnzz07Z8A";
138/// let pwd = b"password";
139/// let res = argon2::verify_encoded(enc, pwd).unwrap();
140/// assert!(res);
141/// ```
142pub fn verify_encoded(encoded: &str, pwd: &[u8]) -> Result<bool> {
143    verify_encoded_ext(encoded, pwd, &[], &[])
144}
145
146/// Verifies the password with the encoded hash, secret and associated data.
147///
148/// # Examples
149///
150/// ```
151/// use argon2;
152///
153/// let enc = "$argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ\
154///            $OlcSvlN20Lz43sK3jhCJ9K04oejhiY0AmI+ck6nuETo";
155/// let pwd = b"password";
156/// let secret = b"secret";
157/// let ad = b"ad";
158/// let res = argon2::verify_encoded_ext(enc, pwd, secret, ad).unwrap();
159/// assert!(res);
160/// ```
161pub fn verify_encoded_ext(encoded: &str, pwd: &[u8], secret: &[u8], ad: &[u8]) -> Result<bool> {
162    let decoded = encoding::decode_string(encoded)?;
163    let config = Config {
164        variant: decoded.variant,
165        version: decoded.version,
166        mem_cost: decoded.mem_cost,
167        time_cost: decoded.time_cost,
168        lanes: decoded.parallelism,
169        secret,
170        ad,
171        hash_length: decoded.hash.len() as u32,
172    };
173    verify_raw(pwd, &decoded.salt, &decoded.hash, &config)
174}
175
176/// Verifies the password with the supplied configuration.
177///
178/// # Examples
179///
180///
181/// ```
182/// use argon2::{self, Config};
183///
184/// let pwd = b"password";
185/// let salt = b"somesalt";
186/// let hash = &[158, 135, 137, 200, 180, 40, 52, 34, 10, 252, 0, 8, 90, 199,
187///              58, 204, 48, 134, 81, 33, 105, 148, 171, 191, 221, 214, 155,
188///              37, 146, 3, 46, 253];
189/// let config = Config::rfc9106_low_mem();
190/// let res = argon2::verify_raw(pwd, salt, hash, &config).unwrap();
191/// assert!(res);
192/// ```
193pub fn verify_raw(pwd: &[u8], salt: &[u8], hash: &[u8], config: &Config) -> Result<bool> {
194    let config = Config {
195        hash_length: hash.len() as u32,
196        ..config.clone()
197    };
198    let context = Context::new(config, pwd, salt)?;
199    let calculated_hash = run(&context);
200    Ok(constant_time_eq(hash, &calculated_hash))
201}
202
203fn run(context: &Context) -> Vec<u8> {
204    let mut memory = Memory::new(context.config.lanes, context.lane_length);
205    core::initialize(context, &mut memory);
206    core::fill_memory_blocks(context, &mut memory);
207    core::finalize(context, &memory)
208}
209
210#[cfg(test)]
211mod tests {
212    use super::*;
213
214    #[test]
215    fn single_thread_verification_multi_lane_hash() {
216        let hash = "$argon2i$v=19$m=4096,t=3,p=4$YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo$BvBk2OaSofBHfbrUW61nHrWB/43xgfs/QJJ5DkMAd8I";
217        verify_encoded(hash, b"foo").unwrap();
218    }
219}