Initial commit
This commit is contained in:
commit
5304be3ee4
8 changed files with 1151 additions and 0 deletions
81
src/key.rs
Normal file
81
src/key.rs
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
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,
|
||||
}
|
||||
8
src/lib.rs
Normal file
8
src/lib.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#![cfg_attr(not(test), no_std)]
|
||||
|
||||
mod key;
|
||||
|
||||
pub use key::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
13
src/tests.rs
Normal file
13
src/tests.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
use crate::*;
|
||||
|
||||
#[test]
|
||||
fn test_measure_rounds() {
|
||||
let rounds = KeyDescription::measure_rounds(500, || {
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_millis() as u64
|
||||
});
|
||||
|
||||
println!("{rounds}");
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue