Skip to content

Instantly share code, notes, and snippets.

@rgdmarshall
Last active February 21, 2022 00:58
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save rgdmarshall/ae3dc072445ed88b357a to your computer and use it in GitHub Desktop.
Save rgdmarshall/ae3dc072445ed88b357a to your computer and use it in GitHub Desktop.
extern crate crypto;
use crypto::bcrypt::bcrypt;
static CRYPT_B64: &'static str = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
fn crypt_decode(enc: &str, decbuf: &mut [u8]) -> Option<()> {
let mut cbuild = 0u8;
let mut cpos = 0;
let mut dec_idx = 0;
for b in enc.chars() {
if let Some(dec) = CRYPT_B64.find(b) {
if cpos == 0 {
cbuild = dec as u8;
} else {
cbuild <<= cpos;
cbuild |= dec as u8 >> 6 - cpos;
decbuf[dec_idx] = cbuild;
dec_idx += 1;
if dec_idx == decbuf.len() {
break;
}
cbuild = dec as u8 & (0x3F >> cpos);
}
cpos += 2;
if cpos > 6 {
cpos = 0;
}
} else {
return None;
}
}
Some(())
}
struct HashSetup {
cost: u32,
salt: String,
hash: String,
}
fn parse_hash(h: &str) -> Option<HashSetup> {
let mut i = 0;
let mut cost = None;
let mut salt = None;
let mut hash = None;
for component in h.split('$') {
match i {
0 => (),
1 => match component {
"2y" => (),
_ => { return None; }
},
2 => {
if let Ok(c) = component.parse::<u32>() {
cost = Some(c);
} else {
return None;
}
},
3 if component.len() == 53 => {
salt = Some(component[..22].chars().collect());
hash = Some(component[22..].chars().collect());
},
_ => { return None; }
}
i += 1;
}
if cost.is_none() || salt.is_none() || hash.is_none() {
return None;
}
Some(HashSetup {
cost: cost.unwrap(),
salt: salt.unwrap(),
hash: hash.unwrap()
})
}
fn nul_terminate(pw: &str) -> Vec<u8> {
let mut v: Vec<_> = pw.bytes().collect();
v.push(0);
v
}
fn check_pass<S: AsRef<str>>(pw: S, hash: S) -> bool {
if let Some(hs) = parse_hash(hash.as_ref()) {
let mut saltbuf = [0u8; 16];
if crypt_decode(&hs.salt, &mut saltbuf).is_none() {
return false;
}
let mut hashbuf = [0u8; 23];
if crypt_decode(&hs.hash, &mut hashbuf).is_none() {
return false;
}
let mut output = [0u8; 24];
bcrypt(hs.cost, &saltbuf, &nul_terminate(pw.as_ref())[..], &mut output);
return &output[..23] == hashbuf;
}
false
}
fn main() {
println!("{}", check_pass("password", "$2y$05$bvIG6Nmid91Mu9RcmmWZfO5HJIMCT8riNW0hEp8f6/FuA2/mHZFpe"));
println!("{}", check_pass("foo", "$2y$10$mKr5/591RHaLEy9BSfCOKuMCXg9jNUuWFvRNvbO6KkqGiCJh3rbe2"));
println!("{}", check_pass("U*U", "$2y$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW"));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment