use super::{Header, KeystoreFile};
use crate::{
KdfParams,
crypto::{SALT_LEN, algorithm::Algorithm},
format::{MAGIC_LEN, VER_LEN},
};
use anyhow::{Result, bail};
pub const VERSION_V1: u8 = 1;
const MEM_LEN: usize = 4;
const TIME_LEN: usize = 4;
const PAR_LEN: usize = 4;
const NONCE_LEN: usize = crate::crypto::chacha20poly1305::NONCE_LEN;
const HEADER_LEN: usize = MAGIC_LEN + VER_LEN + MEM_LEN + TIME_LEN + PAR_LEN + SALT_LEN + NONCE_LEN;
pub fn parse(data: &[u8]) -> Result<KeystoreFile> {
if data.len() < HEADER_LEN {
bail!("file too short for v1");
}
let mut offset = MAGIC_LEN + VER_LEN;
let mem_cost = u32::from_le_bytes(data[offset..offset + MEM_LEN].try_into()?);
offset += MEM_LEN;
let time_cost = u32::from_le_bytes(data[offset..offset + TIME_LEN].try_into()?);
offset += TIME_LEN;
let parallelism = u32::from_le_bytes(data[offset..offset + PAR_LEN].try_into()?);
offset += PAR_LEN;
let salt = data[offset..offset + SALT_LEN].to_vec();
offset += SALT_LEN;
let nonce = data[offset..offset + NONCE_LEN].to_vec();
offset += NONCE_LEN;
let ciphertext: Vec<u8> = data[offset..].to_vec();
let kdf = KdfParams::new(mem_cost, time_cost, parallelism)?;
let header = Header::new(kdf, Algorithm::XChaCha20Poly1305, salt, nonce);
Ok(KeystoreFile::new(header, ciphertext))
}
#[cfg(test)]
mod tests {
#[test]
fn v1_parse_valid_data() {
let mut data = vec![0u8; 61];
data[..4].copy_from_slice(b"KNST"); data[4] = 1; let _result = super::parse(&data);
}
#[test]
fn header_too_short_fails() {
let data = vec![0u8; 10];
assert!(super::parse(&data).is_err());
}
}