96 lines
2.9 KiB
C
Raw Normal View History

#include "boss.h"
#include "sha.h"
#include "aes.h"
// http://3dbrew.org/wiki/SpotPass#Content_Header
u32 CheckBossHash(BossHeader* boss, bool encrypted) {
2019-05-08 00:18:34 +02:00
u8 hash_area[0x14] __attribute__((aligned(4))) = { 0 };
u8 boss_sha256[0x20];
u8 l_sha256[0x20];
// calculate hash
memcpy(hash_area, ((u8*) boss) + 0x28, 0x12);
memcpy(boss_sha256, boss->hash_header, 0x20);
if (encrypted) {
CryptBoss(hash_area, 0x28, 0x12, boss);
CryptBoss(boss_sha256, 0x28 + 0x12, 0x20, boss);
}
sha_quick(l_sha256, hash_area, 0x14, SHA256_MODE);
return (memcmp(boss_sha256, l_sha256, 0x20) == 0) ? 0 : 1;
}
u32 ValidateBossHeader(BossHeader* header, u32 fsize) {
u8 boss_magic[] = { BOSS_MAGIC };
// base checks
if ((memcmp(header->magic, boss_magic, sizeof(boss_magic)) != 0) ||
(fsize && (fsize != getbe32(header->filesize))) ||
(getbe32(header->filesize) < sizeof(BossHeader)) ||
(getbe16(header->unknown0) != 0x0001) ||
(getbe16(header->cnthdr_hash_type) != 0x0002) ||
(getbe16(header->cnthdr_rsa_size) != 0x0002))
return 1;
// hash check
if ((CheckBossHash(header, false) != 0) &&
(CheckBossHash(header, true) != 0))
return 1;
return 0;
}
u32 GetBossPayloadHashHeader(u8* header, BossHeader* boss) {
memset(header, 0, BOSS_SIZE_PAYLOAD_HEADER);
memcpy(header, ((u8*) boss) + 0x15A, 0x1C);
return 0;
}
u32 CheckBossEncrypted(BossHeader* boss) {
return CheckBossHash(boss, true);
}
// on the fly de-/encryptor for BOSS
u32 CryptBoss(void* data, u32 offset, u32 size, BossHeader* boss) {
// check data area (encrypted area starts @0x28)
if (offset + size < 0x28) return 0;
else if (offset < 0x28) {
data = ((u8*)data + 0x28 - offset);
size -= 0x28 - offset;
offset = 0x28;
}
// decrypt BOSS data
u8 ctr[16] = { 0 };
memcpy(ctr, boss->ctr12, 12);
ctr[15] = 0x01;
use_aeskey(0x38);
ctr_decrypt_byte(data, data, size, offset - 0x28, AES_CNT_CTRNAND_MODE, ctr);
return 0;
}
// on the fly de-/encryptor for BOSS - sequential
u32 CryptBossSequential(void* data, u32 offset, u32 size) {
// warning: this will only work for sequential processing
// unexpected results otherwise
static BossHeader boss = { 0 };
static BossHeader* bossptr = NULL;
// fetch boss header from data
if ((offset == 0) && (size >= sizeof(BossHeader))) {
bossptr = NULL;
memcpy(&boss, data, sizeof(BossHeader));
if (((CheckBossEncrypted(&boss) == 0) &&
(CryptBoss((u8*) &boss, 0, sizeof(BossHeader), &boss) != 0)) ||
(ValidateBossHeader(&boss, 0) != 0))
return 1;
bossptr = &boss;
}
// safety check, boss pointer
if (!bossptr) return 1;
return CryptBoss(data, offset, size, bossptr);
}