89 lines
2.4 KiB
Rust
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()
|
|
}
|