Unified NPD header in unedat.h

This commit is contained in:
NicknineTheEagle 2022-03-20 15:12:59 +03:00 committed by Megamouse
parent d03fcad9bd
commit 8065dbc2e7
4 changed files with 42 additions and 48 deletions

View File

@ -647,8 +647,8 @@ void read_npd_edat_header(const fs::file* input, NPD_HEADER& NPD, EDAT_HEADER& E
memcpy(NPD.digest, &npd_header[64], 0x10); memcpy(NPD.digest, &npd_header[64], 0x10);
memcpy(NPD.title_hash, &npd_header[80], 0x10); memcpy(NPD.title_hash, &npd_header[80], 0x10);
memcpy(NPD.dev_hash, &npd_header[96], 0x10); memcpy(NPD.dev_hash, &npd_header[96], 0x10);
NPD.unk1 = swap64(*reinterpret_cast<u64*>(&npd_header[112])); NPD.activate_time = swap64(*reinterpret_cast<s64*>(&npd_header[112]));
NPD.unk2 = swap64(*reinterpret_cast<u64*>(&npd_header[120])); NPD.expire_time = swap64(*reinterpret_cast<s64*>(&npd_header[120]));
EDAT.flags = swap32(*reinterpret_cast<s32*>(&edat_header[0])); EDAT.flags = swap32(*reinterpret_cast<s32*>(&edat_header[0]));
EDAT.block_size = swap32(*reinterpret_cast<s32*>(&edat_header[4])); EDAT.block_size = swap32(*reinterpret_cast<s32*>(&edat_header[4]));

View File

@ -43,8 +43,8 @@ struct NPD_HEADER
u8 digest[0x10]; u8 digest[0x10];
u8 title_hash[0x10]; u8 title_hash[0x10];
u8 dev_hash[0x10]; u8 dev_hash[0x10];
u64 unk1; s64 activate_time;
u64 unk2; s64 expire_time;
}; };
struct EDAT_HEADER struct EDAT_HEADER

View File

@ -279,15 +279,15 @@ void ControlInfo::Load(const fs::file& f)
else if (type == 3) else if (type == 3)
{ {
npdrm.magic = Read32(f); npdrm.magic = Read32(f);
npdrm.unknown1 = Read32(f); npdrm.version = Read32(f);
npdrm.license = Read32(f); npdrm.license = Read32(f);
npdrm.type = Read32(f); npdrm.type = Read32(f);
f.read(npdrm.content_id, 48); f.read(npdrm.content_id, 48);
f.read(npdrm.digest, 16); f.read(npdrm.digest, 16);
f.read(npdrm.invdigest, 16); f.read(npdrm.title_hash, 16);
f.read(npdrm.xordigest, 16); f.read(npdrm.dev_hash, 16);
npdrm.unknown2 = Read64(f); npdrm.activate_time = Read64(f);
npdrm.unknown3 = Read64(f); npdrm.expire_time = Read64(f);
} }
} }
@ -325,15 +325,15 @@ void ControlInfo::Show() const
else if (type == 3) else if (type == 3)
{ {
self_log.notice("Magic: 0x%08x", npdrm.magic); self_log.notice("Magic: 0x%08x", npdrm.magic);
self_log.notice("Unknown1: 0x%08x", npdrm.unknown1); self_log.notice("Version: 0x%08x", npdrm.version);
self_log.notice("License: 0x%08x", npdrm.license); self_log.notice("License: 0x%08x", npdrm.license);
self_log.notice("Type: 0x%08x", npdrm.type); self_log.notice("Type: 0x%08x", npdrm.type);
self_log.notice("ContentID: %s", npdrm.content_id); self_log.notice("ContentID: %s", npdrm.content_id);
self_log.notice("Digest: %s", npdrm.digest); self_log.notice("Digest: %s", npdrm.digest);
self_log.notice("Inverse digest: %s", npdrm.invdigest); self_log.notice("Inverse digest: %s", npdrm.title_hash);
self_log.notice("XOR digest: %s", npdrm.xordigest); self_log.notice("XOR digest: %s", npdrm.dev_hash);
self_log.notice("Unknown2: 0x%llx", npdrm.unknown2); self_log.notice("Activation time: 0x%llx", npdrm.activate_time);
self_log.notice("Unknown3: 0x%llx", npdrm.unknown3); self_log.notice("Expiration time: 0x%llx", npdrm.expire_time);
} }
} }
@ -1062,47 +1062,37 @@ void SELFDecrypter::ShowHeaders(bool isElf32)
bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size) bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
{ {
aes_context aes; aes_context aes;
ControlInfo *ctrl = NULL;
u8 npdrm_key[0x10]; u8 npdrm_key[0x10];
u8 npdrm_iv[0x10]; u8 npdrm_iv[0x10];
// Parse the control info structures to find the NPDRM control info.
for(unsigned int i = 0; i < ctrlinfo_arr.size(); i++)
{
if (ctrlinfo_arr[i].type == 3)
{
ctrl = &ctrlinfo_arr[i];
break;
}
}
// Check if we have a valid NPDRM control info structure. // Check if we have a valid NPDRM control info structure.
// If not, the data has no NPDRM layer. // If not, the data has no NPDRM layer.
if (!ctrl) const NPD_HEADER* npd = GetNPDHeader();
if (!npd)
{ {
self_log.trace("SELF: No NPDRM control info found!"); self_log.trace("SELF: No NPDRM control info found!");
return true; return true;
} }
if (ctrl->npdrm.license == 1) // Network license. if (npd->license == 1) // Network license.
{ {
// Try to find a RAP file to get the key. // Try to find a RAP file to get the key.
if (!GetKeyFromRap(ctrl->npdrm.content_id, npdrm_key)) if (!GetKeyFromRap(npd->content_id, npdrm_key))
{ {
self_log.error("SELF: Can't decrypt network NPDRM!"); self_log.error("SELF: Can't decrypt network NPDRM!");
return false; return false;
} }
} }
else if (ctrl->npdrm.license == 2) // Local license. else if (npd->license == 2) // Local license.
{ {
// Try to find a RAP file to get the key. // Try to find a RAP file to get the key.
if (!GetKeyFromRap(ctrl->npdrm.content_id, npdrm_key)) if (!GetKeyFromRap(npd->content_id, npdrm_key))
{ {
self_log.error("SELF: Can't find RAP file for NPDRM decryption!"); self_log.error("SELF: Can't find RAP file for NPDRM decryption!");
return false; return false;
} }
} }
else if (ctrl->npdrm.license == 3) // Free license. else if (npd->license == 3) // Free license.
{ {
// Use klicensee if available. // Use klicensee if available.
if (key_v.GetKlicenseeKey() != nullptr) if (key_v.GetKlicenseeKey() != nullptr)
@ -1130,6 +1120,20 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
return true; return true;
} }
const NPD_HEADER* SELFDecrypter::GetNPDHeader() const
{
// Parse the control info structures to find the NPDRM control info.
for (const ControlInfo& info : ctrlinfo_arr)
{
if (info.type == 3)
{
return &info.npdrm;
}
}
return nullptr;
}
bool SELFDecrypter::LoadMetadata(u8* klic_key) bool SELFDecrypter::LoadMetadata(u8* klic_key)
{ {
aes_context aes; aes_context aes;
@ -1288,14 +1292,14 @@ fs::file SELFDecrypter::MakeElf(bool isElf32)
return e; return e;
} }
bool SELFDecrypter::GetKeyFromRap(u8* content_id, u8* npdrm_key) bool SELFDecrypter::GetKeyFromRap(const char* content_id, u8* npdrm_key)
{ {
// Set empty RAP key. // Set empty RAP key.
u8 rap_key[0x10]; u8 rap_key[0x10];
memset(rap_key, 0, 0x10); memset(rap_key, 0, 0x10);
// Try to find a matching RAP file under exdata folder. // Try to find a matching RAP file under exdata folder.
const std::string ci_str = reinterpret_cast<const char*>(content_id); const std::string ci_str = content_id;
const std::string rap_path = rpcs3::utils::get_rap_file_path(ci_str); const std::string rap_path = rpcs3::utils::get_rap_file_path(ci_str);
// Open the RAP file and read the key. // Open the RAP file and read the key.

View File

@ -7,6 +7,8 @@
#include "Utilities/File.h" #include "Utilities/File.h"
#include "util/logs.hpp" #include "util/logs.hpp"
#include "unedat.h"
LOG_CHANNEL(self_log, "SELF"); LOG_CHANNEL(self_log, "SELF");
struct AppInfo struct AppInfo
@ -85,20 +87,7 @@ struct ControlInfo
} file_digest_40; } file_digest_40;
// type 3 0x90 bytes // type 3 0x90 bytes
struct NPD_HEADER npdrm;
{
u32 magic;
u32 unknown1;
u32 license;
u32 type;
u8 content_id[48];
u8 digest[16];
u8 invdigest[16];
u8 xordigest[16];
u64 unknown2;
u64 unknown3;
} npdrm;
}; };
void Load(const fs::file& f); void Load(const fs::file& f);
@ -427,7 +416,8 @@ public:
bool LoadMetadata(u8* klic_key); bool LoadMetadata(u8* klic_key);
bool DecryptData(); bool DecryptData();
bool DecryptNPDRM(u8 *metadata, u32 metadata_size); bool DecryptNPDRM(u8 *metadata, u32 metadata_size);
static bool GetKeyFromRap(u8 *content_id, u8 *npdrm_key); const NPD_HEADER* GetNPDHeader() const;
static bool GetKeyFromRap(const char *content_id, u8 *npdrm_key);
private: private:
template<typename EHdr, typename SHdr, typename PHdr> template<typename EHdr, typename SHdr, typename PHdr>