use super::funejson::Value; use super::crypto_pbkdf2_sha256::pbkdf2_sha256; use super::encoding_base64_base64_encode::base64_encode; /// A password as pbkdf2_sha256$$$, the salt and the /// 32-byte PBKDF2-HMAC-SHA256 key in standard base64. The salt is passed in /// because a capability may not read randomness: generate 16 or more fresh /// random bytes for every call. /// /// # Panics /// Panics on a salt under 16 bytes, a value outside 0-255, or fewer than /// 1000 iterations. pub fn hash_password(password: &str, salt: &[i64], iterations: i64) -> String { if salt.len() < 16 { panic!("salt must be at least 16 bytes, received {}", salt.len()); } if iterations < 1000 { panic!("iterations must be a whole number of at least 1000"); } let bytes: Vec = password.bytes().map(|b| b as i64).collect(); let derived = pbkdf2_sha256(&bytes, salt, iterations, 32); format!("pbkdf2_sha256${}${}${}", iterations, base64_encode(salt), base64_encode(&derived)) } pub fn fune_vector(args: &[Value]) -> Value { let password = match &args[0] { Value::Str(s) => s.as_str(), _ => panic!("password must be a string"), }; let salt: Vec = match &args[1] { Value::Arr(items) => items .iter() .map(|item| match item { Value::Int(i) => *i, _ => panic!("salt must be a list of integers from 0 to 255"), }) .collect(), _ => panic!("salt must be a list of integers from 0 to 255"), }; let iterations = match &args[2] { Value::Int(i) => *i, _ => panic!("iterations must be a whole number of at least 1000"), }; Value::str(&hash_password(password, &salt, iterations)) }