use super::PasswordError;
use crate::aes;
use crate::ffi;
use rtoolbox::safe_string::SafeString;
use rtoolbox::safe_vec::SafeVec;
use serde::{Deserialize, Serialize};
use serde_json;
use serde_json::Error;
use sha2::{Digest, Sha256};
use std::ops::Deref;
const IV_LEN: usize = 16;
#[derive(Serialize, Deserialize)]
pub struct Schema {
passwords: Vec<Password>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Password {
pub name: String,
pub domain: Option<String>,
pub username: String,
pub password: SafeString,
pub created_at: ffi::time_t,
pub updated_at: ffi::time_t,
}
fn generate_encryption_key(master_password: &str) -> SafeVec {
let mut hasher = Sha256::new();
hasher.update(master_password.as_bytes());
let result = hasher.finalize();
SafeVec::new(result.deref().to_vec())
}
pub fn get_all_passwords(
master_password: &str,
encrypted: &[u8],
) -> Result<Vec<Password>, PasswordError> {
let passwords: Vec<Password> = if !encrypted.is_empty() {
let iv = &encrypted[encrypted.len() - IV_LEN..];
let key = generate_encryption_key(master_password);
let encrypted = &encrypted[..encrypted.len() - IV_LEN];
let decrypted_maybe = aes::decrypt(encrypted, key.deref(), iv);
match decrypted_maybe {
Ok(decrypted) => {
let encoded = SafeString::from_string(
String::from_utf8_lossy(decrypted.deref()).into_owned(),
);
let s: Result<Schema, Error> = serde_json::from_str(encoded.deref());
match s {
Ok(schema) => schema.passwords,
Err(_) => {
return Err(PasswordError::InvalidJson);
}
}
}
Err(_) => {
return Err(PasswordError::Decryption);
}
}
} else {
Vec::new()
};
Ok(passwords)
}
#[cfg(test)]
mod test {
use super::generate_encryption_key;
use std::ops::Deref;
#[test]
fn test_generate_encryption_key_is_256_bits() {
assert_eq!(generate_encryption_key("test").deref().len(), 256 / 8);
}
}