use crate::binary;
use aes::Aes256;
use cipher::generic_array::GenericArray;
use cipher::BlockEncryptMut;
use hmac::digest::CtOutput;
use hmac::{Hmac, Mac};
use sha2::{Digest, Sha256, Sha512};
use std::string::ToString;
use thiserror::Error;
type HmacSha256 = Hmac<Sha256>;
pub struct CompositeKey {
pw: Option<String>,
keyfile: Option<Vec<u8>>,
}
impl CompositeKey {
pub fn new(pw: Option<String>, keyfile: Option<Vec<u8>>) -> CompositeKey {
CompositeKey { pw, keyfile }
}
pub fn from_password(pw: &str) -> CompositeKey {
CompositeKey::new(Some(pw.into()), None)
}
pub(crate) fn composed(&self) -> ComposedKey {
let mut buffer = Vec::new();
if let Some(ref pw) = self.pw {
buffer.extend(Sha256::digest(pw.as_bytes()))
}
if let Some(ref keyfile) = self.keyfile {
buffer.extend(Sha256::digest(keyfile))
}
ComposedKey(Sha256::digest(&buffer).iter().cloned().collect())
}
}
#[derive(Debug)]
pub struct ComposedKey(Vec<u8>);
impl ComposedKey {
pub fn master_key(
&self,
kdf_options: &binary::KdfParams,
) -> Result<MasterKey, KeyGenerationError> {
match kdf_options {
binary::KdfParams::Argon2 {
variant,
memory_bytes,
version,
iterations,
lanes,
salt,
} => {
let config = argon2::Config {
variant: *variant,
version: argon2::Version::from_u32(*version)
.map_err(|e| KeyGenerationError::KeyGeneration(e.to_string()))?,
lanes: *lanes,
mem_cost: (memory_bytes / 1024) as u32,
time_cost: *iterations as u32,
..Default::default()
};
let hash = argon2::hash_raw(&self.0, salt, &config)
.map_err(|e| KeyGenerationError::KeyGeneration(e.to_string()))?;
Ok(MasterKey(hash))
}
binary::KdfParams::Aes { rounds, salt } => {
use cipher::KeyInit;
let mut cipher = Aes256::new_from_slice(salt).unwrap();
let chunked: Vec<GenericArray<u8, _>> = self
.0
.chunks_exact(16)
.map(|chunk| *GenericArray::from_slice(chunk))
.collect();
let mut blocks = [chunked[0], chunked[1]];
for _ in 0..*rounds {
cipher.encrypt_blocks_mut(&mut blocks);
}
let mut transformed_hasher = Sha256::new();
transformed_hasher.update(blocks[0]);
transformed_hasher.update(blocks[1]);
let transformed = transformed_hasher.finalize().to_vec();
Ok(MasterKey(transformed))
}
_ => Ok(MasterKey(Vec::new())),
}
}
}
#[derive(Debug)]
pub struct MasterKey(Vec<u8>);
impl MasterKey {
pub(crate) fn hmac_key(&self, seed: &[u8]) -> HmacKey {
let mut data_to_hash = Vec::new();
data_to_hash.extend(seed.iter());
data_to_hash.extend(self.0.iter());
data_to_hash.push(1);
HmacKey(Sha512::digest(&data_to_hash).iter().cloned().collect())
}
pub(crate) fn cipher_key(&self, seed: &[u8]) -> CipherKey {
let mut data_to_hash = Vec::new();
data_to_hash.extend(seed.iter());
data_to_hash.extend(self.0.iter());
CipherKey(Sha256::digest(&data_to_hash).iter().cloned().collect())
}
}
pub(crate) struct CipherKey(pub(crate) Vec<u8>);
pub(crate) struct HmacKey(Vec<u8>);
impl HmacKey {
pub(crate) fn block_key(&self, block_idx: u64) -> HmacBlockKey {
let mut block_key_hash = Sha512::new();
block_key_hash.update(block_idx.to_le_bytes());
block_key_hash.update(&*self.0);
HmacBlockKey(block_idx, block_key_hash.finalize().to_vec())
}
}
pub(crate) struct HmacBlockKey(u64, Vec<u8>);
impl HmacBlockKey {
pub(crate) fn verify_data_block(&self, hmac: &[u8], data: &[u8]) -> bool {
let mut calc_hmac = HmacSha256::new_from_slice(&self.1).unwrap();
calc_hmac.update(&self.0.to_le_bytes());
calc_hmac.update(&(data.len() as u32).to_le_bytes());
calc_hmac.update(data);
calc_hmac.verify_slice(hmac).is_ok()
}
pub(crate) fn calculate_data_hmac(
&self,
data: &[u8],
) -> Result<CtOutput<HmacSha256>, cipher::InvalidLength> {
let mut calc_hmac: HmacSha256 = HmacSha256::new_from_slice(&self.1).unwrap();
calc_hmac.update(&self.0.to_le_bytes());
calc_hmac.update(&(data.len() as u32).to_le_bytes());
calc_hmac.update(data);
Ok(calc_hmac.finalize())
}
pub(crate) fn calculate_header_hmac(
&self,
data: &[u8],
) -> Result<CtOutput<HmacSha256>, cipher::InvalidLength> {
let mut calc_hmac = HmacSha256::new_from_slice(&self.1)?;
calc_hmac.update(data);
Ok(calc_hmac.finalize())
}
pub(crate) fn verify_header_block(&self, hmac: &[u8], data: &[u8]) -> bool {
let mut calc_hmac = HmacSha256::new_from_slice(&self.1).unwrap();
calc_hmac.update(data);
calc_hmac.verify_slice(hmac).is_ok()
}
}
pub(crate) fn verify_sha256(data: &[u8], expected_sha: &[u8]) -> bool {
expected_sha == &*Sha256::digest(data)
}
pub(crate) fn sha256(data: &[u8]) -> Vec<u8> {
Sha256::digest(data).as_slice().to_vec()
}
#[derive(Debug, Error)]
pub enum KeyGenerationError {
#[error("Could not generate key: {0}")]
KeyGeneration(String),
#[error("Generation for KDF Options: {0:?} not implemented")]
UnimplementedKdfOptions(binary::KdfParams),
}