1use hmac::{Hmac, KeyInit as _, Mac as _};2use sha2::Sha256;34type HmacSha256 = Hmac<Sha256>;56pub const NAMING_SECRET_SIZE: usize = 32;78#[derive(Clone)]9pub struct NamingSecret(pub [u8; NAMING_SECRET_SIZE]);1011fn derive(secret: &NamingSecret, parts: &[&[u8]]) -> [u8; 32] {12 let mut mac = HmacSha256::new_from_slice(&secret.0).expect("any key size is valid");13 for part in parts {14 mac.update(&u64::to_be_bytes(part.len() as u64));15 mac.update(part);16 }17 mac.finalize().into_bytes().into()18}1920pub fn file_key(secret: &NamingSecret, nar_hash: &str) -> [u8; 32] {21 derive(secret, &[b"fleet-usb.v1.key\0", nar_hash.as_bytes()])22}2324pub fn chunk_name(secret: &NamingSecret, nar_hash: &str, index: u32, count: u32) -> String {25 let h = derive(26 secret,27 &[28 b"fleet-usb.v1.name\0",29 nar_hash.as_bytes(),30 &index.to_le_bytes(),31 &count.to_le_bytes(),32 ],33 );34 hex::encode(&h[..16])35}3637pub fn is_data_name(name: &str) -> bool {38 name.len() == 3239 && name40 .bytes()41 .all(|b| b.is_ascii_hexdigit() && !b.is_ascii_uppercase())42}