pub use self::native::Bcrypt;
mod native {
extern crate bcrypt;
use self::bcrypt::bcrypt;
use primitives::{Primitive, PrimitiveImpl};
use sod::Sod;
use serde_mcf::Hashes;
use std::fmt;
use std::sync::Arc;
#[derive(Clone, Deserialize, Serialize)]
pub struct Bcrypt {
cost: u32,
}
lazy_static! {
static ref DEFAULT: Arc<dyn PrimitiveImpl> = Arc::new(Bcrypt::new_impl(12));
}
impl PrimitiveImpl for Bcrypt {
fn compute<'a>(&'a self, password: &[u8], salt: &[u8]) -> Vec<u8> {
let mut hash = [0_u8; 24];
let mut pw = [0_u8; 72];
let pw = if password.len() > 71 {
pw[..72].copy_from_slice(&password[..72]);
&pw[..]
} else {
pw[..password.len()].copy_from_slice(password);
&pw[..password.len() + 1]
};
bcrypt(self.cost, salt, pw, &mut hash);
hash[..23].to_vec()
}
fn params_as_vec(&self) -> Vec<(&'static str, String)> {
vec![("cost", self.cost.to_string())]
}
fn hash_id(&self) -> Hashes {
Hashes::BcryptMcf
}
}
impl fmt::Debug for Bcrypt {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "Bcrypt, cost: {:?}", self.cost)
}
}
impl Bcrypt {
#[allow(clippy::new_ret_no_self)]
pub fn new(cost: u32) -> Primitive {
Self::new_impl(cost).into()
}
fn new_impl(cost: u32) -> Self {
Self { cost }
}
pub fn default() -> Primitive {
Primitive(Sod::Dynamic(Arc::clone(&DEFAULT)))
}
}
}
benches!(Bcrypt);
#[cfg(test)]
mod bcrypt_test {
use hashing::*;
use serde_mcf as mcf;
#[test]
fn sanity_check() {
let password = "hunter2";
let params = super::Bcrypt::default();
println!("{:?}", params);
let salt = ::get_salt();
let hash = params.compute(password.as_bytes(), &salt);
let hash2 = params.compute(password.as_bytes(), &salt);
assert_eq!(hash, hash2);
let out = Output {
alg: Algorithm::Single(params),
salt,
hash,
};
println!("{:?}", mcf::to_string(&out).unwrap());
}
#[test]
fn verifies_bcrypt_hashes() {
let password = "hunter2";
let hash = "$2a$10$ckjEeyTD6estWyoofn4EROM9Ik2PqVcfcrepX.uGp6.aqRdCMN/Oe";
assert!(::verify_password(&hash, password));
}
fn openwall_test(hash: &str, password: &[u8]) {
let pwd_hash: Output = mcf::from_str(&hash).unwrap();
assert_eq!(
pwd_hash.hash,
pwd_hash.alg.hash_with_salt(password, &pwd_hash.salt)
);
}
#[test]
fn openwall_test_vectors() {
openwall_test(
"$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW",
b"U*U",
);
openwall_test(
"$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK",
b"U*U*",
);
openwall_test(
"$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a",
b"U*U*U",
);
openwall_test(
"$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy",
b"",
);
openwall_test(
"$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui",
b"0123456789abcdefghijklmnopqrstuvwxyz\
ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\
chars after 72 are ignored",
);
openwall_test(
"$2y$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
b"\xa3",
);
openwall_test(
"$2a$05$/OK.fbVrR/bpIqNJ5ianF.swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6",
b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\
\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\
\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\
\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\
\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\
\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\
chars after 72 are ignored as usual",
);
openwall_test(
"$2a$05$/OK.fbVrR/bpIqNJ5ianF.R9xrDjiycxMbQE2bp.vgqlYpW5wx2yy",
b"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\
\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\
\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\
\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\
\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\
\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55",
);
openwall_test(
"$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy",
b"",
);
openwall_test(
"$2a$05$/OK.fbVrR/bpIqNJ5ianF.9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe",
b"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\
\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\
\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\
\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\
\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\
\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff",
);
}
}