86 lines
3.0 KiB
C

#include "ncsd.h"
#include "ncch.h"
#include "rsa.h"
#include "itcm.h"
u32 ValidateNcsdHeader(NcsdHeader* header) {
static const u8 zeroes[16] = { 0 };
if ((memcmp(header->magic, "NCSD", 4) != 0) || // check magic number
(memcmp(header->partitions_fs_type, zeroes, 8) != 0) || !header->mediaId) // prevent detection of NAND images
return 1;
u32 data_units = 0;
for (u32 i = 0; i < 8; i++) {
NcchPartition* partition = header->partitions + i;
if ((i == 0) && !partition->size) return 1; // first content must be there
else if (!partition->size) continue;
if (partition->offset < data_units)
return 1; // overlapping partitions, failed
data_units = partition->offset + partition->size;
}
if (data_units > header->size)
return 1;
return 0;
}
u32 ValidateNcsdSignature(NcsdHeader* header) {
u8 exp[4] = { 0x00, 0x01, 0x00, 0x01 };
// this will fail for non-cart NCSDs anyways, so we don't need to check
if (!RSA_setKey2048(3, (const u32*)(const void*)&ARM9_ITCM->rsaModulusCartNCSD[0], getle32(exp)) ||
!RSA_verify2048((const u32*)(const void*)&header->signature[0], (const u32*)(const void*)&((u8*)header)[0x100], 0x100))
return 1;
return 0;
}
u64 GetNcsdTrimmedSize(NcsdHeader* header) {
u32 data_units = 0;
for (u32 i = 0; i < 8; i++) {
NcchPartition* partition = header->partitions + i;
u32 partition_end = partition->offset + partition->size;
if (!partition->size) continue;
data_units = (partition_end > data_units) ? partition_end : data_units;
}
return data_units * NCSD_MEDIA_UNIT;
}
// on the fly decryptor for NCSD
u32 CryptNcsdSequential(void* data, u32 offset_data, u32 size_data, u16 crypto) {
// warning: this will only work for sequential processing
static NcsdHeader ncsd;
// fetch ncsd header from data
if ((offset_data == 0) && (size_data >= sizeof(NcsdHeader)))
memcpy(&ncsd, data, sizeof(NcsdHeader));
for (u32 i = 0; i < 8; i++) {
NcchPartition* partition = ncsd.partitions + i;
u32 offset_p = partition->offset * NCSD_MEDIA_UNIT;
u32 size_p = partition->size * NCSD_MEDIA_UNIT;
// check if partition in data
if ((offset_p >= offset_data + size_data) ||
(offset_data >= offset_p + size_p) ||
!size_p) {
continue; // section not in data
}
// determine data / offset / size
u8* data8 = (u8*)data;
u8* data_i = data8;
u32 offset_i = 0;
u32 size_i = size_p;
if (offset_p < offset_data)
offset_i = offset_data - offset_p;
else data_i = data8 + (offset_p - offset_data);
size_i = size_p - offset_i;
if (size_i > size_data - (data_i - data8))
size_i = size_data - (data_i - data8);
// decrypt ncch segment
if (CryptNcchSequential(data_i, offset_i, size_i, crypto) != 0)
return 1;
}
return 0;
}