use flamberge_crypto::{aes, kdf};
use super::{decode_b64, HEADER_STRIP_LEN};
use crate::{KeyError, Result};
pub fn pack_entropy(
serial: u32,
vendor: [u8; 12],
signature: [u8; 3],
username: &[u8],
) -> [u8; 32] {
let mut out = [0u8; 32];
out[0..4].copy_from_slice(&serial.to_be_bytes());
out[4..16].copy_from_slice(&vendor);
out[16..19].copy_from_slice(&signature);
let user_len = username.len().min(13);
out[19..19 + user_len].copy_from_slice(&username[..user_len]);
out
}
pub fn decrypt_private_license_key(keykey: &[u8], b64: &str) -> Result<Vec<u8>> {
if keykey.len() != 16 {
return Err(KeyError::Invalid(format!(
"ADEPT keykey must be 16 bytes, got {}",
keykey.len()
)));
}
let wrapped = decode_b64(b64)?;
let decrypted = aes::cbc_decrypt(keykey, &[0u8; 16], &wrapped)?;
let unpadded = kdf::pkcs7_unpad(&decrypted, 16)?;
if unpadded.len() <= HEADER_STRIP_LEN {
return Err(KeyError::Invalid(format!(
"decrypted privateLicenseKey too short: {} bytes",
unpadded.len()
)));
}
Ok(unpadded[HEADER_STRIP_LEN..].to_vec())
}
#[cfg(test)]
mod tests {
use super::*;
use base64::Engine;
#[test]
fn pack_entropy_matches_struct_pack_layout() {
let entropy = pack_entropy(0x0102_0304, *b"GenuineIntel", [0x00, 0x06, 0xf2], b"alice");
let mut expected = Vec::new();
expected.extend_from_slice(&[0x01, 0x02, 0x03, 0x04]);
expected.extend_from_slice(b"GenuineIntel");
expected.extend_from_slice(&[0x00, 0x06, 0xf2]);
expected.extend_from_slice(b"alice");
expected.extend_from_slice(&[0u8; 8]); assert_eq!(&entropy[..], &expected[..]);
assert_eq!(entropy.len(), 32);
}
#[test]
fn pack_entropy_truncates_long_username() {
let entropy = pack_entropy(0, [0; 12], [0; 3], b"an-overly-long-username");
assert_eq!(&entropy[19..32], b"an-overly-lon");
}
#[test]
fn decrypt_round_trips_a_wrapped_key() {
let keykey = [0x11u8; 16];
let der = [0xABu8; 40];
let mut plain = vec![0x5Au8; HEADER_STRIP_LEN];
plain.extend_from_slice(&der);
let pad = 16 - (plain.len() % 16);
plain.extend(std::iter::repeat_n(pad as u8, pad));
let ct = aes::cbc_encrypt(&keykey, &[0u8; 16], &plain).unwrap();
let b64 = base64::engine::general_purpose::STANDARD.encode(&ct);
assert_eq!(decrypt_private_license_key(&keykey, &b64).unwrap(), der);
}
#[test]
fn decrypt_rejects_wrong_key_length() {
assert!(decrypt_private_license_key(&[0u8; 8], "AAAA").is_err());
}
}