2017-01-25 14:46:29 +01:00
|
|
|
#include "ncchinfo.h"
|
|
|
|
#include "ncch.h"
|
|
|
|
#include "aes.h"
|
|
|
|
|
|
|
|
u32 GetNcchInfoVersion(NcchInfoHeader* info) {
|
|
|
|
if (!info->n_entries) return 0; // cannot be empty
|
|
|
|
if (info->ncch_info_version == NCCHINFO_V3_MAGIC) return 3;
|
|
|
|
else if (info->ncch_info_version == NCCHINFO_V4_MAGIC) return 4;
|
|
|
|
else return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 FixNcchInfoEntry(NcchInfoEntry* entry, u32 version) {
|
|
|
|
// convert ncchinfo if v3
|
|
|
|
if (version == 3) { // ncchinfo v3
|
|
|
|
u8* entry_data = (u8*) (entry);
|
|
|
|
memmove(entry_data + 56, entry_data + 48, 112);
|
|
|
|
memset(entry_data + 48, 0, 8); // zero out nonexistent title id
|
|
|
|
} else if (version != 4) { // !ncchinfo v4.0/v4.1/v4.2
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// poor man's UTF-16 -> UTF-8
|
|
|
|
if (entry->filename[1] == 0x00) {
|
|
|
|
for (u32 i = 1; i < (sizeof(entry->filename) / 2); i++)
|
|
|
|
entry->filename[i] = entry->filename[i*2];
|
|
|
|
}
|
|
|
|
|
|
|
|
// fix sdmc: prefix
|
|
|
|
if (memcmp(entry->filename, "sdmc:", 5) == 0)
|
|
|
|
memmove(entry->filename, entry->filename + 5, 112 - 5);
|
|
|
|
|
|
|
|
// workaround (1) for older (v4.0) ncchinfo.bin
|
|
|
|
// this combination means seed crypto rather than FixedKey
|
|
|
|
if ((entry->ncchFlag7 == 0x01) && entry->ncchFlag3)
|
|
|
|
entry->ncchFlag7 = 0x20;
|
|
|
|
|
|
|
|
// workaround (2) for older (v4.1) ncchinfo.bin
|
|
|
|
if (!entry->size_b) entry->size_b = entry->size_mb * 1024 * 1024;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-06-01 15:11:41 +02:00
|
|
|
u32 BuildNcchInfoXorpad(void* buffer, NcchInfoEntry* entry, u32 size, u32 offset) {
|
2017-01-25 14:46:29 +01:00
|
|
|
// set NCCH key
|
|
|
|
// build faux NCCH header from entry
|
|
|
|
NcchHeader ncch = { 0 };
|
|
|
|
memcpy(ncch.signature, entry->keyY, 16);
|
|
|
|
ncch.flags[3] = (u8) entry->ncchFlag3;
|
|
|
|
ncch.flags[7] = (u8) (entry->ncchFlag7 & ~0x04);
|
|
|
|
ncch.programId = ncch.partitionId = entry->titleId;
|
2017-01-30 22:06:26 +01:00
|
|
|
if (SetNcchKey(&ncch, NCCH_GET_CRYPTO(&ncch), 1) != 0)
|
2017-01-25 14:46:29 +01:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
// write xorpad
|
|
|
|
memset(buffer, 0, size);
|
|
|
|
ctr_decrypt_byte(buffer, buffer, size, offset, AES_CNT_CTRNAND_MODE, entry->ctr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|