#![doc = include_str!("../README.md")]
pub mod wrap;
pub use argon2::Error;
pub use secrecy::zeroize::Zeroizing;
pub use secrecy::{ExposeSecret, Secret, SecretBytesMut};
use argon2::Argon2;
use rand::prelude::*;
use secrecy::{CloneableSecret, DebugSecret, Zeroize};
use std::ops::Deref;
use std::ops::DerefMut;
pub struct Input {
passphrase: Secret<Vec<u8>>,
salt: Secret<Vec<u8>>,
}
impl Input {
pub fn new(pwd: impl AsRef<[u8]>, salt: impl AsRef<[u8]>) -> Self {
Self {
passphrase: Secret::new(pwd.as_ref().to_vec()),
salt: Secret::new(salt.as_ref().to_vec()),
}
}
pub fn derive_key(&self) -> Result<SecretSeed, Error> {
let mut output_key_material = [0u8; 32]; Argon2::default().hash_password_into(
self.passphrase.expose_secret(),
self.salt.expose_secret(),
&mut output_key_material,
)?;
Ok(SecretSeed::new(Seed(output_key_material.into())))
}
}
pub fn derive_key(pwd: impl AsRef<[u8]>, salt: impl AsRef<[u8]>) -> Result<SecretSeed, Error> {
let mut output_key_material = [0u8; 32]; Argon2::default().hash_password_into(pwd.as_ref(), salt.as_ref(), &mut output_key_material)?;
Ok(SecretSeed::new(Seed(output_key_material.into())))
}
pub fn rand_seed() -> Secret<Seed> {
let mut rng = rand::thread_rng();
let mut output_key_material = Zeroizing::new([0u8; 32]); rng.fill_bytes(&mut *output_key_material);
SecretSeed::new(Seed(Zeroizing::new(*output_key_material)))
}
#[derive(Clone, Default, Debug, PartialEq)]
pub struct Seed(Zeroizing<[u8; 32]>);
impl Seed {
pub fn new(seed: Zeroizing<[u8; 32]>) -> Self {
Self(seed)
}
}
impl Zeroize for Seed {
fn zeroize(&mut self) {
self.0.zeroize();
}
}
impl CloneableSecret for Seed {}
impl DebugSecret for Seed {}
pub type SecretSeed = Secret<Seed>;
impl Deref for Seed {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&*self.0
}
}
impl DerefMut for Seed {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut *self.0
}
}
impl AsRef<[u8]> for Seed {
fn as_ref(&self) -> &[u8] {
&*self.0
}
}
impl AsRef<[u8; 32]> for Seed {
fn as_ref(&self) -> &[u8; 32] {
&self.0
}
}
impl PartialEq<Seed> for [u8] {
fn eq(&self, other: &Seed) -> bool {
self[..] == other[..]
}
}
impl PartialEq<Seed> for [u8; 32] {
fn eq(&self, other: &Seed) -> bool {
self[..] == other[..]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() -> Result<(), Error> {
let salt = b"some@email.com"; let password = b"some random words that you made up, for sure!";
let mut output_key_material_1 = [0u8; 32]; let mut output_key_material_2 = Seed::default(); let mut output_key_material_3: Vec<u8> = vec![0; 48]; Argon2::default().hash_password_into(password, salt, &mut output_key_material_1)?;
Argon2::default().hash_password_into(password, salt, &mut output_key_material_2)?;
Argon2::default().hash_password_into(password, salt, &mut output_key_material_3)?;
assert_eq!(output_key_material_1, output_key_material_2);
output_key_material_1.zeroize();
output_key_material_2.zeroize();
Ok(())
}
#[test]
fn api_works() -> Result<(), Error> {
let password = "some random words that you made up, for sure!".to_string();
let salt = b"some@email.com"; let input = Input::new(&password, salt);
let seed = input.derive_key()?;
assert_eq!(
**seed.expose_secret(),
[
164, 103, 254, 113, 126, 241, 57, 240, 100, 56, 243, 125, 155, 224, 40, 242, 178,
136, 222, 133, 220, 141, 127, 10, 88, 199, 181, 11, 241, 91, 149, 249
]
);
println!("Seed {:?}", seed);
let seed = derive_key(password, salt)?;
assert_eq!(
**seed.expose_secret(),
[
164, 103, 254, 113, 126, 241, 57, 240, 100, 56, 243, 125, 155, 224, 40, 242, 178,
136, 222, 133, 220, 141, 127, 10, 88, 199, 181, 11, 241, 91, 149, 249
]
);
Ok(())
}
#[test]
fn rand_seed_works() -> Result<(), Error> {
let seed = rand_seed();
assert_eq!(seed.expose_secret().len(), 32);
Ok(())
}
}