use crate::aliases::{
Aes256Key32, Block16, EncryptedSessionBlock48, HmacSha256, Iv16, PasswordString,
};
use crate::constants::{PBKDF2_MAX_ITER, PBKDF2_MIN_ITER};
use crate::error::AescryptError;
use crate::kdf::pbkdf2::derive_pbkdf2_key;
use crate::utilities::xor_blocks;
use aes::cipher::BlockEncrypt;
use aes::{Aes256Enc, Block as AesBlock};
use hmac::Mac;
use secure_gate::{RevealSecret, RevealSecretMut};
#[inline]
pub fn derive_setup_key(
password: &PasswordString,
public_iv: &Iv16,
iterations: u32,
out_key: &mut Aes256Key32,
) -> Result<(), AescryptError> {
if !(PBKDF2_MIN_ITER..=PBKDF2_MAX_ITER).contains(&iterations) {
return Err(AescryptError::Header("invalid KDF iterations".into()));
}
derive_pbkdf2_key(password, public_iv, iterations, out_key)
}
#[inline]
pub fn encrypt_session_block(
cipher: &Aes256Enc,
session_iv: &Iv16,
session_key: &Aes256Key32,
public_iv: &Iv16,
enc_block: &mut EncryptedSessionBlock48,
hmac: &mut HmacSha256,
) -> Result<(), AescryptError> {
let mut prev_block = public_iv.with_secret(|iv| Block16::new(*iv));
let mut block = Block16::new([0u8; 16]);
session_iv.with_secret(|siv| {
prev_block.with_secret(|pb| block.with_secret_mut(|b| xor_blocks(siv, pb, b)))
});
let mut aes_block = block.with_secret(|b| AesBlock::from(*b));
cipher.encrypt_block(&mut aes_block);
enc_block.with_secret_mut(|eb| eb[0..16].copy_from_slice(aes_block.as_ref()));
hmac.update(aes_block.as_ref());
let temp_block = Block16::new(*aes_block.as_ref());
prev_block = temp_block;
session_key.with_secret(|sk| {
prev_block.with_secret(|pb| block.with_secret_mut(|b| xor_blocks(&sk[0..16], pb, b)))
});
aes_block = block.with_secret(|b| AesBlock::from(*b));
cipher.encrypt_block(&mut aes_block);
enc_block.with_secret_mut(|eb| eb[16..32].copy_from_slice(aes_block.as_ref()));
hmac.update(aes_block.as_ref());
let temp_block = Block16::new(*aes_block.as_ref());
prev_block = temp_block;
session_key.with_secret(|sk| {
prev_block.with_secret(|pb| block.with_secret_mut(|b| xor_blocks(&sk[16..32], pb, b)))
});
aes_block = block.with_secret(|b| AesBlock::from(*b));
cipher.encrypt_block(&mut aes_block);
enc_block.with_secret_mut(|eb| eb[32..48].copy_from_slice(aes_block.as_ref()));
hmac.update(aes_block.as_ref());
Ok(())
}