use std::cmp::Ordering;
use std::default::Default;
use config;
use primitives::Primitive;
mod de;
mod ser;
#[derive(Clone, Debug, PartialEq)]
pub enum Algorithm {
Single(Primitive),
Nested {
outer: Primitive,
inner: Box<Algorithm>,
},
}
#[derive(Debug)]
pub struct Output {
pub alg: Algorithm,
pub salt: Vec<u8>,
pub hash: Vec<u8>,
}
impl Default for Algorithm {
fn default() -> Self {
config::DEFAULT_ALG.clone()
}
}
impl Output {
pub fn verify(&self, password: &str) -> bool {
self.alg.verify(password.as_bytes(), &self.salt, &self.hash)
}
pub(crate) fn check_keys(&mut self, config: &config::Config) {
self.alg.update_key(config);
}
}
impl Algorithm {
pub fn hash(&self, password: &str) -> Output {
let salt = super::gen_salt(&*config::RANDOMNESS_SOURCE);
let output = self.hash_with_salt(password.as_bytes(), &salt);
Output {
hash: output,
salt,
alg: self.clone(),
}
}
pub fn hash_with_salt(&self, password: &[u8], salt: &[u8]) -> Vec<u8> {
match *self {
Algorithm::Single(ref p) => p.compute(password, salt),
Algorithm::Nested {
ref inner,
ref outer,
} => {
let innerput = inner.hash_with_salt(password, salt);
outer.compute(&innerput, salt)
}
}
}
pub fn verify(&self, password: &[u8], salt: &[u8], hash: &[u8]) -> bool {
match *self {
Algorithm::Single(ref p) => p.verify(password, salt, hash),
Algorithm::Nested {
ref inner,
ref outer,
} => {
let innerput = inner.hash_with_salt(password, salt);
outer.verify(&innerput, salt, hash)
}
}
}
pub fn needs_migrating(&self, prim: &Primitive) -> bool {
match *self {
Algorithm::Single(ref a2) |
Algorithm::Nested { outer: ref a2, .. } => {
!matches!(a2.partial_cmp(prim), Some(Ordering::Greater) | Some(Ordering::Equal))
}
}
}
pub fn to_wrapped(&self, outer: Primitive) -> Self {
Algorithm::Nested {
outer,
inner: Box::new(self.clone()),
}
}
pub fn into_wrapped(self, outer: Primitive) -> Self {
Algorithm::Nested {
outer,
inner: Box::new(self),
}
}
pub(crate) fn update_key(&mut self, config: &config::Config) {
match *self {
Algorithm::Single(ref mut p) => {
if let Some(newp) = p.update_key(config) {
*p = newp;
}
}
Algorithm::Nested {
ref mut inner,
ref mut outer,
} => {
inner.update_key(config);
if let Some(newp) = outer.update_key(config) {
*outer = newp;
}
}
}
}
}
#[cfg(test)]
mod test {
use super::*;
use serde_mcf;
#[test]
fn test_hash() {
let alg = Algorithm::default();
let output = alg.hash(&"hunter2");
println!("{:?}", serde_mcf::to_string(&output).unwrap());
}
#[test]
fn test_wrapped() {
let alg = Algorithm::default();
let prim = &*config::DEFAULT_PRIM;
let _alg1 = alg.to_wrapped(prim.clone());
let _alg = alg.into_wrapped(prim.clone());
}
}