From 45bb51ded8f41f6a819201384b5258b9a61785c5 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 28 Feb 2017 12:22:50 +0300 Subject: [PATCH] unpkg improved Initial content_type parsing Added PSP2 support --- rpcs3/Crypto/unpkg.cpp | 85 ++++++++++++++++++++++++++++++++++++------ rpcs3/Crypto/unpkg.h | 6 +-- 2 files changed, 77 insertions(+), 14 deletions(-) diff --git a/rpcs3/Crypto/unpkg.cpp b/rpcs3/Crypto/unpkg.cpp index c2761051de..3f4d0e3849 100644 --- a/rpcs3/Crypto/unpkg.cpp +++ b/rpcs3/Crypto/unpkg.cpp @@ -49,12 +49,6 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t } } - if (header.header_size != PKG_HEADER_SIZE && header.header_size != PKG_HEADER_SIZE2) - { - LOG_ERROR(LOADER, "Wrong PKG header size (0x%x)", header.header_size); - return false; - } - if (header.pkg_size > pkg_f.size()) { LOG_ERROR(LOADER, "PKG file size mismatch (pkg_size=0x%llx)", header.pkg_size); @@ -67,11 +61,54 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t return false; } + be_t drm_type{0}; + be_t content_type{0}; + + pkg_f.seek(header.pkg_info_off); + + for (u32 i = 0; i < header.pkg_info_num; i++) + { + struct packet_T + { + be_t id; + be_t size; + } packet; + + pkg_f.read(packet); + + // TODO + switch (+packet.id) + { + case 0x1: + { + if (packet.size == sizeof(drm_type)) + { + pkg_f.read(drm_type); + continue; + } + + break; + } + case 0x2: + { + if (packet.size == sizeof(content_type)) + { + pkg_f.read(content_type); + continue; + } + + break; + } + } + + pkg_f.seek(packet.size, fs::seek_cur); + } + // Allocate buffer with BUF_SIZE size or more if required const std::unique_ptr buf(new u128[std::max(BUF_SIZE, sizeof(PKGEntry) * header.file_count) / sizeof(u128)]); // Define decryption subfunction (`psp` arg selects the key for specific block) - auto decrypt = [&](u64 offset, u64 size, bool psp) -> u64 + auto decrypt = [&](u64 offset, u64 size, const uchar* key) -> u64 { pkg_f.seek(start_offset + header.data_offset + offset); @@ -114,7 +151,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t aes_context ctx; // Set encryption key for stream cipher - aes_setkey_enc(&ctx, psp ? PKG_AES_KEY2 : PKG_AES_KEY, 128); + aes_setkey_enc(&ctx, key, 128); // Initialize stream cipher for start position be_t input = header.klicensee.value() + offset / 16; @@ -134,7 +171,24 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t return read; }; - decrypt(0, header.file_count * sizeof(PKGEntry), header.pkg_platform == PKG_PLATFORM_TYPE_PSP); + std::array dec_key; + + if (header.pkg_platform == PKG_PLATFORM_TYPE_PSP && content_type >= 0x15 && content_type <= 0x17) + { + const uchar psp2t1[] = {0xE3, 0x1A, 0x70, 0xC9, 0xCE, 0x1D, 0xD7, 0x2B, 0xF3, 0xC0, 0x62, 0x29, 0x63, 0xF2, 0xEC, 0xCB}; + const uchar psp2t2[] = {0x42, 0x3A, 0xCA, 0x3A, 0x2B, 0xD5, 0x64, 0x9F, 0x96, 0x86, 0xAB, 0xAD, 0x6F, 0xD8, 0x80, 0x1F}; + const uchar psp2t3[] = {0xAF, 0x07, 0xFD, 0x59, 0x65, 0x25, 0x27, 0xBA, 0xF1, 0x33, 0x89, 0x66, 0x8B, 0x17, 0xD9, 0xEA}; + + aes_context ctx; + aes_setkey_enc(&ctx, content_type == 0x15 ? psp2t1 : content_type == 0x16 ? psp2t2 : psp2t3, 128); + aes_crypt_ecb(&ctx, AES_ENCRYPT, reinterpret_cast(&header.klicensee), dec_key.data()); + decrypt(0, header.file_count * sizeof(PKGEntry), dec_key.data()); + } + else + { + std::memcpy(dec_key.data(), PKG_AES_KEY, dec_key.size()); + decrypt(0, header.file_count * sizeof(PKGEntry), header.pkg_platform == PKG_PLATFORM_TYPE_PSP ? PKG_AES_KEY2 : dec_key.data()); + } std::vector entries(header.file_count); @@ -150,10 +204,12 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t continue; } - decrypt(entry.name_offset, entry.name_size, is_psp); + decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : dec_key.data()); const std::string name(reinterpret_cast(buf.get()), entry.name_size); + LOG_NOTICE(LOADER, "Entry 0x%08x: %s", entry.type, name); + switch (entry.type & 0xff) { case PKG_FILE_ENTRY_NPDRM: @@ -161,6 +217,12 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t case PKG_FILE_ENTRY_SDAT: case PKG_FILE_ENTRY_REGULAR: case PKG_FILE_ENTRY_UNK1: + case 0xe: + case 0x10: + case 0x11: + case 0x13: + case 0x15: + case 0x16: { const std::string path = dir + name; @@ -172,7 +234,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t { const u64 block_size = std::min(BUF_SIZE, entry.file_size - pos); - if (decrypt(entry.file_offset + pos, block_size, is_psp) != block_size) + if (decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : dec_key.data()) != block_size) { LOG_ERROR(LOADER, "Failed to extract file %s", path); break; @@ -209,6 +271,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t } case PKG_FILE_ENTRY_FOLDER: + case 0x12: { const std::string path = dir + name; diff --git a/rpcs3/Crypto/unpkg.h b/rpcs3/Crypto/unpkg.h index f288b2c095..75e7ff57ba 100644 --- a/rpcs3/Crypto/unpkg.h +++ b/rpcs3/Crypto/unpkg.h @@ -35,9 +35,9 @@ struct PKGHeader nse_t pkg_magic; // Magic (0x7f504b47) be_t pkg_type; // Release type (Retail:0x8000, Debug:0x0000) be_t pkg_platform; // Platform type (PS3:0x0001, PSP:0x0002) - be_t header_size; // Header size (0xc0) - be_t unk1; // Some PKG version maybe? - be_t meta_size; // Size of metadata (block after header & hashes) + be_t pkg_info_off; + be_t pkg_info_num; + be_t header_size; // Header size be_t file_count; // Number of files be_t pkg_size; // PKG size in bytes be_t data_offset; // Encrypted data offset