use std::path::Path;
use crate::crypto::{AuthKey, create_local_key, decrypt_local};
use crate::qdatastream::QDataStream;
use crate::{Error, MAX_ACCOUNTS, Result};
use super::file_io::read_file;
#[derive(Debug)]
pub struct KeyData {
pub salt: Vec<u8>,
pub key_encrypted: Vec<u8>,
pub info_encrypted: Vec<u8>,
pub version: u32,
}
#[derive(Debug)]
pub struct KeyInfo {
pub local_key: AuthKey,
pub account_indices: Vec<i32>,
}
pub fn read_key_data(base_path: &Path, key_file: &str) -> Result<KeyData> {
let name = format!("key_{key_file}");
let file = read_file(&name, base_path)?;
let mut stream = QDataStream::new(&file.data);
let salt = stream.read_qbytearray()?;
let key_encrypted = stream.read_qbytearray()?;
let info_encrypted = stream.read_qbytearray()?;
Ok(KeyData { salt, key_encrypted, info_encrypted, version: file.version })
}
pub fn decrypt_key_data(key_data: &KeyData, passcode: &[u8]) -> Result<KeyInfo> {
let passcode_key = create_local_key(&key_data.salt, passcode);
let decrypted_key = decrypt_local(&key_data.key_encrypted, &passcode_key)?;
if decrypted_key.len() < 256 {
return Err(Error::invalid_format(format!(
"decrypted key too short: {} bytes",
decrypted_key.len()
)));
}
let local_key = AuthKey::from_bytes(&decrypted_key[..256])?;
let decrypted_info = decrypt_local(&key_data.info_encrypted, &local_key)?;
let mut info_stream = QDataStream::new(&decrypted_info);
let count = info_stream.read_i32()?;
if count <= 0 || count > MAX_ACCOUNTS as i32 {
return Err(Error::invalid_format(format!("invalid account count: {count}")));
}
let mut account_indices = Vec::with_capacity(count as usize);
for _ in 0..count {
let index = info_stream.read_i32()?;
if index >= 0 && index < MAX_ACCOUNTS as i32 {
account_indices.push(index);
}
}
Ok(KeyInfo { local_key, account_indices })
}