diff --git a/build/tests/CheckDSHashTable/CheckDSHashTable.rsf b/build/tests/CheckDSHashTable/CheckDSHashTable.rsf new file mode 100644 index 00000000..4c5ccc66 --- /dev/null +++ b/build/tests/CheckDSHashTable/CheckDSHashTable.rsf @@ -0,0 +1,207 @@ +#---------------------------------------------------------------------------- +# Project: TwlSDK - include +# File: ROM-TS.rsf +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded insructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: $ +# $Rev$ +# $Author$ +#---------------------------------------------------------------------------- +# +# TWL ROM SPEC FILE +# + +Arm9 +{ + Static "$(MAKEROM_ARM9:r).TWL.FLX.sbin$(COMPSUFFIX9)" + OverlayDefs "$(MAKEROM_ARM9:r)_defs.TWL.FLX.sbin$(COMPSUFFIX9)" + OverlayTable "$(MAKEROM_ARM9:r)_table.TWL.FLX.sbin$(COMPSUFFIX9)" + Elf "$(MAKEROM_ARM9:r).tef" +} + +Arm7 +{ + Static "$(MAKEROM_ARM7_BASE:r).TWL.FLX.sbin$(COMPSUFFIX7)" + OverlayDefs "$(MAKEROM_ARM7_BASE:r)_defs.TWL.FLX.sbin$(COMPSUFFIX7)" + OverlayTable "$(MAKEROM_ARM7_BASE:r)_table.TWL.FLX.sbin$(COMPSUFFIX7)" + Elf "$(MAKEROM_ARM7_BASE:r).tef" +} + +Arm9.Ltd +{ + Static "$(MAKEROM_ARM9:r).TWL.LTD.sbin$(COMPSUFFIX9)" + OverlayDefs "$(MAKEROM_ARM9:r)_defs.TWL.LTD.sbin$(COMPSUFFIX9)" + OverlayTable "$(MAKEROM_ARM9:r)_table.TWL.LTD.sbin$(COMPSUFFIX9)" +} + +Arm7.Ltd +{ + Static "$(MAKEROM_ARM7_BASE:r).TWL.LTD.sbin$(COMPSUFFIX7)" + OverlayDefs "$(MAKEROM_ARM7_BASE:r)_defs.TWL.LTD.sbin$(COMPSUFFIX7)" + OverlayTable "$(MAKEROM_ARM7_BASE:r)_table.TWL.LTD.sbin$(COMPSUFFIX7)" +} + +Property +{ + ### + ### Settings for FinalROM + ### + #### BEGIN + # + # TITLE NAME: Your product name within 12bytes + # + #TitleName "YourAppName" + + # + # MAKER CODE: Your company ID# in 2 ascii words + # issued by NINTENDO + # + #MakerCode "00" + + # + # REMASTER VERSION: Mastering version + # + #RomVersion 0 + + # + # ROM SPEED TYPE: [MROM/1TROM/UNDEFINED] + # + RomSpeedType $(MAKEROM_ROMSPEED) + + # + # ROM SIZE: in bit [64M/128M/256M/512M/1G/2G] + # + #RomSize 128M + #RomSize 256M + + # + # ROM PADDING: TRUE if finalrom + # + #RomFootPadding TRUE + + # + # ROM HEADER TEMPLATE: Provided to every product by NINTENDO + # + #RomHeaderTemplate ./etc/rom_header.template.sbin + + # + # BANNER FILE: generated from Banner Spec File + # + #BannerFile ./etc/myGameBanner.bnr + BannerFile $(TWLSDK_ROOT)/include/twl/specfiles/default.bnr + + # + # Permit TmpJump: for TWL "ApplicationJump" function + # + #PermitTmpJump FALSE + + ### + ### Setting for TWL + ### + + # + # Digest parameters: + # + DigestParam 1024 32 + + # + # WRAM mapping: [MAP_BB_HYB/MAP_BB_LTD/MAP_TS_HYB/MAP_TS_LTD + # MAP2_BB_HYB/MAP2_BB_LTD/MAP2_TS_HYB/MAP2_TS_LTD] + # don't have to edit + # + WramMapping $(MAKEROM_WRAM_MAPPING) + + # + # Codec mode: + # don't have to edit + # + CodecMode $(MAKEROM_CODEC_MODE) + + # + # Enable Other Type Parental Controls + #OtherParentalControls FALSE + + # + # Use WiFiConnection + #WiFiConnection TRUE + + ### + #### END +} + +AppendProperty +{ + # + # Publisher : "Nintendo" + # don't have to edit + Publisher Nintendo + + # + # Application type : [USER/SYSTEM] + # don't have to edit + AppType User + + # + # launch title on the launcher : [TRUE/FALSE] + # don't have to edit + Launch TRUE + + # + # Boot allowed Media: [GameCard] + # + Media GameCard + + # + # Data only title : [TRUE/FALSE] + # don't have to edit + DataOnly FALSE + + # + # Secure title : [TRUE/FALSE] + # don't have to edit + Secure FALSE + + # + # GameCode for TitleID : Your GameCode in 4 ascii words + # + #GameCode ABCJ + + # + # Public save data size: [16K/32K/64K/128K/256K/512K/1M/2M/4M/8M] + # + #PublicSaveDataSize 32K + + # + # Private save data size: [16K/32K/64K/128K/256K/512K/1M/2M/4M/8M] + # + #PrivateSaveDataSize 16K + + # + # Enable SubBannerFile + #SubBannerFile TRUE +} + +RomSpec +{ + Offset 0x00000000 + Segment ALL + HostRoot ../../tools/MakeDSHashTable + Root /sign + File DSHashTable.bin + HostRoot D:/SRL + Root /srl +# File NA22E0.035 # 1st +# File NA22J0.024 # 2nd +# File NYZYE0.E81 # last-1 +# File NYZZJ0.L57 # last + File NYRVJ0.J30 # max number of overlaies + File NALKJ1.879 # max overlay size + File NA39J0.357 # mario kart +} diff --git a/build/tests/CheckDSHashTable/Makefile b/build/tests/CheckDSHashTable/Makefile new file mode 100644 index 00000000..530f467d --- /dev/null +++ b/build/tests/CheckDSHashTable/Makefile @@ -0,0 +1,41 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlIPL - tests - CheckDSHashTable +# File: Makefile +# +# Copyright 2008 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: $ +# $Rev$ +# $Author$ +#---------------------------------------------------------------------------- + +TARGET_PLATFORM := TWL +TARGET_FIRM := SYSTEMMENU +override TWL_ARCHGEN := LIMITED + +SRCS = main.c dht.c +LINCLUDES = include +TARGET_BIN = CheckDSHashTable.srl +ROM_SPEC = CheckDSHashTable.rsf + +include $(TWL_IPL_RED_ROOT)/build/buildtools/commondefs + +#---------------------------------------------------------------------------- + +SUBDIRS = + +#---------------------------------------------------------------------------- + +do-build: $(TARGETS) + +#---------------------------------------------------------------------------- +include $(TWLSDK_ROOT)/build/buildtools/modulerules + +#===== End of Makefile ===== diff --git a/build/tests/CheckDSHashTable/include/dht.h b/build/tests/CheckDSHashTable/include/dht.h new file mode 100644 index 00000000..0bc7fd00 --- /dev/null +++ b/build/tests/CheckDSHashTable/include/dht.h @@ -0,0 +1,40 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL - DHT + File: dht.h + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ +#ifndef _DHT_H_ +#define _DHT_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +BOOL DHT_PrepareDatabase(DHTFile* pDHT); + +const DHTDatabase* DHT_GetDatabase(const DHTFile* pDHT, const ROM_Header_Short* pROMHeader); + +BOOL DHT_CheckHashPhase1(const DHTDatabase *db, const ROM_Header_Short* pROMHeader, const void* pARM9, const void* pARM7); + +BOOL DHT_CheckHashPhase2(const DHTDatabase *db, const ROM_Header_Short* pROMHeader, FSFile* fp, void* buffer); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _DHT_H_ diff --git a/build/tests/CheckDSHashTable/src/dht.c b/build/tests/CheckDSHashTable/src/dht.c new file mode 100644 index 00000000..c50ebd69 --- /dev/null +++ b/build/tests/CheckDSHashTable/src/dht.c @@ -0,0 +1,407 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL - DHT + File: dht.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include + +#define HASH_PATH "/sign/DSHashTable.bin" + +/* + 定義すると処理時間を表示する +*/ +#define PRINT_PROFILE + +#ifdef PRINT_PROFILE +static int count; +static OSTick profile[0x10]; +#define PROFILE_INIT() (count = 0) +#define PROFILE_COUNT() (profile[count++] = OS_GetTick()) +#else +#define PROFILE_INIT() ((void)0) +#define PROFILE_COUNT() ((void)0) +#define +#endif + +static const u8 g_pubkey_DER[ 0xa2 ] = { + 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xc7, 0xf4, 0x1d, + 0x27, 0x3f, 0xe8, 0xae, 0x7f, 0x7c, 0xbc, 0x9a, 0xae, 0x09, 0x8d, 0x19, 0x26, 0x2e, 0x90, 0x04, + 0x03, 0x13, 0x93, 0xbc, 0xb2, 0xe0, 0x8b, 0x1f, 0x85, 0x48, 0xf5, 0xf6, 0x94, 0x69, 0x3e, 0x05, + 0x1b, 0x97, 0x85, 0x44, 0x6d, 0xa3, 0xcd, 0xa8, 0x01, 0xfe, 0xdc, 0x77, 0x5d, 0xd1, 0xb1, 0x36, + 0x21, 0xfc, 0x80, 0xe8, 0xa6, 0x0e, 0xde, 0x59, 0x76, 0xca, 0x96, 0xcc, 0x87, 0x4c, 0xc3, 0x90, + 0xc6, 0x3b, 0xc8, 0x17, 0x9d, 0x2d, 0xac, 0x45, 0xbc, 0xa7, 0x15, 0xb2, 0xe3, 0xd7, 0x76, 0xfa, + 0x09, 0x8c, 0x55, 0x09, 0x22, 0x95, 0x4b, 0xe7, 0xde, 0xc0, 0x82, 0xf2, 0x02, 0x1a, 0x8a, 0x42, + 0x38, 0x7f, 0xbb, 0x31, 0xd6, 0xa8, 0x36, 0xdc, 0x8d, 0x2c, 0x42, 0x56, 0x51, 0xc1, 0xa3, 0x30, + 0x21, 0x30, 0xef, 0x06, 0x72, 0x0c, 0xa6, 0x55, 0xb7, 0x4f, 0x30, 0x35, 0x1b, 0x02, 0x03, 0x01, + 0x00, 0x01 +}; + +static const u8 hmac_key[] = DHT_HMAC_KEY; + + +/* + 自家製bsearch +*/ + +static void *bsearch(const void *key, const void *base, + size_t nmemb, size_t size, + int (*compar)(const void *, const void *)) +{ + u32 left = 0; + u32 right = nmemb; + + if ( compar((u8*)base + size * (right - 1), key) < 0 ) + { + return NULL; + } + if ( compar((u8*)base + size * left, key) > 0 ) + { + return NULL; + } + + while (left <= right) + { + u32 mid = (left + right) >> 1; + const void* data = (u8*)base + size * mid; + int result = compar(data, key); +//OS_TPrintf("left = %d, mid = %d, right = %d\n", left, mid, right); + if ( !result ) + { + return (void*)data; + } + if ( result < 0 ) + { + left = mid + 1; + } + else + { + right = mid - 1; + } + } + return NULL; +} +static int CompareGameCodeAndVersion(const void* a, const void* b) +{ + return MI_CpuComp8(a, b, 5); +} + +/* +データベースを読み込む (前準備) +*/ +BOOL DHT_PrepareDatabase(DHTFile* pDHT) +{ + FSFile file; + u32 length; + s32 result; + SVCSignHeapContext pool; + u8 heap[4*1024]; + u8 md1[20]; + u8 md2[20]; + PROFILE_INIT(); + + // ファイルオープン + PROFILE_COUNT(); + if (!FS_OpenFileEx(&file, HASH_PATH, FS_FILEMODE_R)) + { + OS_TPrintf("Cannot open " HASH_PATH ".\n"); + return FALSE; + } + // ヘッダ読み込み + PROFILE_COUNT(); + result = FS_ReadFile(&file, &pDHT->header, sizeof(DHTHeader)); + if ( result != sizeof(DHTHeader) ) + { + OS_TPrintf("Cannot read the header of " HASH_PATH " (result=%d).\n", result); + return FALSE; + } + if ( pDHT->header.magic_code != DHT_MAGIC_CODE ) + { + OS_TPrintf("Invalid " HASH_PATH " magic code (magic=0x%08X).\n", pDHT->header.magic_code); + return FALSE; + } + // サイズチェック + PROFILE_COUNT(); + length = FS_GetFileLength(&file); + if ( length != sizeof(DHTHeader) + pDHT->header.nums * sizeof(DHTDatabase) ) + { + OS_TPrintf("Invalid " HASH_PATH " size (%d != %d).\n", length, sizeof(DHTHeader) + pDHT->header.nums * sizeof(DHTDatabase)); + return FALSE; + } + // databaseサイズの保存 + length = pDHT->header.nums * sizeof(DHTDatabase); + // データベース読み込み + PROFILE_COUNT(); + result = FS_ReadFile(&file, pDHT->database, (s32)length); + if ( result != length ) + { + OS_TPrintf("Cannot read the database of " HASH_PATH " (result=%d).\n", result); + return FALSE; + } + FS_CloseFile(&file); + // ファイル署名取り出し + PROFILE_COUNT(); + SVC_InitSignHeap(&pool, heap, sizeof(heap)); + SVC_DecryptSign(&pool, md1, pDHT->header.sign, &g_pubkey_DER[29]); + // ハッシュ計算 + PROFILE_COUNT(); + SVC_CalcSHA1(md2, DHT_GET_SIGN_TARGET_ADDR(&pDHT->header), DHT_GET_SIGN_TARGET_SIZE(&pDHT->header)); + // 検証 + PROFILE_COUNT(); + result = SVC_CompareSHA1(md1, md2); + if ( !result ) + { + OS_TPrintfEx("SIGN = % 20B\n", md1); + OS_TPrintfEx("HASH = % 20B\n", md2); + OS_TPrintf("Signature is not valid.\n"); + return FALSE; + } + // 結果報告 +#ifdef PRINT_PROFILE + PROFILE_COUNT(); + OS_TPrintf("\nDone to prepare the database.\n"); + OS_TPrintf("%10d msec for file open.\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0])); + OS_TPrintf("%10d msec for reading header.\n", (int)OS_TicksToMilliSeconds(profile[2]-profile[1])); + OS_TPrintf("%10d msec for size check.\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[2])); + OS_TPrintf("%10d msec for reading database.\n", (int)OS_TicksToMilliSeconds(profile[4]-profile[3])); + OS_TPrintf("%10d msec for decrypt sign.\n", (int)OS_TicksToMilliSeconds(profile[5]-profile[4])); + OS_TPrintf("%10d msec for hashing database.\n", (int)OS_TicksToMilliSeconds(profile[6]-profile[5])); + OS_TPrintf("%10d msec for comparing hash.\n", (int)OS_TicksToMilliSeconds(profile[7]-profile[6])); + OS_TPrintf("\nTotal: %10d msec.\n", (int)OS_TicksToMilliSeconds(profile[7]-profile[0])); +#endif + return TRUE; +} +/* +ROMヘッダに対応するデータベースを手に入れる +*/ +const DHTDatabase* DHT_GetDatabase(const DHTFile* pDHT, const ROM_Header_Short* pROMHeader) +{ + u8 data[5]; + DHTDatabase* db; + PROFILE_INIT(); + + // 準備 + PROFILE_COUNT(); + MI_CpuCopy8( pROMHeader->game_code, data, 4 ); + data[4] = pROMHeader->rom_version; + db = (DHTDatabase*)bsearch(data, pDHT->database, pDHT->header.nums, sizeof(DHTDatabase), CompareGameCodeAndVersion); + if ( !db ) + { + OS_TPrintf("Cannot find the database.\n"); + } +#ifdef PRINT_PROFILE + PROFILE_COUNT(); + OS_TPrintf("%10d msec for searching database.\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0])); +#endif + return db; +} +/* +ハッシュ計算 (1) +読み込み済みデータをチェックする +*/ +BOOL DHT_CheckHashPhase1(const DHTDatabase *db, const ROM_Header_Short* pROMHeader, const void* pARM9, const void* pARM7) +{ + SVCHMACSHA1Context ctx; + u8 md[20]; + BOOL result; + PROFILE_INIT(); + + // 準備 + PROFILE_COUNT(); + SVC_HMACSHA1Init(&ctx, hmac_key, sizeof(hmac_key)); + // ヘッダ + PROFILE_COUNT(); + SVC_HMACSHA1Update(&ctx, pROMHeader, DHT_DS_HEADER_SIZE); + // ARM9 Static + PROFILE_COUNT(); + SVC_HMACSHA1Update(&ctx, pARM9, pROMHeader->main_size); + // ARM7 Static + PROFILE_COUNT(); + SVC_HMACSHA1Update(&ctx, pARM7, pROMHeader->sub_size); + // 検証 + PROFILE_COUNT(); + SVC_HMACSHA1GetHash(&ctx, md); + result = SVC_CompareSHA1(db->hash[0], md); + if ( !result ) + { + OS_TPrintfEx("DB = % 20B\n", db->hash[0]); + OS_TPrintfEx("HASH = % 20B\n", md); + OS_TPrintf("%s: hash[0] is not valid.\n", __func__); + } + // 結果報告 +#ifdef PRINT_PROFILE + PROFILE_COUNT(); + OS_TPrintf("\nDone to chekc the hash (phase 1).\n"); + OS_TPrintf("%10d msec for preparing hash.\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0])); + OS_TPrintf("%10d msec for scanning header.\n", (int)OS_TicksToMilliSeconds(profile[2]-profile[1])); + OS_TPrintf("%10d msec for scanning ARM9.\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[2])); + OS_TPrintf("%10d msec for scanning ARM7.\n", (int)OS_TicksToMilliSeconds(profile[4]-profile[3])); + OS_TPrintf("%10d msec for comparing hash.\n", (int)OS_TicksToMilliSeconds(profile[5]-profile[4])); + OS_TPrintf("\nTotal: %10d msec.\n", (int)OS_TicksToMilliSeconds(profile[5]-profile[0])); +#endif + return result; +} +/* +ハッシュ計算 (2) +対象領域の読み込みとチェックを行う +FSを用いたテストの場合とCARDアプリの場合で異なる +*/ +#if 1 +// FS版 (fctx == FSFile*) +static BOOL ReadImage(void* fctx, void* dest, s32 offset, s32 length) +{ + FSFile* fp = fctx; + s32 result; + if ( !FS_SeekFile(fp, offset, FS_SEEK_SET) ) + { + OS_TPrintf("Cannot seek to the offset (%d bytes).\n", offset); + return FALSE; + } + result = FS_ReadFile(fp, dest, length); + if ( result != length ) + { + OS_TPrintf("Cannot read the data (%d bytes).\n", length); + return FALSE; + } + return TRUE; +} +#else +// CARD版 (fctx == dma no) +static BOOL ReadImage(void* fctx, void* dest, s32 offset, s32 length) +{ + u32 dma = (u32)fctx; + CARD_ReadRom(dma, (void*)offset, dest, (u32)length); + return TRUE; +} +#endif + +static BOOL ImageHMACSHA1Update(SVCHMACSHA1Context* ctx, void* fctx, s32 offset, s32 length, void* buffer) +{ + if ( !ReadImage(fctx, buffer, offset, length) ) + { + return FALSE; + } + SVC_HMACSHA1Update(ctx, buffer, (u32)length); + return TRUE; +} + +static BOOL GetOverlayInfo(int no, void* fctx, int fat_offset, int* pOffset, int* pLength) +{ + ROM_FAT fat; + if ( !ReadImage(fctx, &fat, fat_offset + no * (s32)sizeof(ROM_FAT), sizeof(ROM_FAT)) ) + { + return FALSE; + } + if ( pOffset ) + { + *pOffset = (s32)fat.top.offset; + } + if ( pLength ) + { + *pLength = (s32)(fat.bottom.offset - fat.top.offset); + } + return TRUE; +} + +BOOL DHT_CheckHashPhase2(const DHTDatabase *db, const ROM_Header_Short* pROMHeader, void* fctx, void* buffer) +{ + int overlay_nums = (int)(pROMHeader->main_ovt_size / sizeof(ROM_OVT)); + u8 md[20]; + PROFILE_INIT(); + + if ( overlay_nums ) + { + SVCHMACSHA1Context ctx; + int total_sectors; + int i; + + // 準備 + PROFILE_COUNT(); + SVC_HMACSHA1Init(&ctx, hmac_key, sizeof(hmac_key)); + // OVT + PROFILE_COUNT(); + if ( !ImageHMACSHA1Update(&ctx, fctx, (s32)pROMHeader->main_ovt_offset, (s32)pROMHeader->main_ovt_size, buffer) ) + { + OS_TPrintf("Cannot calc HMAC-SHA1 for OVT.\n"); + return FALSE; + } + // FAT + PROFILE_COUNT(); + if ( !ImageHMACSHA1Update(&ctx, fctx, (s32)pROMHeader->fat_offset, overlay_nums * (s32)sizeof(ROM_FAT), buffer) ) + { + OS_TPrintf("Cannot calc HMAC-SHA1 for %d of FAT.\n", overlay_nums); + return FALSE; + } + // 各オーバーレイ + PROFILE_COUNT(); + total_sectors = 0; + for (i = 0; i < overlay_nums; i++) + { + int max_sectors = (DHT_OVERLAY_MAX/512 - total_sectors) / (overlay_nums - i); + int offset; + int length; + if ( !GetOverlayInfo(i, fctx, (s32)pROMHeader->fat_offset, &offset, &length) ) + { + OS_TPrintf("Cannot get %d of overlay info.\n", i); + return FALSE; + } + length = (length + 511) / 512; // bytes -> sectors + if ( length > max_sectors ) + { + length = max_sectors; + } + if ( !ImageHMACSHA1Update(&ctx, fctx, offset, length * 512, buffer) ) + { + OS_TPrintf("Cannot calc HMAC-SHA1 for %d of overlay.\n", i); + return FALSE; + } + total_sectors += length; + } + // 検証 + PROFILE_COUNT(); + SVC_HMACSHA1GetHash(&ctx, md); + } + else + { + PROFILE_COUNT(); + PROFILE_COUNT(); + PROFILE_COUNT(); + PROFILE_COUNT(); + PROFILE_COUNT(); + MI_CpuClear8(md, sizeof(md)); + } + if ( !SVC_CompareSHA1(md, db->hash[1]) ) + { + OS_TPrintfEx("DB = % 20B\n", db->hash[1]); + OS_TPrintfEx("HASH = % 20B\n", md); + OS_TPrintf("%s: hash[1] is not valid.\n", __func__); + return FALSE; + } + // 結果報告 +#ifdef PRINT_PROFILE + PROFILE_COUNT(); + OS_TPrintf("\nDone to chekc the hash (phase 2).\n"); + OS_TPrintf("%10d msec for preparing hash.\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0])); + OS_TPrintf("%10d msec for scanning OVT.\n", (int)OS_TicksToMilliSeconds(profile[2]-profile[1])); + OS_TPrintf("%10d msec for scanning FAT.\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[2])); + OS_TPrintf("%10d msec for scanning every overlays.\n", (int)OS_TicksToMilliSeconds(profile[4]-profile[3])); + OS_TPrintf("%10d msec for comparing hash.\n", (int)OS_TicksToMilliSeconds(profile[5]-profile[4])); + OS_TPrintf("\nTotal: %10d msec.\n", (int)OS_TicksToMilliSeconds(profile[5]-profile[0])); +#endif + return TRUE; +} + + diff --git a/build/tests/CheckDSHashTable/src/main.c b/build/tests/CheckDSHashTable/src/main.c new file mode 100644 index 00000000..2194d15b --- /dev/null +++ b/build/tests/CheckDSHashTable/src/main.c @@ -0,0 +1,193 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL - tests - CheckDSHashTable + File: main.c + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include + +/* + このサンプルはテスト用であり、CARD関数の代わりにFS関数で + DHTライブラリが実装されている前提である +*/ + +#define ROM_PATH "/srl" + +#define DS_HASH_TABLE_NUMS 3000 +#define DS_HASH_TABLE_SIZE (sizeof(DHTHeader) + DS_HASH_TABLE_NUMS * sizeof(DHTDatabase)) + +/* + DHTファイル読み込み先 +*/ +static u8 dht_buffer[DS_HASH_TABLE_SIZE] ATTRIBUTE_ALIGN(32); +static DHTFile *const dht = (DHTFile*)dht_buffer; +/* + Phase2用バッファ +*/ +static u8 ov_buffer[DHT_OVERLAY_MAX]; + +/* + 実際にはアドレス固定 +*/ +#include +static ROM_Header_Short rom_header ATTRIBUTE_ALIGN(32); // 使うのは DHT_DS_HEADER_SIZE だけ +static u8 rom_arm9[3*1024*1024] ATTRIBUTE_ALIGN(32); +static u8 rom_arm7[1024*1024] ATTRIBUTE_ALIGN(32); +#include + + +static void VBlankIntr( void ) +{ + OS_SetIrqCheckFlag(OS_IE_V_BLANK); +} + +/* + 検証本番のうち、実際にはオーバーヘッドにならない処理 +*/ +static BOOL CheckValidation(FSFile* fp) +{ + const DHTDatabase *db; + s32 result; + + // ヘッダの読み込み + result = FS_ReadFile(fp, &rom_header, DHT_DS_HEADER_SIZE); + if ( result != DHT_DS_HEADER_SIZE ) + { + OS_TPrintf("Cannot read ROM header.\n"); + return FALSE; + } + // ARM9部分 + if ( rom_header.main_size > sizeof(rom_arm9) ) + { + OS_TPrintf("Too large main size (%d > %d).\n", rom_header.main_size, sizeof(rom_arm9)); + return FALSE; + } + if ( !FS_SeekFile(fp, (s32)rom_header.main_rom_offset, FS_SEEK_SET) ) + { + OS_TPrintf("Cannot seek to ARM9 static.\n"); + return FALSE; + } + result = FS_ReadFile(fp, rom_arm9, (s32)rom_header.main_size); + if ( result != rom_header.main_size ) + { + OS_TPrintf("Cannot read ARM9 static.\n"); + return FALSE; + } + // ARM7部分 + if ( rom_header.sub_size > sizeof(rom_arm7) ) + { + OS_TPrintf("Too large sub size (%d > %d).\n", rom_header.sub_size, sizeof(rom_arm7)); + return FALSE; + } + if ( !FS_SeekFile(fp, (s32)rom_header.sub_rom_offset, FS_SEEK_SET) ) + { + OS_TPrintf("Cannot seek to ARM7 static.\n"); + return FALSE; + } + result = FS_ReadFile(fp, rom_arm7, (s32)rom_header.sub_size); + if ( result != rom_header.sub_size ) + { + OS_TPrintf("Cannot read ARM7 static.\n"); + return FALSE; + } + + // データベースの検索 + db = DHT_GetDatabase(dht, &rom_header); + if ( !db ) + { + return FALSE; + } +//OS_TPrintf("FOUND: 0x%08X: %.4s(%d)\n", db, db->game_code, db->rom_version); + // ハッシュ計算 (1) - 隠蔽可能なはず + if ( !DHT_CheckHashPhase1(db, &rom_header, rom_arm9, rom_arm7) ) + { + return FALSE; + } + // ハッシュ計算 (2) - 隠蔽は難しいか + if ( !DHT_CheckHashPhase2(db, &rom_header, fp, ov_buffer) ) + { + return FALSE; + } + + return TRUE; +} + +void TwlMain(void) +{ + OS_Init(); + OS_InitTick(); + + (void)OS_EnableIrq(); + (void)OS_EnableInterrupts(); + + // 割り込み許可---------------------------- + (void)OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr); + (void)OS_EnableIrqMask(OS_IE_V_BLANK); + (void)GX_VBlankIntr(TRUE); + + FS_Init(FS_DMA_NOT_USE); + + // 署名ロード + if ( !DHT_PrepareDatabase(dht) ) + { + OS_TPanic("Cannot prepare the database.\n"); + } + + // 本番 + { + FSFile dir; + FSDirectoryEntryInfo info; + BOOL result; + result = FS_OpenDirectory(&dir, ROM_PATH, FS_FILEMODE_R); + if ( !result ) + { + OS_TPanic("Cannot open " ROM_PATH ".\n"); + } + while ( FS_ReadDirectory(&dir, &info) ) + { + FSFile file; + OSTick begin; + char path[FS_ENTRY_LONGNAME_MAX+sizeof(ROM_PATH)+1]; + if ( info.attributes & FS_ATTRIBUTE_IS_DIRECTORY ) + { + OS_TPrintf("%s is directory.\n", info.longname); + continue; + } + STD_CopyString(path, ROM_PATH "/"); + STD_ConcatenateString(path, info.longname); + if (!FS_OpenFileEx(&file, path, FS_FILEMODE_R)) + { + OS_TPrintf("Cannot open %s.\n", path); + continue; + } + OS_TPrintf("\nTrying %s...\n", path); + begin = OS_GetTick(); + if ( !CheckValidation(&file) ) + { + OS_TPrintf("Failed. %d msec (includes loading static data).\n", (int)OS_TicksToMilliSeconds(OS_GetTick()-begin)); + } + else + { + OS_TPrintf("Success. %d msec (includes loading static data).\n", (int)OS_TicksToMilliSeconds(OS_GetTick()-begin)); + } + FS_CloseFile(&file); + } + FS_CloseDirectory(&dir); + } + + OS_TPrintf("\nDone.\n"); + OS_Terminate(); +} + diff --git a/build/tools/MakeDSHashTable/MakeDSHashTable.c b/build/tools/MakeDSHashTable/MakeDSHashTable.c new file mode 100644 index 00000000..f3b4099a --- /dev/null +++ b/build/tools/MakeDSHashTable/MakeDSHashTable.c @@ -0,0 +1,592 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL - tools - MakeDSHashTable + File: MakeDSHashTable.c + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define TARGET_DIR "." +#define OUTPUT_FILE "DSHashTable.bin" + +const BOOL DebugMode = TRUE; // acsignで必要 + +// データベース署名用秘密鍵 +const u8 g_privKey_DER[ 0x261 ] = { + 0x30, 0x82, 0x02, 0x5d, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xc7, 0xf4, 0x1d, 0x27, 0x3f, + 0xe8, 0xae, 0x7f, 0x7c, 0xbc, 0x9a, 0xae, 0x09, 0x8d, 0x19, 0x26, 0x2e, 0x90, 0x04, 0x03, 0x13, + 0x93, 0xbc, 0xb2, 0xe0, 0x8b, 0x1f, 0x85, 0x48, 0xf5, 0xf6, 0x94, 0x69, 0x3e, 0x05, 0x1b, 0x97, + 0x85, 0x44, 0x6d, 0xa3, 0xcd, 0xa8, 0x01, 0xfe, 0xdc, 0x77, 0x5d, 0xd1, 0xb1, 0x36, 0x21, 0xfc, + 0x80, 0xe8, 0xa6, 0x0e, 0xde, 0x59, 0x76, 0xca, 0x96, 0xcc, 0x87, 0x4c, 0xc3, 0x90, 0xc6, 0x3b, + 0xc8, 0x17, 0x9d, 0x2d, 0xac, 0x45, 0xbc, 0xa7, 0x15, 0xb2, 0xe3, 0xd7, 0x76, 0xfa, 0x09, 0x8c, + 0x55, 0x09, 0x22, 0x95, 0x4b, 0xe7, 0xde, 0xc0, 0x82, 0xf2, 0x02, 0x1a, 0x8a, 0x42, 0x38, 0x7f, + 0xbb, 0x31, 0xd6, 0xa8, 0x36, 0xdc, 0x8d, 0x2c, 0x42, 0x56, 0x51, 0xc1, 0xa3, 0x30, 0x21, 0x30, + 0xef, 0x06, 0x72, 0x0c, 0xa6, 0x55, 0xb7, 0x4f, 0x30, 0x35, 0x1b, 0x02, 0x03, 0x01, 0x00, 0x01, + 0x02, 0x81, 0x80, 0x17, 0x47, 0x76, 0x75, 0x71, 0x5d, 0x57, 0xa3, 0x84, 0x14, 0x39, 0x35, 0xf5, + 0xea, 0xb5, 0x78, 0xda, 0x86, 0xed, 0xd0, 0xa5, 0xe0, 0xd7, 0x61, 0x43, 0xff, 0x2e, 0x86, 0x47, + 0xfe, 0x4a, 0xdc, 0xf0, 0x7b, 0xc6, 0x00, 0x76, 0x5d, 0x8f, 0x9f, 0xec, 0x28, 0x2f, 0x5d, 0x3c, + 0x1c, 0xd2, 0xd0, 0xdb, 0x6e, 0xf4, 0x4c, 0x74, 0xa7, 0x55, 0x6e, 0xaf, 0xe0, 0x77, 0x2d, 0xfb, + 0x5c, 0x1f, 0x27, 0x94, 0xa1, 0x64, 0x4d, 0xaa, 0x17, 0x5f, 0x96, 0x55, 0x86, 0x23, 0x94, 0xf1, + 0x46, 0x52, 0x91, 0x49, 0x8e, 0x47, 0x89, 0xf3, 0xa0, 0xe9, 0x71, 0xe4, 0x7f, 0x9a, 0x85, 0xf1, + 0x20, 0xfd, 0x71, 0xf8, 0xc0, 0x97, 0x0d, 0x23, 0x16, 0xb0, 0x80, 0x1c, 0x57, 0xf1, 0xbd, 0x6d, + 0xa0, 0x0f, 0xea, 0x34, 0xed, 0x98, 0xee, 0xf0, 0x38, 0xba, 0x92, 0x6b, 0x51, 0x21, 0xae, 0xf3, + 0x6a, 0x75, 0x91, 0x02, 0x41, 0x00, 0xf0, 0xde, 0xc2, 0x64, 0x7f, 0xdc, 0x84, 0xc5, 0xf6, 0x36, + 0x71, 0xa6, 0x12, 0x07, 0x14, 0x0c, 0xfa, 0x86, 0x4f, 0x2b, 0x37, 0xd6, 0x11, 0xdf, 0xac, 0xe7, + 0xe6, 0xd3, 0x4c, 0x0c, 0xff, 0x70, 0x5f, 0x75, 0x18, 0x5d, 0xd4, 0xee, 0x25, 0xda, 0x66, 0xac, + 0xe1, 0x51, 0x59, 0xe4, 0xc5, 0xcb, 0x6a, 0x87, 0xa6, 0x2e, 0x19, 0xb0, 0xca, 0x44, 0x4c, 0xac, + 0xbf, 0x48, 0x2c, 0xb6, 0x6b, 0xc5, 0x02, 0x41, 0x00, 0xd4, 0x83, 0x68, 0x59, 0x55, 0x37, 0x8b, + 0xab, 0xa1, 0x10, 0xbb, 0xc2, 0xac, 0x91, 0x69, 0x1a, 0x3b, 0x19, 0xd5, 0x11, 0xa0, 0x06, 0x8b, + 0xcd, 0x35, 0xc7, 0x26, 0x19, 0xe4, 0xd3, 0xf0, 0xb9, 0xa6, 0x98, 0xe4, 0xf2, 0xaf, 0x81, 0x08, + 0x44, 0x90, 0xb8, 0x25, 0x54, 0x22, 0x6f, 0xe6, 0x34, 0xfb, 0x84, 0x8f, 0x80, 0x4e, 0x13, 0xee, + 0xe7, 0x6d, 0xda, 0xf4, 0x71, 0x83, 0x75, 0xcb, 0x5f, 0x02, 0x40, 0x2e, 0x3e, 0x36, 0x07, 0xe1, + 0x5c, 0x4e, 0xc9, 0x4a, 0xb9, 0xad, 0x1b, 0xfa, 0xfe, 0x0c, 0xe5, 0x68, 0xfb, 0x7c, 0x1b, 0x89, + 0xfe, 0xb9, 0x33, 0xbe, 0x18, 0x4f, 0x82, 0x65, 0x69, 0x61, 0x69, 0x0b, 0x8a, 0x89, 0x81, 0x0a, + 0x2e, 0x26, 0x6a, 0x45, 0xa8, 0x0f, 0x21, 0xf5, 0x26, 0x2c, 0xab, 0x1e, 0xea, 0xa8, 0x06, 0xd5, + 0xbb, 0xd1, 0x39, 0x47, 0x97, 0x2a, 0xaa, 0x0a, 0x9b, 0x83, 0x19, 0x02, 0x41, 0x00, 0xad, 0x53, + 0x70, 0x2c, 0x4c, 0x40, 0xbd, 0x7e, 0x02, 0x23, 0xef, 0xbf, 0xdb, 0x97, 0xcd, 0xad, 0x43, 0x3e, + 0xd2, 0x75, 0x49, 0x9b, 0x8d, 0x32, 0x96, 0x06, 0x13, 0xa1, 0x52, 0xed, 0x39, 0x8d, 0x71, 0xbf, + 0x8a, 0x1c, 0x15, 0xe0, 0x9b, 0xa9, 0xb0, 0x8f, 0x40, 0x82, 0xda, 0x83, 0x81, 0xb2, 0xfc, 0xe1, + 0x25, 0x59, 0x74, 0x54, 0xf5, 0xa9, 0x74, 0x03, 0xfd, 0x13, 0x08, 0x31, 0x6e, 0xe9, 0x02, 0x41, + 0x00, 0xa9, 0xfa, 0xfc, 0x14, 0x12, 0x56, 0xf5, 0x27, 0xe7, 0xe6, 0x9e, 0x21, 0x21, 0xbc, 0x78, + 0x30, 0xf8, 0xdc, 0x2a, 0xca, 0xbf, 0x5f, 0x2a, 0x48, 0x5b, 0x63, 0xe3, 0x55, 0xde, 0xb8, 0x96, + 0x04, 0x2d, 0xfb, 0xda, 0x88, 0x74, 0x68, 0x7f, 0xb3, 0x69, 0xef, 0xe7, 0x7d, 0x7a, 0x6c, 0x0b, + 0x07, 0x7f, 0x1b, 0x8e, 0xc1, 0xa7, 0x8a, 0xdb, 0x20, 0x6c, 0xea, 0xe9, 0xda, 0x88, 0x14, 0x6e, + 0x95 +}; + +/* + 自家製scandir +*/ +static int alphasort( const struct dirent** a, const struct dirent** b ) +{ + return strcoll((*a)->d_name, (*b)->d_name); +} + +static int scandir( const char* path, struct dirent ***plist, int (*filter)( const struct dirent* ), int(*compar)( const struct dirent**, const struct dirent** ) ) +{ + int nums; + DIR* dp; + struct dirent* entry; + + chdir(path); + if ( !(dp = opendir( "." )) ) + { + printf("Failed to open the target directory \"%s\".\n", path); + return -1; + } + if ( !plist || !compar ) + { + printf("plist = %p, compar = %p\n", plist, compar); + return -1; + } + + *plist = NULL; + nums = 0; + + while ( (entry = readdir( dp )) != NULL ) + { + if (filter && filter(entry) == 0) + { + continue; + } + *plist = realloc(*plist, ++nums * sizeof(struct dirent*)); + if ( !(*plist) ) + { + printf("Failed to realloc %d bytes.\n", nums * sizeof(struct dirent*)); + return -1; + } + (*plist)[nums-1] = malloc(sizeof(struct dirent)); + memcpy((*plist)[nums-1], entry, sizeof(struct dirent)); + } + closedir( dp ); + if ( nums && *plist && compar ) + { + qsort( *plist, nums, sizeof(struct dirent*), (int(*)(const void *, const void *))compar ); + } + return nums; +} +/* + 個別版HMAC-SHA1 +*/ +typedef struct HMACSHA1Context +{ + SHA1Context sha1_ctx; + u8 key[64]; + u32 keylen; +} +HMACSHA1Context; + +void HMACSHA1Init( HMACSHA1Context *ctx, const void *key, u32 keylen ) +{ + u8 ipad[64]; + int i; + + if ( ctx == NULL || ( keylen > 0 && key == NULL ) ) // key == NULL && keylen == 0 を認める + return; // FAILED + + /* 鍵がブロック長よりも長い場合、ハッシュ値を鍵とする. */ + if ( keylen > 64 ) + { + SHA1Context sha1_ctx; + SHA1Reset( &sha1_ctx ); + SHA1Input( &sha1_ctx, key, keylen ); + SHA1Result( &sha1_ctx, ctx->key ); + ctx->keylen = 20; + } + else + { + memcpy( ctx->key, key, keylen ); + ctx->keylen = keylen; + } + /* 鍵とipadのXOR */ + for ( i = 0; i < ctx->keylen; i++ ) + { + ipad[i] = (u8)(ctx->key[i] ^ 0x36); + } + /* 鍵のパディング部分とipadのXOR */ + for ( ; i < 64; i++ ) + { + ipad[i] = 0x00 ^ 0x36; + } + + /* メッセージとの結合とハッシュ値の計算 */ + SHA1Reset( &ctx->sha1_ctx ); + SHA1Input( &ctx->sha1_ctx, ipad, 64 ); +} + +void HMACSHA1Update( HMACSHA1Context *ctx, const void *data, u32 len ) +{ +/* + if ( ctx == NULL || ( len > 0 && data == NULL ) ) + return; // FAILED + if ( len == 0 && data == NULL ) // 何もすることはない + return; // SUCCESS +*/ + if ( ctx == NULL || len == 0 || data == NULL ) // void型なのでまとめる + return; + + /* メッセージとの結合とハッシュ値の計算 */ + SHA1Input( &ctx->sha1_ctx, data, len ); +} + +void HMACSHA1GetHash( HMACSHA1Context *ctx, u8* md ) +{ + u8 opad[64]; + u8 temp[20]; + int i; + + if ( ctx == NULL || md == NULL ) + return; // FAILED + + /* メッセージとの結合とハッシュ値の計算 */ + SHA1Result( &ctx->sha1_ctx, temp ); + + /* 鍵とopadのXOR */ + for ( i = 0; i < ctx->keylen; i++ ) + { + opad[i] = (u8)(ctx->key[i] ^ 0x5c); + } + /* 鍵のパディング部分とopadのXOR */ + for ( ; i < 64; i++ ) + { + opad[i] = 0x00 ^ 0x5c; + } + /* ハッシュ値との結合とハッシュ値の計算 */ + SHA1Reset( &ctx->sha1_ctx ); + SHA1Input( &ctx->sha1_ctx, opad, 64 ); + SHA1Input( &ctx->sha1_ctx, temp, 20 ); + SHA1Result( &ctx->sha1_ctx, md ); +} + +/* + シーク済みfpからsize分をHMAC-SHA1計算 +*/ +#define BUFSIZE 0x1000 +static BOOL FileHMACSHA1( HMACSHA1Context *ctx, FILE* fp, int size ) +{ + while ( size > 0 ) + { + int len = size < BUFSIZE ? size : BUFSIZE; + u8 buffer[BUFSIZE]; + if ( fread(buffer, len, 1, fp) < 1 ) + { + return FALSE; + } + HMACSHA1Update(ctx, buffer, len); + size -= len; + } + return TRUE; +} + +/* + ROMファイルっぽいものかどうかの判定 +*/ +static int srl_filter( const struct dirent* dir ) +{ + struct stat buf; + + if ( strlen( dir->d_name ) > 11 ) + { + return 0; + } + if ( stat(dir->d_name, &buf) ) + { + printf("Cannot stat \"%s\".\n", dir->d_name); + return 0; + } + if ( S_ISDIR(buf.st_mode) ) + { + return 0; + } + if ( buf.st_size < sizeof(ROM_Header) ) + { + return 0; + } + + return 1; +} +/* + ROMヘッダhpがまともそうか判定する +*/ +static BOOL check_code( const ROM_Header_Short* hp ) +{ + if ( !isprint(hp->game_code[0]) || !isprint(hp->game_code[1]) || !isprint(hp->game_code[2]) || !isprint(hp->game_code[3]) + || !isprint(hp->maker_code[0]) || !isprint(hp->maker_code[1]) ) + { + return FALSE; + } + return TRUE; +} +/* + ROMヘッダhpからオーバーレイのサイズを計算する +*/ +static int get_overlay_nums( const ROM_Header_Short* hp ) +{ + return hp->main_ovt_size / sizeof(struct ROM_OVT); +} +/* + ROMヘッダhpからオーバーレイのサイズを計算する +*/ +static BOOL get_overlay_info( FILE* fp, int offset, int no, int* pOff, int* pLen ) +{ + struct ROM_FAT fat; + if ( !fp ) + { + return FALSE; + } + if ( fseek( fp, offset + no * sizeof(ROM_FAT), SEEK_SET ) ) + { + printf("Cannot seek No.%d of FAT\n", no); + return FALSE; + } + if ( fread( &fat, sizeof(struct ROM_FAT), 1, fp ) < 1 ) + { + printf("Cannot read No.%d of FAT\n", no); + return FALSE; + } + if ( pOff ) + { + *pOff = fat.top.offset; + } + if ( pLen ) + { + *pLen = fat.bottom.offset - fat.top.offset; + } + return TRUE; +} + + +/* + filenameを解析して結果をfoutに書き出す +*/ +static BOOL output_hash( FILE* fout, const char* filename ) +{ + FILE* fin = fopen(filename, "rb"); + ROM_Header_Short header; + DHTDatabase db; + HMACSHA1Context ctx; + const u8 key[] = DHT_HMAC_KEY; + int nums; + + if ( !fin ) + { + printf("Cannot open the target file \"%s\".\n", filename); + return FALSE; + } + // まずヘッダを読む + if ( fread( &header, sizeof(ROM_Header_Short), 1, fin ) < 1 ) + { + fseek( fin, 0, SEEK_SET ); + printf("Cannot read the target file \"%s\". %d bytes only.\n", filename, fread( &header, 1, sizeof(ROM_Header_Short), fin )); + fclose(fin); + return FALSE; + } + // DSのROMか簡易チェック + if ( !check_code( &header ) ) + { + fclose(fin); + return FALSE; + } + + // db clear + memset(&db, 0, sizeof(db)); + memcpy(db.game_code, header.game_code, sizeof(db.game_code)); + db.rom_version = header.rom_version; + + // ハッシュ準備 (その1) + HMACSHA1Init( &ctx, key, sizeof(key) ); + + // ヘッダのハッシュ計算 + HMACSHA1Update( &ctx, (u8*)&header, DHT_DS_HEADER_SIZE ); + + // ARM9の読み込み + fseek(fin, header.main_rom_offset, SEEK_SET); + if ( !FileHMACSHA1( &ctx, fin, header.main_size ) ) + { + printf("Cannot read the ARM9 Static for %.4s(%x).\n", header.game_code, header.rom_version); + fclose(fin); + return FALSE; + } + + // ARM7の読み込み + fseek(fin, header.sub_rom_offset, SEEK_SET); + if ( !FileHMACSHA1( &ctx, fin, header.sub_size ) ) + { + printf("Cannot read the ARM7 Static for %.4s(%x).\n", header.game_code, header.rom_version); + fclose(fin); + return FALSE; + } + + // ハッシュ計算 (その1) + HMACSHA1GetHash( &ctx, db.hash[0] ); + + // オーバーレイ編 + nums = get_overlay_nums(&header); + if (nums) + { + int i; + int total_sectors; + + // ハッシュ準備 (その2) + HMACSHA1Init( &ctx, key, sizeof(key) ); + + // OVTの読み込み + fseek(fin, (long)header.main_ovt_offset, SEEK_SET); + if ( !FileHMACSHA1( &ctx, fin, header.main_ovt_size ) ) + { + printf("Cannot read the OVT for %.4s(%x).\n", header.game_code, header.rom_version); + fclose(fin); + return FALSE; + } + + // FAT(オーバーレイ部分)の読み込み + fseek(fin, (long)header.fat_offset, SEEK_SET); + if ( !FileHMACSHA1( &ctx, fin, nums * sizeof(ROM_FAT) ) ) + { + printf("Cannot read the part of FAT for %.4s(%x).\n", header.game_code, header.rom_version); + fclose(fin); + return FALSE; + } + + // 各オーバーレイの読み込み + total_sectors = 0; + for (i = 0; i < nums; i++) + { + int max_sectors = (DHT_OVERLAY_MAX/512 - total_sectors) / (nums-i); + int offset; + int length; + if ( !get_overlay_info( fin, (long)header.fat_offset, i, &offset, &length ) ) + { + printf("Cannot get overlay info No.%d for %.4s(%x).\n", i, header.game_code, header.rom_version); + fclose(fin); + return FALSE; + } + length = (length + 511) / 512; // bytes -> sectors + if ( length > max_sectors ) + { + length = max_sectors; + } + fseek(fin, offset, SEEK_SET); + if ( !FileHMACSHA1( &ctx, fin, length*512 ) ) + { + printf("Cannot read the overlay No.%d for %.4s(%x).\n", i, header.game_code, header.rom_version); + fclose(fin); + return FALSE; + } + total_sectors += length; + if (total_sectors > DHT_OVERLAY_MAX/512) + { + printf("PROGRAM ERROR!!\n"); + exit(1); + } + } + + // ハッシュ計算 (その2) + HMACSHA1GetHash( &ctx, db.hash[1] ); + } + else + { + memset(db.hash[1], 0, 20); + } + fclose(fin); + + // 書き込み + if ( fwrite(&db, sizeof(db), 1, fout) < 1 ) + { + printf("Cannot write the DHTDatabase for %.4s(%x).\n", header.game_code, header.rom_version); + return FALSE; + } + + return TRUE; +} +/* + ヘッダをfoutに書き出す +*/ +static BOOL output_header( FILE* fp, int nums ) +{ + DHTHeader header; + header.magic_code = DHT_MAGIC_CODE; + header.nums = nums; + if (nums) + { + SHA1Context ctx; + u8 hash[20]; + u8 sign[128]; + int size = sizeof(DHTDatabase) * nums; + + printf("Total hash size: %d bytes.\n", nums * sizeof(DHTDatabase)); + if ( SHA1Reset( &ctx ) ) + { + printf("Cannot reset SHA1 context.\n"); + return FALSE; + } + SHA1Input(&ctx, (u8*)&header.nums, sizeof(header.nums)); + fseek(fp, sizeof(DHTHeader), SEEK_SET); + while (size > 0) + { + int len = size < BUFSIZE ? size : BUFSIZE; + u8 buffer[BUFSIZE]; + if ( fread(buffer, len, 1, fp) < 1 ) + { + printf("Cannot calc SHA1 the while file.\n"); + return FALSE; + } + SHA1Input(&ctx, buffer, len); + size -= len; + } + if ( SHA1Result( &ctx, hash ) ) + { + printf("Cannot get SHA1 result for the whole file.\n"); + return FALSE; + } + if( !ACSign_Encrypto( sign, g_privKey_DER, hash, sizeof(hash) ) ) + { + printf("Cannot get signature.\n"); + return FALSE; + } + memcpy(header.sign, sign, 128); + } + else + { + memset(header.sign, 0, 128); + } + rewind(fp); + if (fwrite(&header, sizeof(header), 1, fp) < 1) + { + printf("Cannot write the header. %d bytes only.\n", fwrite( &header, 1, sizeof(header), fp )); + return FALSE; + } + return TRUE; +} +/* + CSVファイルを作成する +*/ +static BOOL make_hash( const char* path ) +{ + struct dirent **namelist; + int file_nums; + int i; + FILE* fp; + + if ( !path ) + { + return FALSE; + } + + // 出力ファイルの作成 + fp = fopen( OUTPUT_FILE, "w+b" ); + if ( !fp ) + { + printf("Cannot open the output file \"./%s\".\n", OUTPUT_FILE); + return FALSE; + } + printf("Ouptput file: ./%s\n", OUTPUT_FILE); + + // ファイルリストの取得 + file_nums = scandir( path, &namelist, srl_filter, alphasort ); + if ( file_nums <= 0 ) + { + printf("No target file.\n"); + fclose(fp); + return FALSE; + } + printf("Found %d files.\n", file_nums); + + // 仮ヘッダ作成 + output_header( fp, 0 ); + + // ファイル解析&出力 + for ( i = 0; i < file_nums; i++ ) + { + output_hash( fp, namelist[i]->d_name ); + free( namelist[i] ); + if ( i % 500 == 0) printf("\n"); + if ( i % 10 == 0) printf("."); + } + free( namelist ); + printf("\n\n"); + + // 本ヘッダ作成 + output_header( fp, file_nums ); + + fclose( fp ); + return TRUE; +} + +int main( int argc, char** argv ) +{ + printf("\n"); + + if (argc == 2 && argv[1] ) + { + make_hash(argv[1]); + } + else + { + make_hash(TARGET_DIR); + } + + printf("\nDone.\n"); + + return 0; +} diff --git a/build/tools/MakeDSHashTable/Makefile b/build/tools/MakeDSHashTable/Makefile new file mode 100644 index 00000000..79910d00 --- /dev/null +++ b/build/tools/MakeDSHashTable/Makefile @@ -0,0 +1,61 @@ +#! make -f +#--------------------------------------------------------------------------- +# Project: TwlIPL - tools - MakeDSHashTalbe +# File: Makefile +# +# Copyright 2008 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: $ +# $Rev$ +# $Author$ +#--------------------------------------------------------------------------- + +TARGET_PLATFORM = TWL +TARGET_FIRM = SYSTEMMENU + +SUBDIRS = + +include $(TWL_IPL_RED_ROOT)/build/buildtools/commondefs + +TARGETS = MakeDSHashTable.exe + +SOURCES = MakeDSHashTable.c +OBJECTS = $(SOURCES:.c=.o) + +LIBDIR = $(ROOT)/build/tools/makerom.TWL + +LIBACSIGN = $(LIBDIR)/acsign/lib/X86/libacsign_x86.a +LIBDIGEST = $(LIBDIR)/digest/lib/X86/libdigest_x86.a + +MACROS = -I$(LIBDIR) \ + -I$(ROOT)/include \ + -I$(SYSMENU_ROOT)/include + +INSTALL_DIR = $(SYSMENU_INSTALL_TOOLSDIR)/bin +INSTALL_TARGETS = $(TARGETS) + +LDIRT_CLEAN = depend $(OBJECTS) + +include $(TWLSDK_ROOT)/build/buildtools/twl/modulerules.x86 + +#---------------------------------------------------------------------------- +# build +#---------------------------------------------------------------------------- +do-build: $(TARGETS) + +$(TARGETS): $(OBJECTS) $(LIBACSIGN) $(LIBDIGEST) + $(CC_X86) $+ -o $@ + +depend: $(SOURCES) + -@ $(RM) depend + -@ for i in $(SOURCES); do\ + $(CC_X86) $(MACROS) -MM -w -DSDK_WIN32 $(WARNING) -I. -c -I$(TWL_INCDIR) $$i >> depend;\ + done + +-include depend diff --git a/include/sysmenu/dht/dht.h b/include/sysmenu/dht/dht.h new file mode 100644 index 00000000..db5dbb97 --- /dev/null +++ b/include/sysmenu/dht/dht.h @@ -0,0 +1,84 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL - DHT + File: dht.h + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ +#ifndef SYSMENU_DHT_H_ +#define SYSMENU_DHT_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*---------------------------------------------------------------------------* + Name: DHT_PrepareDatabase + + Description: 全データベースを読み込む + + Arguments: pDHT 全データベースの格納先 + + Returns: 成功すればTRUE + *---------------------------------------------------------------------------*/ +BOOL DHT_PrepareDatabase(DHTFile* pDHT); + +/*---------------------------------------------------------------------------* + Name: DHT_GetDatabase + + Description: ROMヘッダに対応するデータベースを検索する + + Arguments: pDHT 全データベースの格納先 + pROMHeader 対象となるROMヘッダ格納先 + + Returns: 対象データベースへのポインタ + *---------------------------------------------------------------------------*/ +const DHTDatabase* DHT_GetDatabase(const DHTFile* pDHT, const ROM_Header_Short* pROMHeader); + +/*---------------------------------------------------------------------------* + Name: DHT_CheckHashPhase1 + + Description: ROMヘッダおよびARM9/ARM7スタティック領域の検証 + + Arguments: db 対象データベースへのポインタ + pROMHeader 対象となるROMヘッダ格納先 + pARM9 対象となるARM9スタティック格納先 + pARM7 対象となるARM7スタティック格納先 + + Returns: 問題なければTRUE + *---------------------------------------------------------------------------*/ +BOOL DHT_CheckHashPhase1(const DHTDatabase *db, const ROM_Header_Short* pROMHeader, const void* pARM9, const void* pARM7); + +/*---------------------------------------------------------------------------* + Name: DHT_CheckHashPhase2 + + Description: オー馬齢領域の検証 + + Arguments: db 対象データベースへのポインタ + pROMHeader 対象となるROMヘッダ格納先 + fctx (FS版) FSFile構造体へのポインタ + (CARD版) dma番号をvoid*にキャストしたもの + buffer 本APIで使用するワーク (DHT_OVERLAY_MAXだけ必要) + + Returns: 問題なければTRUE + *---------------------------------------------------------------------------*/ +BOOL DHT_CheckHashPhase2(const DHTDatabase *db, const ROM_Header_Short* pROMHeader, void* fctx, void* buffer); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // SYSMENU_DHT_H_ diff --git a/include/sysmenu/dht/dht_format.h b/include/sysmenu/dht/dht_format.h new file mode 100644 index 00000000..b41f957b --- /dev/null +++ b/include/sysmenu/dht/dht_format.h @@ -0,0 +1,76 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL - DHT + File: dht_format.h + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: 2007-09-06$ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ +#ifndef SYSMENU_DHT_FORMAT_H_ +#define SYSMENU_DHT_FORMAT_H_ + +#define DHT_MAGIC_CODE (('N' << 0)|('D' << 8)|('H' << 16)|('T' << 24)) +#define DHT_DS_HEADER_SIZE 0x160 +#define DHT_OVERLAY_MAX (512*1024) + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct DHTHeader +{ + u32 magic_code; // fixed + u8 sign[128]; // for nums member and whole DHTDatabase array + u32 nums; // number of subsequent DHTDatabase array +} +DHTHeader; + +typedef struct DHTDatabase +{ + u8 game_code[4]; + u8 rom_version; + u8 reserved[3]; // for 4B alignment DHTDatabase array + u8 hash[2][20]; +} +DHTDatabase; + +typedef struct DHTFile +{ + DHTHeader header; + DHTDatabase database[]; +} +DHTFile; + +#define DHT_HMAC_KEY { \ + 0x61, 0xbd, 0xdd, 0x72, 0x7e, 0x72, 0xbe, 0xde, 0xad, 0x3a, 0xdf, 0x7f, 0x3d, 0x2d, 0xf7, 0xa5, \ + 0x16, 0x7e, 0xb4, 0xc9, 0x7c, 0x6c, 0x00, 0x7c, 0x57, 0xbb, 0x94, 0x8a, 0x64, 0xcd, 0x4e, 0x1c, \ + 0x51, 0x6b, 0xbd, 0xdb, 0x1d, 0xeb, 0x54, 0xe9, 0x34, 0x27, 0xf9, 0x31, 0x51, 0x5e, 0x89, 0x4e, \ + 0x7f, 0xd9, 0x7c, 0xe9, 0x92, 0x44, 0x0f, 0xef, 0x6b, 0xb6, 0x12, 0x21, 0x68, 0x88, 0xd8, 0xee \ +} + + +/* + ユーティリティ + hp: メモリ上のファイルの先頭アドレス +*/ +#define DHT_GET_SIGN_TARGET_ADDR(hp) (&((DHTHeader*)hp)->nums) +#define DHT_GET_SIGN_TARGET_SIZE(hp) (((DHTHeader*)hp)->nums * sizeof(DHTDatabase) + sizeof(u32)) + +#define DHT_GET_SIGN_TARGET_OFFSET (int)DHT_GET_SIGN_TARGET_ADDR(0) + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif //SYSMENU_DHT_FORMAT_H_