use openssl::symm::Cipher;
use url::Url;
use api::url::UrlBuilder;
use file::remote_file::RemoteFile;
use super::{b64, rand_bytes};
use super::hdkf::{derive_auth_key, derive_file_key, derive_meta_key};
const KEY_IV_LEN: usize = 12;
pub struct KeySet {
secret: Vec<u8>,
iv: [u8; KEY_IV_LEN],
file_key: Option<Vec<u8>>,
auth_key: Option<Vec<u8>>,
meta_key: Option<Vec<u8>>,
}
impl KeySet {
pub fn new(secret: Vec<u8>, iv: [u8; 12]) -> Self {
Self {
secret,
iv,
file_key: None,
auth_key: None,
meta_key: None,
}
}
pub fn from(file: &RemoteFile, password: Option<&String>) -> Self {
let mut set = Self::new(
file.secret_raw().clone(),
[0; 12],
);
set.derive();
if let Some(password) = password {
set.derive_auth_password(password, &UrlBuilder::download(&file, true));
}
set
}
pub fn generate(derive: bool) -> Self {
let mut secret = vec![0u8; 16];
let mut iv = [0u8; 12];
rand_bytes(&mut secret)
.expect("failed to generate crypto secure random secret");
rand_bytes(&mut iv)
.expect("failed to generate crypto secure random input vector");
let mut key = Self::new(secret, iv);
if derive {
key.derive();
}
key
}
pub fn derive(&mut self) {
self.file_key = Some(derive_file_key(&self.secret));
self.auth_key = Some(derive_auth_key(&self.secret, None, None));
self.meta_key = Some(derive_meta_key(&self.secret));
}
pub fn derive_auth_password(&mut self, pass: &str, url: &Url) {
self.auth_key = Some(derive_auth_key(
&self.secret,
Some(pass),
Some(url),
));
}
pub fn secret(&self) -> &[u8] {
&self.secret
}
pub fn secret_encoded(&self) -> String {
b64::encode(self.secret())
}
pub fn iv(&self) -> &[u8] {
&self.iv
}
pub fn set_iv(&mut self, iv: [u8; KEY_IV_LEN]) {
self.iv = iv;
}
pub fn file_key(&self) -> Option<&Vec<u8>> {
self.file_key.as_ref()
}
pub fn auth_key(&self) -> Option<&Vec<u8>> {
self.auth_key.as_ref()
}
pub fn auth_key_encoded(&self) -> Option<String> {
self.auth_key().map(|key| b64::encode(key))
}
pub fn meta_key(&self) -> Option<&Vec<u8>> {
self.meta_key.as_ref()
}
pub fn cipher() -> Cipher {
Cipher::aes_128_gcm()
}
}