pfl_upg: change key detection ope, add some sony keys, add extraction of nested UPG

This commit is contained in:
theubusu
2026-05-05 19:27:51 +02:00
parent 196662d218
commit f4345b75f1
4 changed files with 111 additions and 95 deletions
+37 -22
View File
@@ -2,29 +2,44 @@ use crate::utils::common;
use binrw::BinRead;
use aes::Aes256;
use ecb::{Decryptor, cipher::{BlockDecryptMut, KeyInit, generic_array::GenericArray}};
use crate::keys;
use rsa::{RsaPublicKey, BigUint};
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;
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();
let aes_key = &dec_sig[20..52];
let dec_ciphertext = decrypt_aes256_ecb(aes_key.try_into().unwrap(), &ciphertext)?;
//needs to start with null-termninated filename string
let end = match dec_ciphertext.iter().position(|&b| b == 0) {
Some(pos) => pos,
None => continue, //there is no 0, continue
};
let fname = &dec_ciphertext[..end];
if fname.is_ascii() { //is ascii filename
result = Some((name.to_string(), aes_key.try_into().unwrap()));
break
}
}
Ok(result)
}
pub static AUTO_FWS: &[(&str, &str)] = &[
("Q5551", "q5551"),
("Q5553", "q5551"),
("Q554E", "q5551"),
("Q554M", "q5551"),
("QF1EU", "qf1eu"),
("QF2EU", "qf1eu"),
("Q591E", "q591e"),
("Q522E", "q522e"),
("Q582E", "q522e"),
("Q5481", "q5481"),
("Q5431", "q5431"),
("Q5492", "q5492"),
("S5551", "q5551"), //Sharp
];
type Aes256EcbDec = Decryptor<Aes256>;
pub fn decrypt_aes256_ecb(key: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
let key_array: [u8; 32] = key.try_into()?;
let mut decryptor = Aes256EcbDec::new(&key_array.into());
pub fn decrypt_aes256_ecb(key: [u8; 32], ciphertext: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
let mut decryptor = Aes256EcbDec::new(&key.into());
let mut buffer = ciphertext.to_vec();
for chunk in buffer.chunks_exact_mut(16) {
@@ -38,7 +53,7 @@ pub fn decrypt_aes256_ecb(key: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>, Box<
#[derive(BinRead)]
pub struct Header {
_magic_bytes: [u8; 8],
pub header_size: u32,
pub header_size: u32, //data start
pub data_size: u32,
_crc32: u32,
pub mask: u32,
@@ -73,7 +88,7 @@ impl FileHeader {
pub fn has_extended_name(&self) -> bool {
(self.attributes[2] & (1 << 7)) != 0
}
pub fn _is_package(&self) -> bool {
(self.attributes[3] & (1 << 1)) != 0
pub fn is_package(&self) -> bool {
(self.attributes[3] & (1 << 2)) != 0
}
}