mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-02 19:13:36 +00:00
Crypto: fix sprx/self check in npDrm and edata fixes
This commit is contained in:
parent
44e62c5c92
commit
65696bf6a3
@ -159,7 +159,7 @@ class KeyVault
|
||||
std::vector<SELF_KEY> sk_LDR_arr;
|
||||
std::vector<SELF_KEY> sk_UNK7_arr;
|
||||
std::vector<SELF_KEY> sk_NPDRM_arr;
|
||||
u8 klicensee_key[0x10];
|
||||
u8 klicensee_key[0x10] = {};
|
||||
|
||||
public:
|
||||
KeyVault();
|
||||
|
@ -912,8 +912,7 @@ bool EDATADecrypter::ReadHeader()
|
||||
|
||||
if (dec_key == std::array<u8, 0x10>{0})
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: A valid RAP file is needed for this EDAT file!");
|
||||
return false;
|
||||
LOG_WARNING(LOADER, "EDAT: Empty Dec key!");
|
||||
}
|
||||
}
|
||||
else if ((npdHeader.license & 0x1) == 0x1) // Type 1: Use network activation.
|
||||
|
@ -14,7 +14,7 @@ constexpr u32 EDAT_FLAG_0x10 = 0x00000010;
|
||||
constexpr u32 EDAT_FLAG_0x20 = 0x00000020;
|
||||
constexpr u32 EDAT_DEBUG_DATA_FLAG = 0x80000000;
|
||||
|
||||
struct EdatKeys_t
|
||||
struct LoadedNpdrmKeys_t
|
||||
{
|
||||
std::array<u8, 0x10> devKlic{};
|
||||
std::array<u8, 0x10> rifKey{};
|
||||
|
@ -1089,10 +1089,11 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
|
||||
memcpy(klicensee_key, key_v.GetKlicenseeKey(), 0x10);
|
||||
|
||||
// Use klicensee if available.
|
||||
if (klicensee_key != NULL)
|
||||
if (memcmp(klicensee_key, std::array<u8, 0x10>{0}.data(), 0x10))
|
||||
{
|
||||
memcpy(npdrm_key, klicensee_key, 0x10);
|
||||
|
||||
if (ctrl->npdrm.license == 1) // Network license.
|
||||
}
|
||||
else if (ctrl->npdrm.license == 1) // Network license.
|
||||
{
|
||||
LOG_ERROR(LOADER, "SELF: Can't decrypt network NPDRM!");
|
||||
return false;
|
||||
@ -1131,7 +1132,7 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SELFDecrypter::LoadMetadata()
|
||||
bool SELFDecrypter::LoadMetadata(u8* klic_key)
|
||||
{
|
||||
aes_context aes;
|
||||
u32 metadata_info_size = SIZE_32(meta_info);
|
||||
@ -1150,6 +1151,10 @@ bool SELFDecrypter::LoadMetadata()
|
||||
// Find the right keyset from the key vault.
|
||||
SELF_KEY keyset = key_v.FindSelfKey(app_info.self_type, sce_hdr.se_flags, app_info.version);
|
||||
|
||||
// Set klic if given
|
||||
if (klic_key)
|
||||
key_v.SetKlicenseeKey(klic_key);
|
||||
|
||||
// Copy the necessary parameters.
|
||||
u8 metadata_key[0x20];
|
||||
u8 metadata_iv[0x10];
|
||||
@ -1480,7 +1485,7 @@ static bool CheckDebugSelf(fs::file& s)
|
||||
return false;
|
||||
}
|
||||
|
||||
extern fs::file decrypt_self(fs::file elf_or_self)
|
||||
extern fs::file decrypt_self(fs::file elf_or_self, u8* klic_key)
|
||||
{
|
||||
if (!elf_or_self)
|
||||
{
|
||||
@ -1506,7 +1511,7 @@ extern fs::file decrypt_self(fs::file elf_or_self)
|
||||
}
|
||||
|
||||
// Load and decrypt the SELF file metadata.
|
||||
if (!self_dec.LoadMetadata())
|
||||
if (!self_dec.LoadMetadata(klic_key))
|
||||
{
|
||||
LOG_ERROR(LOADER, "SELF: Failed to load SELF file metadata!");
|
||||
return fs::file{};
|
||||
@ -1525,3 +1530,35 @@ extern fs::file decrypt_self(fs::file elf_or_self)
|
||||
|
||||
return elf_or_self;
|
||||
}
|
||||
|
||||
extern bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key)
|
||||
{
|
||||
if (!self)
|
||||
return false;
|
||||
|
||||
self.seek(0);
|
||||
|
||||
if (self.size() >= 4 && self.read<u32>() == "SCE\0"_u32)
|
||||
{
|
||||
// Check the ELF file class (32 or 64 bit).
|
||||
bool isElf32 = IsSelfElf32(self);
|
||||
|
||||
// Start the decrypter on this SELF file.
|
||||
SELFDecrypter self_dec(self);
|
||||
|
||||
// Load the SELF file headers.
|
||||
if (!self_dec.LoadHeaders(isElf32))
|
||||
{
|
||||
LOG_ERROR(LOADER, "SELF: Failed to load SELF file headers!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load and decrypt the SELF file metadata.
|
||||
if (!self_dec.LoadMetadata(klic_key))
|
||||
{
|
||||
LOG_ERROR(LOADER, "SELF: Failed to load SELF file metadata!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
@ -410,10 +410,11 @@ public:
|
||||
fs::file MakeElf(bool isElf32);
|
||||
bool LoadHeaders(bool isElf32);
|
||||
void ShowHeaders(bool isElf32);
|
||||
bool LoadMetadata();
|
||||
bool LoadMetadata(u8* klic_key);
|
||||
bool DecryptData();
|
||||
bool DecryptNPDRM(u8 *metadata, u32 metadata_size);
|
||||
bool GetKeyFromRap(u8 *content_id, u8 *npdrm_key);
|
||||
};
|
||||
|
||||
extern fs::file decrypt_self(fs::file elf_or_self);
|
||||
extern fs::file decrypt_self(fs::file elf_or_self, u8* klic_key = nullptr);
|
||||
extern bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key = nullptr);
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "Emu/Cell/lv2/sys_process.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Crypto/unedat.h"
|
||||
#include "Crypto/unself.h"
|
||||
#include "sceNp.h"
|
||||
|
||||
logs::channel sceNp("sceNp", logs::level::notice);
|
||||
@ -48,7 +49,7 @@ s32 npDrmIsAvailable(vm::cptr<u8> k_licensee_addr, vm::cptr<char> drm_path)
|
||||
}
|
||||
|
||||
std::string k_licensee_str = "";
|
||||
std::array<u8, 0x10> k_licensee;
|
||||
std::array<u8, 0x10> k_licensee{0};
|
||||
|
||||
if (k_licensee_addr)
|
||||
{
|
||||
@ -57,29 +58,11 @@ s32 npDrmIsAvailable(vm::cptr<u8> k_licensee_addr, vm::cptr<char> drm_path)
|
||||
k_licensee[i] = *(k_licensee_addr + i);
|
||||
k_licensee_str += fmt::format("%02x", k_licensee[i]);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& enc_drm_path_local = vfs::get(enc_drm_path);
|
||||
const fs::file enc_file(vfs::get(enc_drm_path));
|
||||
|
||||
u32 magic;
|
||||
enc_file.read<u32>(magic);
|
||||
enc_file.seek(0);
|
||||
if (magic == "SCE\0"_u32) {
|
||||
sceNp.notice("npDrmIsAvailable(): Assuming file is encrypted at %s", enc_drm_path);
|
||||
//sprx
|
||||
}
|
||||
else if (magic != "NPD\0"_u32)
|
||||
{
|
||||
// for now assume its just unencrypted
|
||||
sceNp.notice("npDrmIsAvailable(): Assuming edat file is unencrypted at %s", enc_drm_path);
|
||||
return CELL_OK;
|
||||
sceNp.notice("npDrmIsAvailable(): KLicense key %s", k_licensee_str);
|
||||
}
|
||||
|
||||
sceNp.warning("npDrmIsAvailable(): Found DRM license file at %s", enc_drm_path);
|
||||
if (k_licensee_addr) {
|
||||
sceNp.notice("npDrmIsAvailable(): KLicense key %s", k_licensee_str);
|
||||
}
|
||||
|
||||
// TODO: Make more explicit what this actually does (currently it copies "XXXXXXXX" from drm_path (== "/dev_hdd0/game/XXXXXXXXX/*" assumed)
|
||||
const std::string& drm_file_dir = enc_drm_path.substr(15);
|
||||
@ -87,39 +70,67 @@ s32 npDrmIsAvailable(vm::cptr<u8> k_licensee_addr, vm::cptr<char> drm_path)
|
||||
|
||||
std::string rap_lpath = vfs::get("/dev_hdd0/home/00000001/exdata/"); // TODO: Allow multiple profiles. Use default for now.
|
||||
|
||||
auto edatkeys = fxm::get_always<EdatKeys_t>();
|
||||
|
||||
// Search for a compatible RAP file.
|
||||
if (!k_licensee_addr) {
|
||||
for (const auto& entry : fs::dir(rap_lpath))
|
||||
for (const auto& entry : fs::dir(rap_lpath))
|
||||
{
|
||||
if (entry.name.find(title_id) != -1)
|
||||
{
|
||||
if (entry.name.find(title_id) != -1)
|
||||
{
|
||||
rap_lpath += entry.name;
|
||||
break;
|
||||
}
|
||||
rap_lpath += entry.name;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rap_lpath.back() == '/')
|
||||
{
|
||||
sceNp.warning("npDrmIsAvailable(): Can't find RAP file for %s", enc_drm_path);
|
||||
edatkeys->rifKey.fill(0);
|
||||
}
|
||||
else
|
||||
edatkeys->rifKey = GetEdatRifKeyFromRapFile(fs::file{ rap_lpath });
|
||||
}
|
||||
|
||||
if (VerifyEDATHeaderWithKLicense(enc_file, enc_drm_path_local, k_licensee))
|
||||
auto npdrmkeys = fxm::get_always<LoadedNpdrmKeys_t>();
|
||||
|
||||
npdrmkeys->devKlic.fill(0);
|
||||
npdrmkeys->rifKey.fill(0);
|
||||
|
||||
if (rap_lpath.back() == '/')
|
||||
{
|
||||
edatkeys->devKlic = std::move(k_licensee);
|
||||
return CELL_OK;
|
||||
sceNp.warning("npDrmIsAvailable(): Can't find RAP file for %s", enc_drm_path);
|
||||
}
|
||||
else
|
||||
npdrmkeys->rifKey = GetEdatRifKeyFromRapFile(fs::file{ rap_lpath });
|
||||
|
||||
const std::string& enc_drm_path_local = vfs::get(enc_drm_path);
|
||||
const fs::file enc_file(enc_drm_path_local);
|
||||
|
||||
u32 magic;
|
||||
|
||||
enc_file.read<u32>(magic);
|
||||
enc_file.seek(0);
|
||||
|
||||
if (magic == "SCE\0"_u32)
|
||||
{
|
||||
if (verify_npdrm_self_headers(enc_file, k_licensee.data()))
|
||||
{
|
||||
npdrmkeys->devKlic = std::move(k_licensee);
|
||||
}
|
||||
else
|
||||
{
|
||||
sceNp.error("npDrmIsAvailable(): Failed to verify sce file %s", enc_drm_path);
|
||||
return SCE_NP_DRM_ERROR_NO_ENTITLEMENT;
|
||||
}
|
||||
|
||||
}
|
||||
else if (magic == "NPD\0"_u32)
|
||||
{
|
||||
// edata / sdata files
|
||||
|
||||
if (VerifyEDATHeaderWithKLicense(enc_file, enc_drm_path_local, k_licensee))
|
||||
{
|
||||
npdrmkeys->devKlic = std::move(k_licensee);
|
||||
}
|
||||
else
|
||||
{
|
||||
sceNp.error("npDrmIsAvailable(): Failed to verify npd file %s", enc_drm_path);
|
||||
return SCE_NP_DRM_ERROR_NO_ENTITLEMENT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sceNp.error("npDrmIsAvailable(): Failed to verify edat file %s", enc_drm_path);
|
||||
edatkeys->devKlic.fill(0);
|
||||
edatkeys->rifKey.fill(0);
|
||||
return SCE_NP_DRM_ERROR_FORMAT;
|
||||
// for now assume its just unencrypted
|
||||
sceNp.notice("npDrmIsAvailable(): Assuming npdrm file is unencrypted at %s", enc_drm_path);
|
||||
}
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -286,7 +286,7 @@ error_code sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode
|
||||
file.seek(0);
|
||||
if (magic == "NPD\0"_u32)
|
||||
{
|
||||
auto edatkeys = fxm::get_always<EdatKeys_t>();
|
||||
auto edatkeys = fxm::get_always<LoadedNpdrmKeys_t>();
|
||||
auto sdata_file = std::make_unique<EDATADecrypter>(std::move(file), edatkeys->devKlic, edatkeys->rifKey);
|
||||
if (!sdata_file->ReadHeader())
|
||||
{
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "Loader/ELF.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Crypto/unedat.h"
|
||||
#include "sys_prx.h"
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
@ -19,7 +20,9 @@ s32 prx_load_module(std::string path, u64 flags, vm::ptr<sys_prx_load_module_opt
|
||||
{
|
||||
sys_prx.warning("prx_load_module(path='%s', flags=0x%llx, pOpt=*0x%x)", path.c_str(), flags, pOpt);
|
||||
|
||||
const ppu_prx_object obj = decrypt_self(fs::file(vfs::get(path)));
|
||||
const auto loadedkeys = fxm::get_always<LoadedNpdrmKeys_t>();
|
||||
|
||||
const ppu_prx_object obj = decrypt_self(fs::file(vfs::get(path)), loadedkeys->devKlic.data());
|
||||
|
||||
if (obj != elf_error::ok)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user