use std;
use std::io::{BufRead, Seek};
use std::str;
use aesni::Aes256;
use block_modes::block_padding::Pkcs7;
use block_modes::{BlockMode, Cbc};
use hmac::{Hmac, Mac};
use ring::pbkdf2;
use sha1::{Digest, Sha1};
use sha2::Sha256;
use crate::error::{Error, Result};
use crate::type_utils::ArqRead;
fn calculate_hmacsha256(secret: &[u8], message: &[u8]) -> Result<Vec<u8>> {
use hmac::NewMac;
let mut mac = Hmac::<Sha256>::new_varkey(secret)?;
mac.update(&message);
Ok(mac.finalize().into_bytes().to_vec())
}
pub fn calculate_sha1sum(message: &[u8]) -> Vec<u8> {
let mut sha = Sha1::new();
sha.update(message);
sha.finalize().to_vec()
}
pub trait Validation {
fn validate(&self, _: usize, _: &str);
}
pub type Header = Vec<u8>;
impl Validation for Header {
fn validate(&self, count: usize, content: &str) {
match str::from_utf8(&self[0..count]) {
Ok(header_str) => {
if header_str != content {
panic!("File contains wrong header: {}", header_str);
}
}
Err(err) => panic!("Couldn't convert to string ({})", err),
};
}
}
pub struct EncryptionDat {
header: Header,
salt: Vec<u8>,
hmac_sha256: Vec<u8>,
iv: Vec<u8>,
encryption_key: Vec<u8>,
pub master_keys: Vec<Vec<u8>>,
}
impl EncryptionDat {
fn parse_master_keys(master_keys: Vec<u8>) -> Vec<Vec<u8>> {
let master_key_1 = &master_keys[0..32];
let master_key_2 = &master_keys[32..64];
let master_key_3 = &master_keys[64..96];
vec![
master_key_1.to_vec(),
master_key_2.to_vec(),
master_key_3.to_vec(),
]
}
fn derive_encryption_key(password: &[u8], salt: &[u8], result: &mut [u8]) {
pbkdf2::derive(
pbkdf2::PBKDF2_HMAC_SHA1,
std::num::NonZeroU32::new(200_000).unwrap(), salt,
password,
result,
);
}
pub fn new<R: BufRead + Seek>(mut reader: R, password: &str) -> Result<EncryptionDat> {
let header = reader.read_bytes(12)?;
assert_eq!(header, [69, 78, 67, 82, 89, 80, 84, 73, 79, 78, 86, 50]);
let salt = reader.read_bytes(8)?;
let hmacsha256 = reader.read_bytes(32)?;
let iv = reader.read_bytes(16)?;
let mut encrypted_master_keys = reader.read_bytes(112)?;
let mut encryption_key: [u8; 64] = [0u8; 64];
Self::derive_encryption_key(password.as_bytes(), &salt[..], &mut encryption_key);
let iv_and_keys = [&iv[..], &encrypted_master_keys[..]].concat();
let calculated_hmacsha256 = calculate_hmacsha256(&encryption_key[32..64], &iv_and_keys)?;
if calculated_hmacsha256 != hmacsha256 {
return Err(Error::WrongPassword);
}
let mode = Cbc::<Aes256, Pkcs7>::new_var(&encryption_key[0..32], &iv[..])?;
mode.decrypt(&mut encrypted_master_keys)?;
Ok(EncryptionDat {
header: header.to_vec(),
salt: salt.to_vec(),
hmac_sha256: hmacsha256.to_vec(),
iv: iv.to_vec(),
encryption_key: encryption_key.to_vec(),
master_keys: Self::parse_master_keys(encrypted_master_keys),
})
}
}
pub struct EncryptedObject {
header: Header,
hmac_sha256: Vec<u8>, master_iv: Vec<u8>,
encrypted_data_iv_session: Vec<u8>,
ciphertext: Vec<u8>,
}
impl EncryptedObject {
pub fn new<R: ArqRead + BufRead>(mut reader: R) -> Result<EncryptedObject> {
let header = reader.read_bytes(4)?.to_vec();
assert_eq!(header, [65, 82, 81, 79]); let hmac_sha256 = reader.read_bytes(32)?.to_vec();
let master_iv = reader.read_bytes(16)?.to_vec();
let encrypted_data_iv_session = reader.read_bytes(64)?.to_vec();
let mut ciphertext: Vec<u8> = Vec::new();
reader.read_to_end(&mut ciphertext)?;
Ok(EncryptedObject {
header,
hmac_sha256,
master_iv,
encrypted_data_iv_session,
ciphertext,
})
}
pub fn validate(&self, master_key: &[u8]) -> Result<()> {
let mut master_iv_and_data = self.master_iv.clone();
master_iv_and_data.append(&mut self.encrypted_data_iv_session.clone());
master_iv_and_data.append(&mut self.ciphertext.clone());
let calculated_hmacsha256 = calculate_hmacsha256(&master_key, &master_iv_and_data)?;
assert_eq!(calculated_hmacsha256, self.hmac_sha256);
Ok(())
}
pub fn decrypt(&self, master_key: &[u8]) -> Result<Vec<u8>> {
let mut enc_data_iv_session = self.encrypted_data_iv_session.clone();
let master_iv = self.master_iv.clone();
let mode = Cbc::<Aes256, Pkcs7>::new_var(&master_key, &master_iv)?;
let data_iv_session = mode.decrypt(&mut enc_data_iv_session)?;
let data_iv = &data_iv_session[0..16];
let session_key = &data_iv_session[16..48];
let mut ciphertext = self.ciphertext.clone();
let session_mode = Cbc::<Aes256, Pkcs7>::new_var(&session_key, data_iv)?;
let content = session_mode.decrypt(&mut ciphertext)?;
Ok(content.to_owned())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_calculate_hmacsha256() {
let secret = "secret".as_bytes();
let message = "message".as_bytes();
let result = [
139, 95, 72, 112, 41, 149, 193, 89, 140, 87, 61, 177, 226, 24, 102, 169, 184, 37, 212,
167, 148, 209, 105, 215, 6, 10, 3, 96, 87, 150, 54, 11,
]
.to_vec();
assert_eq!(result, calculate_hmacsha256(&secret, &message).unwrap());
}
#[test]
fn test_calculate_sha1sum() {
let message = "message".as_bytes();
println!("{:#?}", calculate_sha1sum(&message));
assert_eq!(
hex!("6f9b9af3cd6e8b8a73c2cdced37fe9f59226e27d"),
calculate_sha1sum(&message)[..]
);
}
}