move keys to seperate keys file, cleanup samsung_old

This commit is contained in:
theubusu
2025-10-08 15:14:53 +02:00
parent dbaffb73d0
commit 51c9a668ec
9 changed files with 96 additions and 78 deletions
+1 -8
View File
@@ -8,11 +8,4 @@
- Samsung MSD10(Legacy and Tizen 2015) - Complete
- Samsung MSD11(Tizen 2016+) - Complete
- Panasonic SDDL.SEC(2011+) - Complete
- LG Epk2 (Crypted and plain header)- Should be complete, but needs some more testing
# TODO
- implement some key storing system instead of hardcoding
- cleanup some formats especially mstar and samsung old
- cleanup main file
- Do more testing for PFL UPG and Epk2
- Epk3?
- LG Epk2 (Crypted and plain header)- Should be complete, but needs some more testing
+2 -8
View File
@@ -6,6 +6,7 @@ use aes::Aes128;
use ecb::{Decryptor, cipher::{BlockDecryptMut, KeyInit, generic_array::GenericArray}};
use crate::common;
use crate::keys;
pub fn is_epk2_file(file: &File) -> bool {
let header = common::read_file(&file, 128, 4).expect("Failed to read from file.");
@@ -22,15 +23,8 @@ struct Pak {
name: String,
}
static KEYS: &[(&str, &str)] = &[
("Saturn7/BCM3556", "2F2E2D2C2B2A29281716151413121110"),
("new BCM35230", "6856A0482475A8B41728A35474810203"),
("mtk5369 - Mediatek GP4", "7184C9C428D03C445188234D5A827196"),
("mtk5398 (a2) - Mediatek NetCast 4/4.5", "385A992430196A8C44F1985823C01440"),
];
fn find_key<'a>(data: &[u8], expected_magic: &[u8]) -> Result<Option<(&'a str, Vec<u8>)>, Box<dyn std::error::Error>> {
for (name, key_hex) in KEYS {
for (key_hex, name) in keys::EPK2 {
let key_bytes = hex::decode(key_hex)?;
let decrypted = match decrypt_aes128_ecb(&key_bytes, data) {
Ok(d) => d,
+2 -8
View File
@@ -8,6 +8,7 @@ use cbc::{Decryptor, cipher::{block_padding::Pkcs7, BlockDecryptMut, KeyIvInit}}
type Aes128CbcDec = Decryptor<Aes128>;
use crate::common;
use crate::keys;
pub fn is_msd10_file(file: &File) -> bool {
let header = common::read_file(&file, 0, 6).expect("Failed to read from file.");
@@ -25,13 +26,6 @@ struct Section {
name: String,
}
//fw name, type, key
static KEYS: &[(&str, &str, &str)] = &[
("T-NT14M", "old", "95d01e0bae861a05695bc8a6edb2ea835a09accd"),
("T-HKM", "tizen", "1ac8989ff57db5e75ea67b033050871c"),
("T-HKP", "tizen", "cce8a3ef92f3e94895999e928f4dd6c3"),
];
fn decrypt_aes_salted_old(encrypted_data: &[u8], passphrase_bytes: &Vec<u8>) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
let mut data = encrypted_data.to_vec();
@@ -148,7 +142,7 @@ pub fn extract_msd10(mut file: &File, output_folder: &str) -> Result<(), Box<dyn
let passphrase_bytes;
//find passphrase
for (prefix, fw_type, value) in KEYS {
for (prefix, fw_type, value) in keys::MSD10 {
if firmware_name.starts_with(prefix) {
passphrase = Some(value);
firmware_type = fw_type;
+2 -12
View File
@@ -8,6 +8,7 @@ use cbc::{Decryptor, cipher::{block_padding::Pkcs7, BlockDecryptMut, KeyIvInit}}
type Aes128CbcDec = Decryptor<Aes128>;
use crate::common;
use crate::keys;
pub fn is_msd11_file(file: &File) -> bool {
let header = common::read_file(&file, 0, 6).expect("Failed to read from file.");
@@ -25,17 +26,6 @@ struct Section {
name: String,
}
static KEYS: &[(&str, &str)] = &[
("T-JZM", "9b1d077c0d137d406c79ddacb6b159fe"), //2015
("T-HKMFK", "c7097975e8ab994beb5eaae57e0ba77c"), //2016
("T-KTM2L", "46b04f5e794ca4377a20951c9ea00427"), //2018
("T-KTM2", "29110e0ce940b3a9b67d3e158f3f1342"), //2018
("T-KTM", "d0d49d5f36f5c0da50062fbf32168f5b"), //2017
("T-KTSU", "19e1ba41163f03735e692d9daa2cbb47"), //2018
("T-KTSD", "39332605ff47a0aea999b10ce9087389"), //2018
("T-NKL", "5bab1098dab48792619ebd63650d929f"), //2020
];
fn decrypt_aes_salted_tizen(encrypted_data: &[u8], passphrase_bytes: &Vec<u8>) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
let mut data = encrypted_data.to_vec();
@@ -125,7 +115,7 @@ pub fn extract_msd11(mut file: &File, output_folder: &str) -> Result<(), Box<dyn
let passphrase_bytes;
//find passphrase
for (prefix, value) in KEYS {
for (prefix, value) in keys::MSD11 {
if firmware_name.starts_with(prefix) {
passphrase = Some(value);
break;
+1
View File
@@ -89,6 +89,7 @@ pub fn extract_mstar(file: &File, output_folder: &str) -> Result<(), Box<dyn std
let mut compression = "none";
let mut lz4_expect_size = 0;
let mut j = i + 1;
// get lines after this filepartload, before the next one
while j < lines.len() && !lines[j].starts_with("filepartload") {
//get compression method
+2 -10
View File
@@ -9,6 +9,7 @@ use aes::Aes256;
use ecb::{Decryptor, cipher::{BlockDecryptMut, KeyInit, generic_array::GenericArray}};
use crate::common;
use crate::keys;
pub fn is_pfl_upg_file(file: &File) -> bool {
let header = common::read_file(&file, 0, 8).expect("Failed to read from file.");
@@ -19,15 +20,6 @@ pub fn is_pfl_upg_file(file: &File) -> bool {
}
}
static KEYS: &[(&str, &str)] = &[
("q5551", "D7EE8ED11AC048ED225D4F5F53F8509E55C5D94256A703C79E4CA78AE93ECE1639FE466363AD962BD6D6DE0C46FD19F363687C1D8A21820740A6E7FF87F41C4900DCE1E26EC122E5D4DFA76BFC8F296816B8D0910325E9DC5CBCC9579CF15FC0253EF7CF4919B7613491A5D7BF75DC1888531C458967FD1CF64B33139550BAA5"),
("qf1eu", "ACD684155C7CCCB04372A8808514489FA9EE75D305987D1337420241FDBE0AE1F7CDFBB931C9D56C91D36F2CE79D222695B484FF42BCA12CE362C7C9ABBDEEC8E5D6107FADCF2D4DA5DF0693E13ACE54A18AEB21C051F6B62C075A1791985547C1CFF4FB5B6EA7E0A9405A1B2BB71EB89A9B209E0F62BF9794D673179C0E60F1"),
("q591e", "AFAF89062747CBB29343C4E4EA775E4CFDF5FAFCD92C9DD858A8725201BA54AB973BEFEE04EBF3046910FBBC78B10120AE16D80BA734931E97248BC6B1D4A909F087D37BC0A9C2210FF8A2BE44C00F31E4DD8713A364623637FF75EBBCE9D3A840DB67E0FA910F127F679496F6C21112E3E3AD4ACA459FDE1CC58E300682E6F9"),
("q522e", "C41BE92C212BAC76B48261E2A1704028287DD7E121C11DA25F709E864FBDC1BD8C7F226F57605A4B42D768CDD629AF9E54011A0967AFC2826331406FB1E90321620738526EA0BEA59F1A0E612AE891C396112F13531F423DF02F94D1C871429549F4D5B30D9CA3EFDCC6D7A96849F7C1788DE8FAAEDD36560337008DF06D612F"),
("q5481", "9E7DA389815251E82A84A1182807702E72A0B0E0FF707C8E73E2EA71F79D5FAAFFC6E0B90ED16E13A4289C78A7D3BDA90626162AAE169D7BE28D6A635585CC10639C4E312E288EB8F7C5A44518B7E8A26A45C5023C5078A972A4CC219CA020BAF524F7429257B7AD76E1B15390879064C6ED59CC1F20CC04EEC26C9CF7FC0727"),
("q5431", "C5FD937B301A5CEF4B6C25F187728C99636515D058895FEA469496E2B24907FC7721648841F8AE4C618E215673D0C029752FA970B6F9A7F48C9331293D3B1D43E4DFC7B52914973642CD3E4EE0AD11F5254505038F95CACE0DF21FC769B34E134435D88AB617D2981F66EF45BBC7796CFB1086C5D5672E837204991FE53BC1CF"),
];
static AUTO_FWS: &[(&str, &str)] = &[
("Q5551", "q5551"),
("Q5553", "q5551"),
@@ -109,7 +101,7 @@ pub fn extract_pfl_upg(mut file: &File, output_folder: &str) -> Result<(), Box<d
}
//get key
for (prefix, value) in KEYS {
for (prefix, value) in keys::PFLUPG {
if key == Some(prefix) {
n_hex = Some(value);
break;
+25 -32
View File
@@ -3,12 +3,14 @@ use std::path::{Path, PathBuf};
use std::fs::{File, OpenOptions};
use std::io::{Write};
use aes::Aes128;
use hex::decode;
use cbc::{Decryptor, cipher::{block_padding::Pkcs7, BlockDecryptMut, KeyIvInit}};
use sha1::{Digest, Sha1};
type Aes128CbcDec = Decryptor<Aes128>;
use crate::common;
use crate::keys;
use md5;
@@ -43,36 +45,21 @@ pub fn extract_samsung_old(path: &PathBuf, output_folder: &str) -> Result<(), Bo
println!("Firmware info: {}", fw_info);
let image_path = Path::new(&path).join("image");
let mut secret = "";
let secret_t_ecp = [0x3E, 0xF6, 0x06, 0x72, 0x62, 0xCF, 0x0C, 0x67, 0x85, 0x98, 0xBF, 0xF2, 0x21, 0x69, 0xD1, 0xF1, 0xEA, 0x57, 0xC2, 0x84];
// from samygo tool
if fw_info.starts_with("T-GA"){
secret = "SHWJUH:85a045ae-2296-484c-b457-ede832fcfbe1-646390a3-105e-40aa-85f6-da3086c70111";
} else if fw_info.starts_with("T-MST5"){
secret = "SHWJUH:eceb2c14-db11-425e-9ebf-5f9607f0eb4b-3c38193e-751e-4719-8884-9e76322c0cec";
} else if fw_info.starts_with("B-FIRHT7"){
secret = "d6442d-7b46b2f4-0f11-4623-af63-8bb0a0d54c80-a22fbe2c-1bb5-49cc-b194-25c0f2b870f4";
} else if fw_info.starts_with("B-FIRU") | fw_info.starts_with("B-FIRH") | fw_info.starts_with("B-FIRBSP") | fw_info.starts_with("B-FIR2"){
secret = "SHWJUH:db48ad51-c784-4f06-af57-1070a910c536-6a028bb5-e83e-45da-b326-a3a39ccba26c";
} else if fw_info.starts_with("B-FIRB"){
secret = "d6442d-7b46b2f4-0f11-4623-af63-8bb0a0d54c80-a22fbe2c-1bb5-49cc-b194-25c0f2b870f4";
} else if fw_info.starts_with("T-MST10P"){
secret = "b4c136-fbc93576-b3e8-4035-bf4e-ba4cb4ada1ac-f0d81cc4-8301-4832-bd60-f331295743ba";
} else if fw_info.starts_with("B-ECB"){
secret = "SHWJUH:8fb684a9-84c1-46cf-aa81-977bce241542-6db4c136-8540-4ee4-8704-d9cd18590d11";
} else if fw_info.starts_with("T-VAL"){
secret = "A435HX:d3e90afc-0f09-4054-9bac-350cc8dfc901-7cee72ea-15ae-45ce-b0f5-00001abc2010";
} else if fw_info.starts_with("T-TDT"){
secret = "A435HX:d3e90afc-0f09-4054-9bac-350cc8dfc901-7cee72ea-15ae-45ce-b0f5-00002abc2010";
} else if fw_info.starts_with("T-MSX"){
secret = "A435HX:d3e90afc-0f09-4054-9bac-350cc8dfc901-7cee72ea-15ae-45ce-b0f5-00004abc2010";
} else if fw_info.starts_with("T-CH"){
secret = "A435HX:d3e90afc-0f09-4054-9bac-350cc8dfc901-7cee72ea-15ae-45ce-b0f5-611c4f8d4a71";
} else if fw_info.starts_with("T-ECP") {
let mut secret: Option<&str> = None;
//find secret
for (prefix, value) in keys::SAMSUNG {
if fw_info.starts_with(prefix) {
secret = Some(value);
break;
}
}
if let Some(p) = secret {
println!("Secret: {}", p);
} else {
println!("Sorry, this firmware is not supported!");
return Ok(());
std::process::exit(1);
}
for entry in fs::read_dir(image_path)? {
@@ -86,6 +73,7 @@ pub fn extract_samsung_old(path: &PathBuf, output_folder: &str) -> Result<(), Bo
let filename = path.file_name().unwrap().to_str().unwrap();
let file_size = file.metadata()?.len();
println!("\nFile: {}", filename);
let data = common::read_file(&file, 0, file_size.try_into().unwrap())?;
let salt = &data[8..16];
@@ -95,25 +83,31 @@ pub fn extract_samsung_old(path: &PathBuf, output_folder: &str) -> Result<(), Bo
//Old -> key: md5 of (sha1 of secret as TEXT + salt)
// iv: md5 of (md5 of key + key)
//2012 -> key: md5 of (secret + salt)
//2012 -> key: md5 of (secret(as bytes) + salt)
// iv: md5 of (md5 of key + key)
if fw_info.starts_with("T-ECP") {
let key: Vec<u8> = [&secret_t_ecp, salt].concat();
let mut key = Vec::new();
key.extend_from_slice(&decode(secret.unwrap())?);
key.extend_from_slice(salt);
key_md5 = md5::compute(&key);
let mut iv = Vec::new();
iv.extend_from_slice(&key_md5.0);
iv.extend_from_slice(&key);
iv_md5 = md5::compute(&iv);
} else {
let mut hasher = Sha1::new();
hasher.update(secret);
hasher.update(secret.as_ref().unwrap());
let secret_digest = hasher.finalize();
// yes it needs to be a string first then into bytes
let secret_digest_string = format!("{:x}", secret_digest);
let secret_digest_bytes = secret_digest_string.as_bytes();
let key: Vec<u8> = [&secret_digest_bytes, salt].concat();
let mut key = Vec::new();
key.extend_from_slice(&secret_digest_bytes);
key.extend_from_slice(salt);
key_md5 = md5::compute(&key);
let mut iv = Vec::new();
@@ -124,7 +118,6 @@ pub fn extract_samsung_old(path: &PathBuf, output_folder: &str) -> Result<(), Bo
//println!("Key: {:02x?}", key_md5);
//println!("IV: {:02x?}", iv_md5);
let end = file_size - 260;
println!("- Decrypting file...");
let decrypted_data = decrypt_aes(&data[16..end.try_into().unwrap()], &key_md5, &iv_md5)?;
+60
View File
@@ -0,0 +1,60 @@
//samsung old keys
pub static SAMSUNG: &[(&str, &str)] = &[
("T-GA", "SHWJUH:85a045ae-2296-484c-b457-ede832fcfbe1-646390a3-105e-40aa-85f6-da3086c70111"),
("T-MST5", "SHWJUH:eceb2c14-db11-425e-9ebf-5f9607f0eb4b-3c38193e-751e-4719-8884-9e76322c0cec"),
("T-MST10P","b4c136-fbc93576-b3e8-4035-bf4e-ba4cb4ada1ac-f0d81cc4-8301-4832-bd60-f331295743ba"),
("T-VAL", "A435HX:d3e90afc-0f09-4054-9bac-350cc8dfc901-7cee72ea-15ae-45ce-b0f5-00001abc2010"),
("T-TDT", "A435HX:d3e90afc-0f09-4054-9bac-350cc8dfc901-7cee72ea-15ae-45ce-b0f5-00002abc2010"),
("T-MSX", "A435HX:d3e90afc-0f09-4054-9bac-350cc8dfc901-7cee72ea-15ae-45ce-b0f5-00004abc2010"),
("T-CH", "A435HX:d3e90afc-0f09-4054-9bac-350cc8dfc901-7cee72ea-15ae-45ce-b0f5-611c4f8d4a71"),
("T-ECP", "3EF6067262CF0C678598BFF22169D1F1EA57C284"),
];
//pfl upg keys
pub static PFLUPG: &[(&str, &str)] = &[
("q5551", "D7EE8ED11AC048ED225D4F5F53F8509E55C5D94256A703C79E4CA78AE93ECE1639FE466363AD962BD6D6DE0C46FD19F363687C1D8A21820740A6E7FF87F41C4900DCE1E26EC122E5D4DFA76BFC8F296816B8D0910325E9DC5CBCC9579CF15FC0253EF7CF4919B7613491A5D7BF75DC1888531C458967FD1CF64B33139550BAA5"),
("qf1eu", "ACD684155C7CCCB04372A8808514489FA9EE75D305987D1337420241FDBE0AE1F7CDFBB931C9D56C91D36F2CE79D222695B484FF42BCA12CE362C7C9ABBDEEC8E5D6107FADCF2D4DA5DF0693E13ACE54A18AEB21C051F6B62C075A1791985547C1CFF4FB5B6EA7E0A9405A1B2BB71EB89A9B209E0F62BF9794D673179C0E60F1"),
("q591e", "AFAF89062747CBB29343C4E4EA775E4CFDF5FAFCD92C9DD858A8725201BA54AB973BEFEE04EBF3046910FBBC78B10120AE16D80BA734931E97248BC6B1D4A909F087D37BC0A9C2210FF8A2BE44C00F31E4DD8713A364623637FF75EBBCE9D3A840DB67E0FA910F127F679496F6C21112E3E3AD4ACA459FDE1CC58E300682E6F9"),
("q522e", "C41BE92C212BAC76B48261E2A1704028287DD7E121C11DA25F709E864FBDC1BD8C7F226F57605A4B42D768CDD629AF9E54011A0967AFC2826331406FB1E90321620738526EA0BEA59F1A0E612AE891C396112F13531F423DF02F94D1C871429549F4D5B30D9CA3EFDCC6D7A96849F7C1788DE8FAAEDD36560337008DF06D612F"),
("q5481", "9E7DA389815251E82A84A1182807702E72A0B0E0FF707C8E73E2EA71F79D5FAAFFC6E0B90ED16E13A4289C78A7D3BDA90626162AAE169D7BE28D6A635585CC10639C4E312E288EB8F7C5A44518B7E8A26A45C5023C5078A972A4CC219CA020BAF524F7429257B7AD76E1B15390879064C6ED59CC1F20CC04EEC26C9CF7FC0727"),
("q5431", "C5FD937B301A5CEF4B6C25F187728C99636515D058895FEA469496E2B24907FC7721648841F8AE4C618E215673D0C029752FA970B6F9A7F48C9331293D3B1D43E4DFC7B52914973642CD3E4EE0AD11F5254505038F95CACE0DF21FC769B34E134435D88AB617D2981F66EF45BBC7796CFB1086C5D5672E837204991FE53BC1CF"),
];
//MSD10 keys
//fw prefix, type, key
pub static MSD10: &[(&str, &str, &str)] = &[
("T-NT14M", "old", "95d01e0bae861a05695bc8a6edb2ea835a09accd"),
("T-HKM", "tizen", "1ac8989ff57db5e75ea67b033050871c"),
("T-HKP", "tizen", "cce8a3ef92f3e94895999e928f4dd6c3"),
];
//MSD11 keys
pub static MSD11: &[(&str, &str)] = &[
("T-JZM", "9b1d077c0d137d406c79ddacb6b159fe"), //2015
("T-HKMFK", "c7097975e8ab994beb5eaae57e0ba77c"), //2016
("T-KTM2L", "46b04f5e794ca4377a20951c9ea00427"), //2018
("T-KTM2", "29110e0ce940b3a9b67d3e158f3f1342"), //2018
("T-KTM", "d0d49d5f36f5c0da50062fbf32168f5b"), //2017
("T-KTSU", "19e1ba41163f03735e692d9daa2cbb47"), //2018
("T-KTSD", "39332605ff47a0aea999b10ce9087389"), //2018
("T-NKL", "5bab1098dab48792619ebd63650d929f"), //2020
];
//epk2 keys
pub static EPK2: &[(&str, &str)] = &[
("214BF3C129547AF31D32A5ECB4742192", "unknown"),
("1F1E1D1C1B1A19180706050403020100", "BCM35230/early MTK5369 and LG1152"),
("7184C9C428D03C445188234D5A827196", "mtk5369 - Mediatek GP4"),
("385A992430196A8C44F1985823C01440", "mtk5398 (a2) - Mediatek NetCast 4/4.5"),
("6856A0482475A8B41728A35474810203", "new BCM35230"),
("2F2E2D2C2B2A29281716151413121110", "Saturn7/BCM3556"),
("212D3B2A5C2D3A2C4D5B234B1A321D2A", "new Saturn7/old LM1"),
("4F836AAEB4301F26172A9B0E1120EAF4", "LM1 PDP"),
("4EE662C7A2C0917F7328DE73A0836C6B", "LM1 LCD"),
("2F534ABE34801A36B7DA6B3EB1C04AD4", "m1 - MStar non-webOS"),
("7B2CA5943D2E752CF58606228C5B2DAD", "m1a - MStar non-webOS (L15 signage)"),
("D55C6864035A8C8A2B35A6D6C4565596", "m2 - MStar SimpleSmart"),
("68A284B4953CAD15024BED2C4F852A09", "lm14 - MStar NetCast 4.5"),
("4813B5B63C998A2874EF3320684AC8D9", "lg1152 - LX GP4"),
("14B3623488212250C7C992AACD537447", "lg115x - LX NC4"),
];
+1
View File
@@ -1,5 +1,6 @@
mod common;
mod formats;
mod keys;
use clap::Parser;
use std::path::{PathBuf};