use super::*;
pub(crate) fn process_security_answers(
mut a1: sodoken::LockedArray,
mut a2: sodoken::LockedArray,
mut a3: sodoken::LockedArray,
) -> Result<sodoken::LockedArray, OneErr> {
let a1 = a1.lock();
let a2 = a2.lock();
let a3 = a3.lock();
let a1 = std::str::from_utf8(&a1).map_err(OneErr::new)?;
let a2 = std::str::from_utf8(&a2).map_err(OneErr::new)?;
let a3 = std::str::from_utf8(&a3).map_err(OneErr::new)?;
let a1 = a1.trim();
let a2 = a2.trim();
let a3 = a3.trim();
let a1 = a1.as_bytes();
let a2 = a2.as_bytes();
let a3 = a3.as_bytes();
let mut out = sodoken::LockedArray::new(a1.len() + a2.len() + a3.len())?;
{
let mut lock = out.lock();
(&mut *lock)[0..a1.len()].copy_from_slice(a1);
(&mut *lock)[a1.len()..a1.len() + a2.len()].copy_from_slice(a2);
(&mut *lock)[a1.len() + a2.len()..a1.len() + a2.len() + a3.len()]
.copy_from_slice(a3);
let out_str = std::str::from_utf8_mut(&mut lock).unwrap();
out_str.make_ascii_lowercase();
}
Ok(out)
}
pub(crate) async fn pw_enc(
seed: SharedSizedLockedArray<32>,
passphrase: SharedLockedArray,
limits: PwHashLimits,
) -> Result<
(
[u8; sodoken::argon2::ARGON2_ID_SALTBYTES],
[u8; 24],
[u8; 49],
),
OneErr,
> {
let mut pw_hash = sodoken::SizedLockedArray::<64>::new()?;
sodoken::blake2b::blake2b_hash(
pw_hash.lock().as_mut_slice(),
&passphrase.lock().unwrap().lock(),
None,
)?;
let ops_limit = limits.as_ops_limit();
let mem_limit = limits.as_mem_limit();
let (salt, mut secret) = tokio::task::spawn_blocking({
move || -> Result<_, OneErr> {
let mut salt = [0; sodoken::argon2::ARGON2_ID_SALTBYTES];
sodoken::random::randombytes_buf(&mut salt)?;
let mut secret = sodoken::SizedLockedArray::new()?;
sodoken::argon2::blocking_argon2id(
&mut *secret.lock(),
&*pw_hash.lock(),
&salt,
ops_limit,
mem_limit,
)?;
Ok((salt, secret))
}
})
.await
.map_err(OneErr::new)??;
let mut enc = sodoken::secretstream::State::default();
let mut header = [0; sodoken::secretstream::HEADERBYTES];
sodoken::secretstream::init_push(&mut enc, &mut header, &secret.lock())?;
let mut cipher = [0; 49];
sodoken::secretstream::push(
&mut enc,
&mut cipher,
&*seed.lock().unwrap().lock(),
None,
sodoken::secretstream::Tag::Final,
)?;
Ok((salt, header, cipher))
}
pub(crate) async fn pw_dec(
passphrase: SharedLockedArray,
salt: U8Array<{ sodoken::argon2::ARGON2_ID_SALTBYTES }>,
mem_limit: u32,
ops_limit: u32,
header: U8Array<24>,
cipher: U8Array<49>,
) -> Result<sodoken::SizedLockedArray<32>, OneErr> {
let mut pw_hash = sodoken::SizedLockedArray::<64>::new()?;
sodoken::blake2b::blake2b_hash(
pw_hash.lock().as_mut_slice(),
&passphrase.lock().unwrap().lock(),
None,
)?;
let mut secret = tokio::task::spawn_blocking({
move || -> Result<_, OneErr> {
let mut secret = sodoken::SizedLockedArray::new()?;
sodoken::argon2::blocking_argon2id(
&mut *secret.lock(),
&*pw_hash.lock(),
&salt,
ops_limit,
mem_limit,
)?;
Ok(secret)
}
})
.await
.map_err(OneErr::new)??;
let mut dec = sodoken::secretstream::State::default();
sodoken::secretstream::init_pull(&mut dec, &header.0, &secret.lock())?;
let mut seed = sodoken::SizedLockedArray::new()?;
let tag = sodoken::secretstream::pull(
&mut dec,
&mut *seed.lock(),
&cipher.0,
None,
)?;
if tag != sodoken::secretstream::Tag::Final {
return Err(OneErr::new("secretstream pull did not return final tag"));
}
Ok(seed)
}