#![feature(allocator_api)] use std::{ alloc::Global, ffi::CString, io::{Write, stdin}, iter::zip, str::FromStr, }; use itertools::Itertools; use password_hash::derive_encryption_key; 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 mut lines = stdin().lines(); let username = read_line!(lines, "username"); let secret = read_line!(lines, "secret"); let user_key = unsafe { &*spectre_api_sys::spectre_user_key( username.as_ptr(), secret.as_ptr(), SpectreAlgorithm::Current, ) }; let salt = username.as_bytes(); // TODO: Derive the same salt that spectre passes to scrypt. let encryption_key = derive_encryption_key(salt, secret.as_bytes(), Global); let mut encrypted_user_key = encryption_key; assert_eq!(encrypted_user_key.len(), user_key.bytes.len()); for (dst_byte, user_byte) in zip(&mut encrypted_user_key, &user_key.bytes) { *dst_byte ^= *user_byte; } println!( "\nEncrypted User Key:\n{:02x}", encrypted_user_key.iter().format("") ); }