acid/firmware/password-hash/src/bin.rs
2026-01-22 22:57:43 +01:00

89 lines
2.4 KiB
Rust

#![feature(allocator_api)]
use std::{
alloc::Global,
ffi::{CStr, CString},
io::{Cursor, Write, stdin},
str::FromStr,
};
use byteorder::{BigEndian, WriteBytesExt};
use itertools::Itertools;
use password_hash::{Key, derive_encryption_key, encrypt_with};
use spectre_api_sys::SpectreAlgorithm;
macro_rules! read_line {
($lines:expr, $label:expr) => {{
print!("{}: ", $label);
std::io::stdout().flush().unwrap();
CString::from_str(
&$lines
.next()
.transpose()
.ok()
.flatten()
.unwrap_or_else(|| panic!("Expected {}.", $label)),
)
.unwrap()
}};
}
fn main() {
let print_secrets = std::env::args().contains("--print-secrets");
let mut lines = stdin().lines();
let username = read_line!(lines, "username");
let secret = read_line!(lines, "secret");
let user_key: Key = unsafe {
&*spectre_api_sys::spectre_user_key(
username.as_ptr(),
secret.as_ptr(),
SpectreAlgorithm::Current,
)
}
.bytes;
let user_key_id = unsafe { spectre_api_sys::spectre_id_buf(user_key.as_ptr(), user_key.len()) };
let salt = derive_user_key_salt(&username);
let encryption_key = derive_encryption_key(&salt, secret.as_bytes(), Global);
if print_secrets {
println!("\nUser Key (SECRET):\n{:02x}", user_key.iter().format(""));
println!(
"\nEncryption Key (SECRET):\n{:02x}",
encryption_key.iter().format("")
);
}
let mut encrypted_user_key = user_key;
encrypt_with(&mut encrypted_user_key, &encryption_key);
println!(
"\nUser Key ID:\n{:02x}",
user_key_id.bytes.iter().format("")
);
println!(
"\nEncrypted User Key:\n{:02x}",
encrypted_user_key.iter().format("")
);
}
// Copied from the body of the `spectre_user_key_v3` function.
fn derive_user_key_salt(username: &CStr) -> Vec<u8> {
use spectre_api_sys::*;
let mut salt = Cursor::new(Vec::new());
unsafe {
let key_scope: &'static CStr =
CStr::from_ptr(spectre_purpose_scope(SpectreKeyPurpose::Authentication));
salt.write_all(key_scope.to_bytes()).unwrap();
salt.write_u32::<BigEndian>(username.count_bytes() as u32)
.unwrap();
salt.write_all(username.to_bytes()).unwrap();
}
salt.into_inner()
}