use crate::config::Config;
use crate::context::Context;
use crate::core;
use crate::encoding;
use crate::memory::Memory;
use crate::result::Result;
use crate::variant::Variant;
use crate::version::Version;
use constant_time_eq::constant_time_eq;
#[rustfmt::skip]
pub fn encoded_len(
variant: Variant,
mem_cost: u32,
time_cost: u32,
parallelism: u32,
salt_len: u32,
hash_len: u32
) -> u32 {
("$$v=$m=,t=,p=$$".len() as u32) +
(variant.as_lowercase_str().len() as u32) +
encoding::num_len(Version::default().as_u32()) +
encoding::num_len(mem_cost) +
encoding::num_len(time_cost) +
encoding::num_len(parallelism) +
encoding::base64_len(salt_len) +
encoding::base64_len(hash_len)
}
pub fn hash_encoded(pwd: &[u8], salt: &[u8], config: &Config) -> Result<String> {
let context = Context::new(config.clone(), pwd, salt)?;
let hash = run(&context);
let encoded = encoding::encode_string(&context, &hash);
Ok(encoded)
}
pub fn hash_raw(pwd: &[u8], salt: &[u8], config: &Config) -> Result<Vec<u8>> {
let context = Context::new(config.clone(), pwd, salt)?;
let hash = run(&context);
Ok(hash)
}
pub fn verify_encoded(encoded: &str, pwd: &[u8]) -> Result<bool> {
verify_encoded_ext(encoded, pwd, &[], &[])
}
pub fn verify_encoded_ext(encoded: &str, pwd: &[u8], secret: &[u8], ad: &[u8]) -> Result<bool> {
let decoded = encoding::decode_string(encoded)?;
let config = Config {
variant: decoded.variant,
version: decoded.version,
mem_cost: decoded.mem_cost,
time_cost: decoded.time_cost,
lanes: decoded.parallelism,
secret,
ad,
hash_length: decoded.hash.len() as u32,
};
verify_raw(pwd, &decoded.salt, &decoded.hash, &config)
}
pub fn verify_raw(pwd: &[u8], salt: &[u8], hash: &[u8], config: &Config) -> Result<bool> {
let config = Config {
hash_length: hash.len() as u32,
..config.clone()
};
let context = Context::new(config, pwd, salt)?;
let calculated_hash = run(&context);
Ok(constant_time_eq(hash, &calculated_hash))
}
fn run(context: &Context) -> Vec<u8> {
let mut memory = Memory::new(context.config.lanes, context.lane_length);
core::initialize(context, &mut memory);
core::fill_memory_blocks(context, &mut memory);
core::finalize(context, &memory)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn single_thread_verification_multi_lane_hash() {
let hash = "$argon2i$v=19$m=4096,t=3,p=4$YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo$BvBk2OaSofBHfbrUW61nHrWB/43xgfs/QJJ5DkMAd8I";
verify_encoded(hash, b"foo").unwrap();
}
}