mirror of
https://github.com/Ap0dexMe0/unixtract.git
synced 2026-07-15 21:00:03 +02:00
sony_bdp: add support for aes encryption, add keys for MSB19-29
This commit is contained in:
Generated
+2
-2
@@ -903,9 +903,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.18.0"
|
version = "1.20.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
|
checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ Tip: if you have split ROM (.ROM-00 and .ROM-01), extract both into the same fol
|
|||||||
|
|
||||||
## Sony BDP
|
## Sony BDP
|
||||||
**Used in:** Sony MediaTek-based Blu-Ray players
|
**Used in:** Sony MediaTek-based Blu-Ray players
|
||||||
**Notes:** Only platforms up to MSB18 are supported.
|
**Notes:** **Depends on keys** - see keys.rs (Platforms up to MSB29 are supported)
|
||||||
**Thanks to:** http://malcolmstagg.com/bdp/s390-firmware.html
|
**Thanks to:** http://malcolmstagg.com/bdp/s390-firmware.html
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
use crate::utils::common;
|
use crate::utils::common;
|
||||||
use binrw::BinRead;
|
use binrw::BinRead;
|
||||||
|
|
||||||
//thx sony
|
pub enum EncryptionType {
|
||||||
|
HexSubst,
|
||||||
|
AesOfb(([u8; 16], [u8; 16], String)), //key, iv, key name
|
||||||
|
}
|
||||||
|
|
||||||
|
//for hex subst (old enc)
|
||||||
static HEX_SUBSTITUTION: [u8; 256] = [
|
static HEX_SUBSTITUTION: [u8; 256] = [
|
||||||
0xE8, 0x4D, 0x63, 0xF4, 0xF8, 0xA9, 0x21, 0x9C, 0xC7, 0x82, 0xCD, 0xE3, 0xC1, 0xCE, 0xC0, 0xFA, 0xE7, 0xD6, 0x96, 0x46, 0x12, 0x03, 0x14, 0x33, 0xED, 0x10, 0xEC, 0x69, 0x16, 0xE0, 0x28, 0x30,
|
0xE8, 0x4D, 0x63, 0xF4, 0xF8, 0xA9, 0x21, 0x9C, 0xC7, 0x82, 0xCD, 0xE3, 0xC1, 0xCE, 0xC0, 0xFA, 0xE7, 0xD6, 0x96, 0x46, 0x12, 0x03, 0x14, 0x33, 0xED, 0x10, 0xEC, 0x69, 0x16, 0xE0, 0x28, 0x30,
|
||||||
0x77, 0x0E, 0x3D, 0xEF, 0x36, 0x4C, 0x18, 0xEB, 0x41, 0x89, 0x64, 0x8A, 0x70, 0x0C, 0x23, 0xA3, 0x79, 0x6D, 0x75, 0x7E, 0x1A, 0x2D, 0x01, 0x91, 0x88, 0xCB, 0xFC, 0x8B, 0xFD, 0x94, 0x0A, 0x39,
|
0x77, 0x0E, 0x3D, 0xEF, 0x36, 0x4C, 0x18, 0xEB, 0x41, 0x89, 0x64, 0x8A, 0x70, 0x0C, 0x23, 0xA3, 0x79, 0x6D, 0x75, 0x7E, 0x1A, 0x2D, 0x01, 0x91, 0x88, 0xCB, 0xFC, 0x8B, 0xFD, 0x94, 0x0A, 0x39,
|
||||||
@@ -17,6 +22,31 @@ pub fn hex_substitute(data: &[u8]) -> Vec<u8> {
|
|||||||
data.iter().map(|&b| HEX_SUBSTITUTION[b as usize]).collect()
|
data.iter().map(|&b| HEX_SUBSTITUTION[b as usize]).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//for aes (new enc)
|
||||||
|
use aes::Aes128;
|
||||||
|
use aes::cipher::{BlockEncrypt, KeyInit};
|
||||||
|
use aes::cipher::generic_array::GenericArray;
|
||||||
|
|
||||||
|
pub fn ver_up_decrypt_aes128ofb(key: &[u8], iv: &[u8], data: &[u8]) -> Vec<u8> {
|
||||||
|
let cipher = Aes128::new(GenericArray::from_slice(key));
|
||||||
|
|
||||||
|
let mut output = Vec::with_capacity(data.len());
|
||||||
|
let mut feedback = GenericArray::clone_from_slice(iv);
|
||||||
|
for chunk in data.chunks(16) {
|
||||||
|
cipher.encrypt_block(&mut feedback);
|
||||||
|
for (b, k) in chunk.iter().zip(feedback.iter()) {
|
||||||
|
output.push(b ^ k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_valid_header_magic(data: &[u8]) -> bool {
|
||||||
|
matches!(data, [b'M', b'S', b'B', d1, d2, ..] if d1.is_ascii_digit() && d2.is_ascii_digit()) ||
|
||||||
|
matches!(data, [b'B', b'D', b'P', b'P', d1, d2, ..] if d1.is_ascii_digit() && d2.is_ascii_digit())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(BinRead)]
|
#[derive(BinRead)]
|
||||||
pub struct Header {
|
pub struct Header {
|
||||||
firmware_name_bytes: [u8; 8],
|
firmware_name_bytes: [u8; 8],
|
||||||
|
|||||||
+58
-17
@@ -5,29 +5,70 @@ use crate::{InputTarget, AppContext};
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::fs::{self, OpenOptions};
|
use std::fs::{self, OpenOptions};
|
||||||
use std::io::{Cursor, Write};
|
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
||||||
use binrw::BinReaderExt;
|
use binrw::BinReaderExt;
|
||||||
|
|
||||||
use crate::utils::common;
|
use crate::utils::common;
|
||||||
use crate::formats;
|
use crate::formats;
|
||||||
|
use crate::keys;
|
||||||
use include::*;
|
use include::*;
|
||||||
|
|
||||||
|
struct SonyBdpCtx {
|
||||||
|
encryption_type: EncryptionType,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_sony_bdp_file(app_ctx: &AppContext) -> Result<Option<Box<dyn Any>>, Box<dyn std::error::Error>> {
|
pub fn is_sony_bdp_file(app_ctx: &AppContext) -> Result<Option<Box<dyn Any>>, Box<dyn std::error::Error>> {
|
||||||
let file = match app_ctx.file() {Some(f) => f, None => return Ok(None)};
|
let file = match app_ctx.file() {Some(f) => f, None => return Ok(None)};
|
||||||
|
let header_magic = common::read_file(&file, 0, 16)?;
|
||||||
|
|
||||||
let header = common::read_file(&file, 0, 4)?;
|
//try old encryption (hex subst)
|
||||||
if header == b"\x01\x73\xEC\xC9" || header == b"\x01\x73\xEC\x1F" || header == b"\xEC\x7D\xB0\xB0" { //MSB1x, MSB0x, BDPPxx
|
if is_valid_header_magic(&hex_substitute(&header_magic)) {
|
||||||
Ok(Some(Box::new(())))
|
return Ok(Some(Box::new(
|
||||||
} else {
|
SonyBdpCtx {encryption_type:
|
||||||
Ok(None)
|
EncryptionType::HexSubst
|
||||||
|
}
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//try new encryption (aes)
|
||||||
|
for (key_hex, iv_hex, name) in keys::SONY_BDP_AES {
|
||||||
|
let key_array: [u8; 16] = hex::decode(key_hex)?.as_slice().try_into()?;
|
||||||
|
let iv_array: [u8; 16] = hex::decode(iv_hex)?.as_slice().try_into()?;
|
||||||
|
let try_decrypt = ver_up_decrypt_aes128ofb(&key_array, &iv_array, &header_magic);
|
||||||
|
|
||||||
|
if is_valid_header_magic(&try_decrypt) {
|
||||||
|
return Ok(Some(Box::new(
|
||||||
|
SonyBdpCtx {encryption_type:
|
||||||
|
EncryptionType::AesOfb((key_array, iv_array, name.to_string()))
|
||||||
|
}
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_sony_bdp(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box<dyn std::error::Error>> {
|
pub fn extract_sony_bdp(app_ctx: &AppContext, ctx: Box<dyn Any>) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut file = app_ctx.file().ok_or("Extractor expected file")?;
|
let mut file = app_ctx.file().ok_or("Extractor expected file")?;
|
||||||
|
let ctx = ctx.downcast::<SonyBdpCtx>().expect("Missing context");
|
||||||
|
|
||||||
let obf_header = common::read_exact(&mut file, 300)?;
|
//need to decrypt entire file of new aes enc
|
||||||
let header = hex_substitute(&obf_header);
|
let mut enc_data = Vec::new();
|
||||||
|
file.read_to_end(&mut enc_data)?;
|
||||||
|
|
||||||
|
let dec_data = match ctx.encryption_type {
|
||||||
|
EncryptionType::HexSubst => {
|
||||||
|
println!("Decrypting with hex substitution...");
|
||||||
|
hex_substitute(&enc_data)
|
||||||
|
},
|
||||||
|
EncryptionType::AesOfb((key, iv, key_name)) => {
|
||||||
|
println!("Decrypting with AES key: {}...", key_name);
|
||||||
|
ver_up_decrypt_aes128ofb(&key, &iv, &enc_data)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut data_reader = Cursor::new(dec_data);
|
||||||
|
|
||||||
|
let header = common::read_exact(&mut data_reader, 300)?;
|
||||||
let mut hdr_reader = Cursor::new(header);
|
let mut hdr_reader = Cursor::new(header);
|
||||||
let hdr: Header = hdr_reader.read_le()?;
|
let hdr: Header = hdr_reader.read_le()?;
|
||||||
|
|
||||||
@@ -53,8 +94,8 @@ pub fn extract_sony_bdp(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(),
|
|||||||
first_entry_offset = entry.offset as u64;
|
first_entry_offset = entry.offset as u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
let obf_data = common::read_file(&file, entry.offset as u64, entry.size as usize)?;
|
data_reader.seek(SeekFrom::Start(entry.offset as u64))?;
|
||||||
let data = hex_substitute(&obf_data);
|
let data = common::read_exact(&mut data_reader, entry.size as usize)?;
|
||||||
|
|
||||||
let output_path = Path::new(&app_ctx.output_dir).join(format!("{}.bin", i+1));
|
let output_path = Path::new(&app_ctx.output_dir).join(format!("{}.bin", i+1));
|
||||||
last_file_path = Some(output_path.clone());
|
last_file_path = Some(output_path.clone());
|
||||||
@@ -67,19 +108,19 @@ pub fn extract_sony_bdp(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(),
|
|||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//The last file is often a Mtk BDP file so we can extract that here.
|
//The last file is the host MTK BDP file so we can extract that here (wont work for pre-linux which have old mtk bdp though.)
|
||||||
if last_file_path.is_some() {
|
if last_file_path.is_some() {
|
||||||
println!("\nChecking if it's also MTK BDP...");
|
|
||||||
|
|
||||||
let last_file = File::open(last_file_path.unwrap())?;
|
let last_file = File::open(last_file_path.unwrap())?;
|
||||||
let mtk_extraction_path = app_ctx.output_dir.join(format!("{}", i));
|
let mtk_extraction_path = app_ctx.output_dir.join(format!("{}", i));
|
||||||
|
|
||||||
//this is getting stupid...
|
let ctx: AppContext = AppContext {
|
||||||
let ctx: AppContext = AppContext { input: InputTarget::File(last_file), output_dir: mtk_extraction_path, options: app_ctx.options.clone() };
|
input: InputTarget::File(last_file),
|
||||||
|
output_dir: mtk_extraction_path,
|
||||||
|
options: app_ctx.options.clone()
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(result) = formats::mtk_bdp::is_mtk_bdp_file(&ctx)? {
|
if let Some(result) = formats::mtk_bdp::is_mtk_bdp_file(&ctx)? {
|
||||||
println!("- MTK BDP file detected!\n");
|
println!("- MTK BDP file detected!\n");
|
||||||
|
|
||||||
formats::mtk_bdp::extract_mtk_bdp(&ctx, result)?;
|
formats::mtk_bdp::extract_mtk_bdp(&ctx, result)?;
|
||||||
} else {
|
} else {
|
||||||
println!("- Not an MTK BDP file.");
|
println!("- Not an MTK BDP file.");
|
||||||
|
|||||||
@@ -131,6 +131,13 @@ pub static FUNAI_BDP: &[&str] = &[
|
|||||||
("09E87783"),
|
("09E87783"),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
//Sony BDP AES keys
|
||||||
|
//key, iv(der), desc
|
||||||
|
pub static SONY_BDP_AES: &[(&str, &str, &str)] = &[
|
||||||
|
("2EC0855737CADA76E1D82F9D5526B46E", "8F5E39A2A36AD9B0A9D2E3041AA03867", "MSB19-23"),
|
||||||
|
("0D8B87A8CE27702197155B8AC057E13A", "C280F2F534B1E53421D31AC4BE56CA43", "MSB24-29"),
|
||||||
|
];
|
||||||
|
|
||||||
//EPK keys
|
//EPK keys
|
||||||
//github.com/openlgtv/epk2extract
|
//github.com/openlgtv/epk2extract
|
||||||
pub static EPK: &[(&str, &str)] = &[
|
pub static EPK: &[(&str, &str)] = &[
|
||||||
|
|||||||
Reference in New Issue
Block a user