Files
unixtract/src/formats/pfl_upg/include.rs
T

79 lines
2.3 KiB
Rust
Raw Normal View History

2026-02-17 17:28:59 +01:00
use crate::utils::common;
2026-06-04 19:46:23 +08:00
use crate::utils::aes::decrypt_aes256_ecb;
2026-02-17 17:28:59 +01:00
use binrw::BinRead;
use crate::keys;
use rsa::{RsaPublicKey, BigUint};
2026-02-17 17:28:59 +01:00
pub fn try_find_key(sig: &[u8], ciphertext: &[u8]) -> Result<Option<(String, [u8; 32])>, Box<dyn std::error::Error>> {
let mut result: Option<(String, [u8; 32])> = None;
2026-02-17 17:28:59 +01:00
2026-06-04 19:46:23 +08:00
for (name, n_hex) in keys::PFLUPG {
let n = BigUint::from_bytes_be(&hex::decode(n_hex)?);
let e = BigUint::from_bytes_be(&hex::decode("010001")?);
let pubkey = RsaPublicKey::new(n, e)?;
let sig_int = BigUint::from_bytes_le(&sig);
let dec_int = rsa::hazmat::rsa_encrypt(&pubkey, &sig_int)?;
let dec_sig = dec_int.to_bytes_le();
2026-02-17 17:28:59 +01:00
2026-06-04 19:46:23 +08:00
let aes_key: [u8; 32] = dec_sig[20..52].try_into().unwrap();
let dec_ciphertext = decrypt_aes256_ecb(&aes_key, &ciphertext)?;
// Needs to start with null-terminated filename string
let end = match dec_ciphertext.iter().position(|&b| b == 0) {
Some(pos) => pos,
2026-06-04 19:46:23 +08:00
None => continue, // There is no 0, continue
};
let fname = &dec_ciphertext[..end];
2026-06-04 19:46:23 +08:00
if fname.len() > 1 && fname.is_ascii() { // Is ASCII filename
result = Some((name.to_string(), aes_key));
break
}
}
Ok(result)
}
2026-02-17 17:28:59 +01:00
#[derive(BinRead)]
pub struct Header {
_magic_bytes: [u8; 8],
pub header_size: u32, //data start
2026-02-17 17:28:59 +01:00
pub data_size: u32,
2026-06-05 21:02:40 +08:00
_crc32: u32,
pub mask: u32,
_data_size_decompressed: u32,
_padding2: u32,
description_bytes: [u8; 512],
2026-02-17 17:28:59 +01:00
}
impl Header {
pub fn description(&self) -> String {
common::string_from_bytes(&self.description_bytes).replace('\r', "\n")
}
pub fn is_encrypted(&self) -> bool {
(self.mask & 0x2000_0000) != 0
2026-02-17 17:28:59 +01:00
}
}
#[derive(BinRead)]
pub struct FileHeader {
file_name_bytes: [u8; 60],
pub real_size: u32,
2026-06-05 21:02:40 +08:00
pub stored_size: u32,
pub header_size: u32,
2026-02-17 17:28:59 +01:00
pub attributes: [u8; 4],
}
impl FileHeader {
pub fn file_name(&self) -> String {
common::string_from_bytes(&self.file_name_bytes)
}
pub fn is_folder(&self) -> bool {
(self.attributes[3] & (1 << 1)) != 0
}
pub fn has_extended_name(&self) -> bool {
(self.attributes[2] & (1 << 7)) != 0
}
pub fn is_package(&self) -> bool {
(self.attributes[3] & (1 << 2)) != 0
}
2026-06-04 19:46:23 +08:00
}