82 lines
2.1 KiB
Rust
82 lines
2.1 KiB
Rust
use chacha20poly1305::{aead::heapless::Vec, AeadInPlace, KeyInit};
|
|
use zeroize::{Zeroize, ZeroizeOnDrop};
|
|
|
|
const KEY_SIZE: usize = 32;
|
|
const PBKDF_SALT_SIZE: usize = 32;
|
|
const CHACHA_SALT_SIZE: usize = 12;
|
|
|
|
pub struct KeyDescription {
|
|
encrypted_key: [u8; KEY_SIZE],
|
|
pbkdf_salt: [u8; PBKDF_SALT_SIZE],
|
|
nonce: [u8; CHACHA_SALT_SIZE],
|
|
pbkdf_rounds: u32,
|
|
}
|
|
|
|
#[derive(Zeroize, ZeroizeOnDrop)]
|
|
pub struct Key {
|
|
key: [u8; KEY_SIZE],
|
|
}
|
|
|
|
impl KeyDescription {
|
|
/// Measure the number of rounds to match the target time (in milliseconds)
|
|
/// `now` should return a timestamp in milliseconds
|
|
pub fn measure_rounds<F: Fn() -> u64>(target_time: u64, now: F) -> u32 {
|
|
let mut key = [0; KEY_SIZE];
|
|
let mut memory = [0; KEY_SIZE];
|
|
let salt = core::hint::black_box([0; PBKDF_SALT_SIZE]);
|
|
let passphrase = core::hint::black_box([0]);
|
|
|
|
let start_1 = (now)();
|
|
bcrypt_pbkdf::bcrypt_pbkdf_with_memory(passphrase, &salt, 1, &mut key, &mut memory)
|
|
.unwrap();
|
|
let end_1 = (now)();
|
|
let duration_1 = end_1 - start_1;
|
|
|
|
key = [0; KEY_SIZE];
|
|
memory = [0; KEY_SIZE];
|
|
|
|
let start_2 = (now)();
|
|
bcrypt_pbkdf::bcrypt_pbkdf_with_memory(passphrase, &salt, 17, &mut key, &mut memory)
|
|
.unwrap();
|
|
let end_2 = (now)();
|
|
let duration_2 = end_2 - start_2;
|
|
|
|
assert!(duration_2 > duration_1);
|
|
|
|
(target_time * 16 / (duration_2 - duration_1)) as u32
|
|
}
|
|
|
|
pub fn get_key(&self, passphrase: &mut [u8]) -> Result<Key, Error> {
|
|
let mut derived_key = [0; KEY_SIZE];
|
|
|
|
let mut memory = [0; KEY_SIZE];
|
|
bcrypt_pbkdf::bcrypt_pbkdf_with_memory(
|
|
&*passphrase,
|
|
&self.pbkdf_salt,
|
|
self.pbkdf_rounds,
|
|
&mut derived_key,
|
|
&mut memory,
|
|
)
|
|
.map_err(Error::Pbkdf)?;
|
|
|
|
passphrase.zeroize();
|
|
|
|
let mut key = Vec::<u8, KEY_SIZE>::from_slice(&self.encrypted_key)
|
|
.map_err(|_| Error::WrongKeySize)?;
|
|
let cipher = chacha20poly1305::ChaCha20Poly1305::new(&derived_key.into());
|
|
cipher
|
|
.decrypt_in_place(&self.nonce.into(), &[], &mut key)
|
|
.map_err(Error::Chacha)?;
|
|
|
|
Ok(Key {
|
|
key: key.into_array().map_err(|_| Error::WrongKeySize)?,
|
|
})
|
|
}
|
|
}
|
|
|
|
pub enum Error {
|
|
Chacha(chacha20poly1305::Error),
|
|
Pbkdf(bcrypt_pbkdf::Error),
|
|
WrongKeySize,
|
|
}
|