ホワイトリストphase3, phase4実装、

仮データベース登録 (2009/03/25時点で本物)
SYSM_IGNORE_DHT_PHASE3はバナーチェックでエラーにしない、
SYSM_IGNORE_DHT_EX_NOT_FOUNDは旧データベースでもエラーにしない、
という意味

git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/TwlIPL/trunk@2767 b08762b0-b915-fc4b-9d8c-17b2551a87ff
This commit is contained in:
yutaka 2009-03-25 12:00:30 +00:00
parent 3ac6387837
commit a938401b08
13 changed files with 2764 additions and 1937 deletions

View File

@ -21,6 +21,8 @@ TWL_IPL_COMMONDEFS_ = TRUE
#FIRM_USE_PRODUCT_KEYS = TRUE
#SYSM_BUILD_FOR_DEBUGGER = TRUE
SYSM_DEV_WHITELIST_CHECK_SKIP ?= TRUE
#SYSM_IGNORE_DHT_PHASE_3 = TRUE
SYSM_IGNORE_DHT_EX_NOT_FOUND ?= TRUE
ifeq ($(TARGET_FIRM),SYSTEMMENU)
include $(TWL_IPL_RED_ROOT)/build/buildtools/commondefs.sysmenu

View File

@ -49,7 +49,8 @@ static const u8 g_pubkey_DER[ 0xa2 ] = {
0x00, 0x01
};
static const u8 hmac_key[] = DHT_HMAC_KEY;
static const u8 hmac_key[] = DHT_HMAC_KEY; // for phase1, phase2
static const u8 hmac_key2[] = DHT_HMAC_KEY2; // for phase3, phase4
static DHTReadFunc imageReadFunc;
static void* imageBuffer;
@ -114,6 +115,25 @@ u32 DHT_GetDatabaseLength(const DHTFile* pDHT)
}
return sizeof(DHTHeader) + pDHT->header.nums * sizeof(DHTDatabase);
}
u32 DHT_GetDatabaseExLength(const DHTFileEx* pDHT)
{
if ( pDHT->header.magic_code != DHT_MAGIC_CODE_EX ) // magic codeチェック
{
OS_TPrintf("Invalid magic code (magic=0x%08X) [EX].\n", pDHT->header.magic_code);
return 0;
}
return sizeof(DHTHeader) + pDHT->header.nums * sizeof(DHTDatabaseEx);
}
u32 DHT_GetDatabaseAdHocLength(const DHTFileAdHoc* pDHT)
{
if ( pDHT->header.magic_code != DHT_MAGIC_CODE_ADHOC ) // magic codeチェック
{
OS_TPrintf("Invalid magic code (magic=0x%08X) [AdHoc].\n", pDHT->header.magic_code);
return 0;
}
return sizeof(DHTHeader) + pDHT->header.nums * sizeof(DHTDatabaseAdHoc);
}
static BOOL DHT_CheckDatabase(const DHTFile* pDHT)
{
SVCSignHeapContext pool;
@ -216,6 +236,219 @@ const DHTDatabase* DHT_GetDatabase(const DHTFile* pDHT, const ROM_Header_Short*
#endif
return db;
}
/*
()
*/
static BOOL DHT_CheckDatabaseEx(const DHTFileEx* pDHT)
{
SVCSignHeapContext pool;
static u8 heap[4*1024]; // avoid stack overflow
u8 md1[20];
u8 md2[20];
s32 result;
// ファイル署名取り出し
SVC_InitSignHeap(&pool, heap, sizeof(heap));
SVC_DecryptSign(&pool, md1, pDHT->header.sign, &g_pubkey_DER[29]);
// ハッシュ計算
SVC_CalcSHA1(md2, DHT_GET_SIGN_TARGET_ADDR(&pDHT->header), DHT_GET_SIGN_TARGET_SIZE_EX(&pDHT->header));
// 検証
result = SVC_CompareSHA1(md1, md2);
if ( !result )
{
OS_TPrintf("\n");
OS_TPrintfEx("SIGN = % 20B [EX]\n", md1);
OS_TPrintfEx("HASH = % 20B [EX]\n", md2);
OS_TPrintf("Signature is not valid. [EX]\n");
return FALSE;
}
return TRUE;
}
BOOL DHT_PrepareDatabaseEx(DHTFileEx* pDHT, FSFile* fp)
{
s32 result;
s32 length;
PROFILE_INIT();
if ( fp )
{
// ヘッダ読み込み
PROFILE_COUNT();
result = FS_ReadFile(fp, &pDHT->header, sizeof(DHTHeader));
if ( result != sizeof(DHTHeader) )
{
OS_TPrintf("Cannot read the DHT header (result=%d). [EX]\n", result);
return FALSE;
}
// 拡張データベース読み込み
PROFILE_COUNT();
length = (s32)DHT_GetDatabaseExLength(pDHT) - (s32)sizeof(DHTHeader); // ヘッダを除く
if ( length < 0 )
{
OS_TPrintf("Invalid DHT header. [EX]\n");
return FALSE;
}
result = FS_ReadFile(fp, pDHT->database, length);
if ( result != length )
{
OS_TPrintf("Cannot read the DHT database (result=%d). [EX]\n", result);
return FALSE;
}
}
else
{
PROFILE_COUNT();
PROFILE_COUNT();
}
// 拡張データベースの検証
PROFILE_COUNT();
result = DHT_CheckDatabaseEx(pDHT);
// 結果報告
#ifdef PRINT_PROFILE
PROFILE_COUNT();
OS_TPrintf("\nDone to prepare the database. [EX]\n");
OS_TPrintf("%10d msec for reading header. [EX]\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0]));
OS_TPrintf("%10d msec for reading database. [EX]\n", (int)OS_TicksToMilliSeconds(profile[2]-profile[1]));
OS_TPrintf("%10d msec for comparing hash. [EX]\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[2]));
OS_TPrintf("\nTotal: %10d msec. [EX]\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[0]));
#endif
return result;
}
/*
ROMヘッダに対応する拡張データベースを手に入れる
*/
const DHTDatabaseEx* DHT_GetDatabaseEx(const DHTFileEx* pDHT, const ROM_Header_Short* pROMHeader)
{
u8 data[5];
DHTDatabaseEx* db;
PROFILE_INIT();
// 準備
PROFILE_COUNT();
MI_CpuCopy8( pROMHeader->game_code, data, 4 );
data[4] = pROMHeader->rom_version;
db = (DHTDatabaseEx*)bsearch(data, pDHT->database, pDHT->header.nums, sizeof(DHTDatabaseEx), CompareGameCodeAndVersion);
if ( !db )
{
OS_TPrintf("Cannot find the database. [EX]\n");
}
#ifdef PRINT_PROFILE
PROFILE_COUNT();
OS_TPrintf("%10d msec for searching database. [EX]\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0]));
#endif
return db;
}
/*
()
*/
static BOOL DHT_CheckDatabaseAdHoc(const DHTFileAdHoc* pDHT)
{
SVCSignHeapContext pool;
static u8 heap[4*1024]; // avoid stack overflow
u8 md1[20];
u8 md2[20];
s32 result;
// ファイル署名取り出し
SVC_InitSignHeap(&pool, heap, sizeof(heap));
SVC_DecryptSign(&pool, md1, pDHT->header.sign, &g_pubkey_DER[29]);
// ハッシュ計算
SVC_CalcSHA1(md2, DHT_GET_SIGN_TARGET_ADDR(&pDHT->header), DHT_GET_SIGN_TARGET_SIZE_EX(&pDHT->header));
// 検証
result = SVC_CompareSHA1(md1, md2);
if ( !result )
{
OS_TPrintf("\n");
OS_TPrintfEx("SIGN = % 20B [AdHoc]\n", md1);
OS_TPrintfEx("HASH = % 20B [AdHoc]\n", md2);
OS_TPrintf("Signature is not valid. [AdHoc]\n");
return FALSE;
}
return TRUE;
}
BOOL DHT_PrepareDatabaseAdHoc(DHTFileAdHoc* pDHT, FSFile* fp)
{
s32 result;
s32 length;
PROFILE_INIT();
if ( fp )
{
// ヘッダ読み込み
PROFILE_COUNT();
result = FS_ReadFile(fp, &pDHT->header, sizeof(DHTHeader));
if ( result != sizeof(DHTHeader) )
{
OS_TPrintf("Cannot read the DHT header (result=%d). [AdHoc]\n", result);
return FALSE;
}
// 拡張データベース読み込み
PROFILE_COUNT();
length = (s32)DHT_GetDatabaseAdHocLength(pDHT) - (s32)sizeof(DHTHeader); // ヘッダを除く
if ( length < 0 )
{
OS_TPrintf("Invalid DHT header. [AdHoc]\n");
return FALSE;
}
result = FS_ReadFile(fp, pDHT->database, length);
if ( result != length )
{
OS_TPrintf("Cannot read the DHT database (result=%d). [AdHoc]\n", result);
return FALSE;
}
}
else
{
PROFILE_COUNT();
PROFILE_COUNT();
}
// 拡張データベースの検証
PROFILE_COUNT();
result = DHT_CheckDatabaseAdHoc(pDHT);
// 結果報告
#ifdef PRINT_PROFILE
PROFILE_COUNT();
OS_TPrintf("\nDone to prepare the database. [AdHoc]\n");
OS_TPrintf("%10d msec for reading header. [AdHoc]\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0]));
OS_TPrintf("%10d msec for reading database. [AdHoc]\n", (int)OS_TicksToMilliSeconds(profile[2]-profile[1]));
OS_TPrintf("%10d msec for comparing hash. [AdHoc]\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[2]));
OS_TPrintf("\nTotal: %10d msec. [AdHoc]\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[0]));
#endif
return result;
}
/*
ROMヘッダに対応する拡張データベースを手に入れる
*/
static const DHTDatabaseAdHoc* DHT_GetDatabaseAdHoc(const DHTFileAdHoc* pDHT, const ROM_Header_Short* pROMHeader)
{
u8 data[5];
DHTDatabaseAdHoc* db;
PROFILE_INIT();
// 準備
PROFILE_COUNT();
MI_CpuCopy8( pROMHeader->game_code, data, 4 );
data[4] = pROMHeader->rom_version;
db = (DHTDatabaseAdHoc*)bsearch(data, pDHT->database, pDHT->header.nums, sizeof(DHTDatabaseAdHoc), CompareGameCodeAndVersion);
if ( !db )
{
OS_TPrintf("Cannot find the database. [AdHoc]\n");
}
#ifdef PRINT_PROFILE
PROFILE_COUNT();
OS_TPrintf("%10d msec for searching database. [AdHoc]\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0]));
#endif
return db;
}
/*
(1)
@ -468,3 +701,141 @@ void DHT_CheckHashPhase2ExUpdate(SVCHMACSHA1Context* ctx, const void* ptr, s32 l
SVC_HMACSHA1Update(ctx, ptr, (u32)length);
}
}
/*
(3)
*/
BOOL DHT_CheckHashPhase3(const u8 *hash, const NTRBannerFile* pBanner)
{
SVCHMACSHA1Context ctx;
u8 md[20];
PROFILE_INIT();
PROFILE_COUNT();
SVC_HMACSHA1Init(&ctx, hmac_key2, sizeof(hmac_key2));
// バナーの読み込み (ヘッダ)
PROFILE_COUNT();
SVC_HMACSHA1Update(&ctx, &pBanner->h, sizeof(BannerHeader));
// バナーの読み込み (ボディ)
if (pBanner->h.version == 0)
{
OS_TPrintf("Invalid banner format.\n");
return FALSE;
}
PROFILE_COUNT();
if ( pBanner->h.version >= 1 )
{
SVC_HMACSHA1Update(&ctx, &pBanner->v1, sizeof(BannerFileV1));
}
PROFILE_COUNT();
if ( pBanner->h.version >= 2 )
{
SVC_HMACSHA1Update(&ctx, &pBanner->v2, sizeof(BannerFileV2));
}
PROFILE_COUNT();
if ( pBanner->h.version >= 3 )
{
SVC_HMACSHA1Update(&ctx, &pBanner->v3, sizeof(BannerFileV3));
}
// 検証
PROFILE_COUNT();
SVC_HMACSHA1GetHash(&ctx, md);
if ( !SVC_CompareSHA1(md, hash) )
{
OS_TPrintf("\n");
OS_TPrintfEx("DB = % 20B\n", hash);
OS_TPrintfEx("HASH = % 20B\n", md);
OS_TPrintf("%s: banner_hash is not valid.\n", __func__);
return FALSE;
}
// 結果報告
#ifdef PRINT_PROFILE
PROFILE_COUNT();
OS_TPrintf("\nDone to check the hash (phase 3).\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 V1 body.\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[2]));
OS_TPrintf("%10d msec for scanning V2 body.\n", (int)OS_TicksToMilliSeconds(profile[4]-profile[3]));
OS_TPrintf("%10d msec for scanning V3 body.\n", (int)OS_TicksToMilliSeconds(profile[5]-profile[4]));
OS_TPrintf("%10d msec for comparing hash.\n", (int)OS_TicksToMilliSeconds(profile[6]-profile[5]));
OS_TPrintf("\nTotal: %10d msec.\n", (int)OS_TicksToMilliSeconds(profile[6]-profile[0]));
#endif
return TRUE;
}
/*
(4)
*/
BOOL DHT_CheckHashPhase4(const DHTFileAdHoc* pDHT, const ROM_Header_Short* pROMHeader, DHTPhase4Work* work, DHTReadFunc func, void* arg)
{
imageBuffer = work->buffer;
imageReadFunc = func;
return DHT_CheckHashPhase4Ex(pDHT, pROMHeader, ImageHMACSHA1Update, arg);
}
BOOL DHT_CheckHashPhase4Ex(const DHTFileAdHoc* pDHT, const ROM_Header_Short* pROMHeader, DHTReadFuncEx funcEx, void* arg)
{
const DHTDatabaseAdHoc* plist;
SVCHMACSHA1Context ctx;
int i;
u8 md[20];
PROFILE_INIT();
if ( !funcEx || !pDHT || !pROMHeader )
{
return FALSE;
}
plist = DHT_GetDatabaseAdHoc(pDHT, pROMHeader);
if ( !plist )
{
return TRUE; // not found in individual list
}
// 準備
PROFILE_COUNT();
SVC_HMACSHA1Init(&ctx, hmac_key2, sizeof(hmac_key2));
for (i = 0; i < DHT_INDIVIDUAL_ENTRY_MAX; i++)
{
if (plist->entry[i].offset == 0)
{
break;
}
if ( !funcEx(&ctx, (s32)plist->entry[i].offset, (s32)plist->entry[i].length, arg) )
{
OS_TPrintf("Cannot read the phase 3 for %.4s(%x).\n", pROMHeader->game_code, pROMHeader->rom_version);
return FALSE;
}
}
// 検証
PROFILE_COUNT();
SVC_HMACSHA1GetHash(&ctx, md);
if ( !SVC_CompareSHA1(md, plist->hash) )
{
OS_TPrintf("\n");
OS_TPrintfEx("DB = % 20B\n", plist->hash);
OS_TPrintfEx("HASH = % 20B\n", md);
OS_TPrintf("%s: phase4list->hash is not valid.\n", __func__);
return FALSE;
}
// 結果報告
#ifdef PRINT_PROFILE
PROFILE_COUNT();
OS_TPrintf("\nDone to check the hash (phase 3).\n");
OS_TPrintf("%10d msec for preparing hash.\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0]));
OS_TPrintf("%10d msec for scanning regions.\n", (int)OS_TicksToMilliSeconds(profile[2]-profile[1]));
OS_TPrintf("%10d msec for comparing hash.\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[2]));
OS_TPrintf("\nTotal: %10d msec.\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[0]));
#endif
return TRUE;
}

View File

@ -62,6 +62,16 @@ include $(TWL_IPL_RED_ROOT)/build/buildtools/commondefs
ifeq ($(SYSM_DEV_WHITELIST_CHECK_SKIP),TRUE)
MACRO_FLAGS += -DDEV_WHITELIST_CHECK_SKIP
else
ifeq ($(SYSM_IGNORE_DHT_PHASE_3),TRUE)
MACRO_FLAGS += -DSYSM_IGNORE_DHT_PHASE_3
endif
ifeq ($(SYSM_IGNORE_DHT_EX_NOT_FOUND),TRUE)
MACRO_FLAGS += -DSYSM_IGNORE_DHT_EX_NOT_FOUND
endif
endif
INSTALL_TARGETS = $(TARGETS)

View File

@ -59,7 +59,7 @@
#endif
#include <sysmenu/dht/dht.h>
#define DS_HASH_TABLE_SIZE (256*1024)
#define DS_HASH_TABLE_SIZE (512*1024)
#define SYSM_TITLE_MESSAGE_ARRAY_MAX 1
@ -120,9 +120,17 @@ static u8 *s_calc_hash = NULL;
static BOOL s_b_dev = FALSE;
static BOOL s_result_phase1 = FALSE;
static DHTFile *dht = NULL;
static const u8* hash0 = NULL;
static const u8* hash1 = NULL;
static struct
{
void* buffer;
DHTFile* dht; // in buffer
DHTFileEx* dhtex; // in buffer
DHTFileAdHoc* dhtah; // in buffer
const u8* hash1;
const u8* hash2;
const u8* hash3;
}
s_dht;
// const data------------------------------------------------------------------
static const OSBootType s_launcherToOSBootType[ LAUNCHER_BOOTTYPE_MAX ] = {
@ -218,35 +226,159 @@ static BOOL GetDatabaseFilepath(char *path)
return TRUE;
}
static void PrepareDHTDatabase(void)
// open and read every database (フェーズ4があるので常に実行すること)
static BOOL PrepareDHTDatabase(void)
{
char path[256];
if ( GetDatabaseFilepath( path ) )
{
int length;
FSFile file;
if ( FS_OpenFileEx(&file, path, FS_FILEMODE_R) )
if ( s_dht.buffer )
{
#if 0 // 1 if using attach_dummyromheader
if ( FS_SeekFile(&file, sizeof(ROM_Header), FS_SEEK_SET) )
#endif
{
dht = SYSM_Alloc( DS_HASH_TABLE_SIZE );
if( dht != NULL )
{
if( DHT_PrepareDatabase(dht, &file) )
{
DC_FlushRange(dht, DHT_GetDatabaseLength(dht));
FS_CloseFile(&file);
return;
}
}
}
FS_CloseFile(&file);
}
return TRUE; // already done !?
}
MI_CpuClear8(dht, sizeof(DHTHeader));
dht = NULL;
if ( !GetDatabaseFilepath( path ) )
{
OS_TPrintf("PrepareDHTDatabase failed: DHT file is not found.\n");
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): DHT file is not found.\n" );
}
return FALSE; // database was not found
}
if ( !FS_OpenFileEx(&file, path, FS_FILEMODE_R) )
{
OS_TPrintf("PrepareDHTDatabase failed: DHT file cannot open.\n");
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): DHT file cannot open.\n" );
}
return FALSE; // cannot open the file
}
length = (int)FS_GetFileLength(&file);
if ( length > DS_HASH_TABLE_SIZE )
{
OS_TPrintf("PrepareDHTDatabase failed: DHT file size (%d) is too large.\n", length );
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): DHT file size (%d) is too large.\n", length );
}
FS_CloseFile(&file);
return FALSE; // too large
}
#if 0 // 1 if using attach_dummyromheader
if ( FS_SeekFile(&file, sizeof(ROM_Header), FS_SEEK_SET) )
{
OS_TPrintf("PrepareDHTDatabase failed: DHT file size (%d) is too small.\n", length );
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): DHT file size (%d) is too small.\n", length );
}
SYSM_Free( s_dht.buffer );
s_dht.buffer = NULL;
FS_CloseFile(&file);
return FALSE;
}
#endif
s_dht.buffer = SYSM_Alloc( (u32)length );
if ( !s_dht.buffer )
{
OS_TPrintf("PrepareDHTDatabase failed: cannot allocate %d bytes for buffer.\n", length );
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot allocate %d bytes for buffer.\n", length );
}
FS_CloseFile(&file);
return FALSE; // cannot allocate the memory
}
// 基本データベース
s_dht.dht = s_dht.buffer;
if ( sizeof(DHTHeader) != FS_ReadFile(&file, &s_dht.dht->header, sizeof(DHTHeader)) )
{
OS_TPrintf("PrepareDHTDatabase failed: cannot read DHTHeader for phase 1/2.\n" );
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot read DHTHeader for phase 1/2.\n" );
}
SYSM_Free( s_dht.buffer );
s_dht.buffer = NULL;
FS_CloseFile(&file);
return FALSE; // cannot read the file
}
length = (int)DHT_GetDatabaseLength(s_dht.dht) - (int)sizeof(DHTHeader);
if ( length < 0 || length != FS_ReadFile(&file, &s_dht.dht->database, length) )
{
OS_TPrintf("PrepareDHTDatabase failed: cannot read DHTDatabase for phase 1/2.\n" );
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot read DHTDatabase for phase 1/2.\n" );
}
s_dht.dht = NULL;
SYSM_Free( s_dht.buffer );
s_dht.buffer = NULL;
FS_CloseFile(&file);
return FALSE; // cannot read the file
}
// 拡張データベース
s_dht.dhtex = (void*)((u32)s_dht.buffer + DHT_GetDatabaseLength(s_dht.dht));
if ( sizeof(DHTHeader) != FS_ReadFile(&file, &s_dht.dhtex->header, sizeof(DHTHeader)) )
{
s_dht.dhtex = NULL;
OS_TPrintf("PrepareDHTDatabase failed: cannot read DHTHeader for phase 3.\n" );
FS_CloseFile(&file);
#ifndef SYSM_IGNORE_DHT_EX_NOT_FOUND
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot read DHTHeader for phase 3.\n" );
}
SYSM_Free( s_dht.buffer );
s_dht.buffer = NULL;
return FALSE; // cannot read the file
#else
return TRUE;
#endif
}
length = (int)DHT_GetDatabaseExLength(s_dht.dhtex) - (int)sizeof(DHTHeader);
if ( length < 0 || length != FS_ReadFile(&file, &s_dht.dhtex->database, length) )
{
s_dht.dhtex = NULL;
OS_TPrintf("PrepareDHTDatabase failed: cannot read DHTDatabaseEx for phase 3.\n" );
FS_CloseFile(&file);
#ifndef SYSM_IGNORE_DHT_EX_NOT_FOUND
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot read DHTDatabaseEx for phase 3.\n" );
}
SYSM_Free( s_dht.buffer );
s_dht.buffer = NULL;
return FALSE; // cannot read the file
#else
return TRUE;
#endif
}
// 個別対応データベース
s_dht.dhtah = (void*)((u32)s_dht.buffer + DHT_GetDatabaseExLength(s_dht.dhtex));
if ( sizeof(DHTHeader) != FS_ReadFile(&file, &s_dht.dhtah->header, sizeof(DHTHeader)) )
{
s_dht.dhtah = NULL;
OS_TPrintf("PrepareDHTDatabase failed: cannot read DHTHeader for phase 4.\n" );
FS_CloseFile(&file);
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot read DHTHeader for phase 4.\n" );
}
SYSM_Free( s_dht.buffer );
s_dht.buffer = NULL;
return FALSE; // phase 3が読めてphase4が読めないことはあり得ない
}
length = (int)DHT_GetDatabaseAdHocLength(s_dht.dhtah) - (int)sizeof(DHTHeader);
if ( length < 0 || length != FS_ReadFile(&file, &s_dht.dhtah->database, length) )
{
s_dht.dhtah = NULL;
OS_TPrintf("PrepareDHTDatabase failed: cannot read DHTDatabaseAdHoc for phase 4.\n" );
FS_CloseFile(&file);
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot read DHTDatabaseAdHoc for phase 4.\n" );
}
SYSM_Free( s_dht.buffer );
s_dht.buffer = NULL;
return FALSE; // phase 3が読めてphase4が読めないことはあり得ない
}
FS_CloseFile(&file);
return TRUE;
}
static BOOL WrapperFunc_ReadCardData(void* dest, s32 offset, s32 length, void* arg)
@ -1422,49 +1554,101 @@ static BOOL SYSMi_AuthenticateNTRCardAppHeader( TitleProperty *pBootTitle, ROM_H
OS_TPrintf( "Authenticate_Header : header TitleID check succeed.\n" );
}
// phase 4があるので常に読み込む
if ( !PrepareDHTDatabase() )
{
OS_TPrintf(" SYSMi_AuthenticateNTRCardAppHeader failed : database init error.\n");
if(!s_b_dev)
{
UTL_SetFatalError(FATAL_ERROR_WHITELIST_INITDB_FAILED);
return FALSE;
}
}
// マスタリングの有無
if( head->s.exFlags.enable_nitro_whitelist_signature )
{
// マスタリング済みNTRカードアプリの署名チェック実はTWLアプリと同じ
ret = SYSMi_AuthenticateHeaderWithSign( pBootTitle, head );
if( ret == TRUE )
{
hash0 = head->s.nitro_whitelist_phase1_digest;
hash1 = head->s.nitro_whitelist_phase2_diegst;
s_dht.hash1 = head->s.nitro_whitelist_phase1_digest;
s_dht.hash2 = head->s.nitro_whitelist_phase2_diegst;
// 新マスタリングの有無
if( head->s.exFlags.enable_nitro_extra_whitelist )
{
s_dht.hash3 = head->s.banner_digest;
}
}
}else
{
// ホワイトリスト検索
const DHTDatabase* db;
PrepareDHTDatabase();// 60msくらいなので、ここでやってしまってOKとする。
if(!dht)
if(!s_dht.dht)
{
OS_TPrintf(" Search DHT : database init Failed.\n");
if(!s_b_dev)
{
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): whitelist for phase 1/2 was not loaded.\n" );
UTL_SetFatalError(FATAL_ERROR_WHITELIST_INITDB_FAILED);
ret = FALSE;
}
}else
{
OS_TPrintf("Searching DHT for %.4s(%02X)...", head->s.game_code, head->s.rom_version);
db = DHT_GetDatabase(dht, &head->s);
db = DHT_GetDatabase(s_dht.dht, &head->s);
if ( !db )
{
OS_TPrintf(" Search DHT : Failed.\n");
if(!s_b_dev)
{
ERRORLOG_Printf( "WHITELIST_NOTFOUND (sub info): no entry for phase 1/2.\n" );
UTL_SetFatalError(FATAL_ERROR_WHITELIST_NOTFOUND);
ret = FALSE;
}
}else
{
hash0 = db->hash[0];
hash1 = db->hash[1];
s_dht.hash1 = db->hash[0];
s_dht.hash2 = db->hash[1];
ret = TRUE;
}
}
}
// ROMヘッダにバナーハッシュがない (マスタリング自体とは別枠)
if( !s_dht.hash3 )
{
// 拡張ホワイトリスト検索
const DHTDatabaseEx* db;
if(!s_dht.dhtex)
{
OS_TPrintf(" Search DHT Ex: database init Failed.\n");
if(!s_b_dev)
{
#ifndef SYSM_IGNORE_DHT_EX_NOT_FOUND
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): whitelist for phase 3 was not loaded.\n" );
UTL_SetFatalError(FATAL_ERROR_WHITELIST_INITDB_FAILED);
ret = FALSE;
#endif
}
}else
{
OS_TPrintf("Searching DHT Ex for %.4s(%02X)...", head->s.game_code, head->s.rom_version);
db = DHT_GetDatabaseEx(s_dht.dhtex, &head->s);
if ( !db )
{
OS_TPrintf(" Search DHT Ex: Failed.\n");
if(!s_b_dev)
{
ERRORLOG_Printf( "WHITELIST_NOTFOUND (sub info): no entry for phase 3.\n" );
UTL_SetFatalError(FATAL_ERROR_WHITELIST_NOTFOUND);
ret = FALSE;
}
}else
{
s_dht.hash3 = db->banner_hash;
ret = TRUE;
}
}
}
return ret;
}
@ -1475,21 +1659,23 @@ static BOOL SYSMi_AuthenticateNTRCardTitle( TitleProperty *pBootTitle)
DHTPhase2Work* p2work = NULL;
ROM_Header_Short *hs = ( ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF;
// phase1最終検証
// DHTチェックphase1
if(s_calc_hash)
{
// アプリをロードする時に計算したハッシュを検証
if( !hash0 || !SVC_CompareSHA1( (const void *)hash0, (const void *)&s_calc_hash[1 * SVC_SHA1_DIGEST_SIZE] ) )
if( !s_dht.hash1 || !SVC_CompareSHA1( (const void *)s_dht.hash1, (const void *)&s_calc_hash[1 * SVC_SHA1_DIGEST_SIZE] ) )
{
OS_TPrintf("DHT Phase1 failed: hash check failed.\n");
if(!s_b_dev) {
// デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提
ERRORLOG_Printf( "DHT_PAHSE1_FAILED (sub info): hash0Addr-%08x\n", hash0 );
if(hash0)
ERRORLOG_Printf( "DHT_PAHSE1_FAILED (sub info): hash1Addr-%08x\n", s_dht.hash1 );
if(s_dht.hash1)
{
ERRORLOG_Printf( "DHT_PAHSE1_FAILED (sub info): hash0 - %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
hash0[0], hash0[1], hash0[2], hash0[3], hash0[4], hash0[5], hash0[6], hash0[7], hash0[8], hash0[9],
hash0[10], hash0[11], hash0[12], hash0[13], hash0[14], hash0[15], hash0[16], hash0[17], hash0[18], hash0[19]);
ERRORLOG_Printf( "DHT_PAHSE1_FAILED (sub info): hash1 - %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
s_dht.hash1[0], s_dht.hash1[1], s_dht.hash1[2], s_dht.hash1[3], s_dht.hash1[4],
s_dht.hash1[5], s_dht.hash1[6], s_dht.hash1[7], s_dht.hash1[8], s_dht.hash1[9],
s_dht.hash1[10], s_dht.hash1[11], s_dht.hash1[12], s_dht.hash1[13], s_dht.hash1[14],
s_dht.hash1[15], s_dht.hash1[16], s_dht.hash1[17], s_dht.hash1[18], s_dht.hash1[19]);
ERRORLOG_Printf( "DHT_PAHSE1_FAILED (sub info): calc_hash - %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
s_calc_hash[0], s_calc_hash[1], s_calc_hash[2], s_calc_hash[3], s_calc_hash[4],
s_calc_hash[5], s_calc_hash[6], s_calc_hash[7], s_calc_hash[8], s_calc_hash[9],
@ -1515,18 +1701,75 @@ static BOOL SYSMi_AuthenticateNTRCardTitle( TitleProperty *pBootTitle)
// DHTチェックphase2
OS_TPrintf("DHT Phase2...");
p2work = SYSM_Alloc( sizeof(DHTPhase2Work) );
if ( !p2work || !hash1 || !DHT_CheckHashPhase2(hash1, hs, p2work, WrapperFunc_ReadCardData, NULL) )
if ( !p2work )
{
OS_TPrintf(" Cannot allocate DHT work area.\n");
if (!s_b_dev){
// デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提
ERRORLOG_Printf( "DHT_PAHSE2_FAILED (sub info): p2workAddr-%08x hash2Addr-%08x\n", p2work, s_dht.hash2 );
UTL_SetFatalError(FATAL_ERROR_DHT_PHASE2_FAILED);
return FALSE;
}
return TRUE;
}
if ( !s_dht.hash2 || !DHT_CheckHashPhase2(s_dht.hash2, hs, p2work, WrapperFunc_ReadCardData, NULL) )
{
OS_TPrintf(" DHT Phase2 : Failed.\n");
if(!s_b_dev){
// デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提
ERRORLOG_Printf( "DHT_PAHSE2_FAILED (sub info): p2workAddr-%08x hash1Addr-%08x\n", p2work, hash1 );
if( p2work ) SYSM_Free(p2work);
ERRORLOG_Printf( "DHT_PAHSE2_FAILED (sub info): p2workAddr-%08x hash2Addr-%08x\n", p2work, s_dht.hash2 );
SYSM_Free(p2work);
UTL_SetFatalError(FATAL_ERROR_DHT_PHASE2_FAILED);
return FALSE;
}
}
if( p2work ) SYSM_Free(p2work);
// DHTチェックphase3 (バナーチェック)
OS_TPrintf("DHT Phase3...");
if ( !s_dht.hash3 || !DHT_CheckHashPhase3(s_dht.hash3, (NTRBannerFile*)&s_card_bannerBuf) )
{
OS_TPrintf(" DHT Phase3 : Failed.\n");
if(!s_b_dev){
// デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提
ERRORLOG_Printf( "DHT_PAHSE3_FAILED (sub info): hash3Addr-%08x\n", s_dht.hash3 );
#ifndef SYSM_IGNORE_DHT_EX_NOT_FOUND
#ifndef SYSM_IGNORE_DHT_PHASE_3
SYSM_Free(p2work);
UTL_SetFatalError(FATAL_ERROR_DHT_PHASE3_FAILED);
return FALSE;
#endif
#endif
}
}
// DHTチェックphase4 (個別チェック)
OS_TPrintf("DHT Phase4...");
if ( !s_dht.dhtah )
{
OS_TPrintf(" DHT Phase4 : No database.\n");
if(!s_b_dev){
// デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提
ERRORLOG_Printf( "DHT_PAHSE4_FAILED (sub info): no database\n" );
#ifndef SYSM_IGNORE_DHT_EX_NOT_FOUND
SYSM_Free(p2work);
UTL_SetFatalError(FATAL_ERROR_DHT_PHASE4_FAILED);
return FALSE;
#endif
}
}
else if ( !DHT_CheckHashPhase4(s_dht.dhtah, hs, (DHTPhase4Work*)p2work, WrapperFunc_ReadCardData, NULL) )
{
OS_TPrintf(" DHT Phase4 : Failed.\n");
if(!s_b_dev){
// デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提
ERRORLOG_Printf( "DHT_PAHSE4_FAILED (sub info): p2workAddr-%08x\n", p2work );
SYSM_Free(p2work);
UTL_SetFatalError(FATAL_ERROR_DHT_PHASE4_FAILED);
return FALSE;
}
}
SYSM_Free(p2work);
return TRUE;
}
@ -1678,9 +1921,9 @@ static void SYSMi_AuthenticateTitleThreadFunc( TitleProperty *pBootTitle )
// ロード成功?
if( SYSMi_GetWork()->flags.arm9.isLoadSucceeded == FALSE )
{
UTL_SetFatalError(FATAL_ERROR_TITLE_LOAD_FAILED);
// デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提
ERRORLOG_Printf( "SYSMi_AuthenticateTitleThreadFunc: loaded %d times.\n", s_loadTimes );
UTL_SetFatalError(FATAL_ERROR_TITLE_LOAD_FAILED);
return;
}
// パラメータチェック
@ -1831,11 +2074,11 @@ void SYSM_TryToBootTitle( TitleProperty *pBootTitle )
s_calc_hash = NULL;
}
if(dht)
if(s_dht.buffer)
{
// dht用バッファが確保されていたら解放
SYSM_Free( dht );
dht = NULL;
// DHT用バッファが確保されていたら解放
SYSM_Free( s_dht.buffer );
s_dht.buffer = NULL;
}
// ダイレクトブート時など、まだSystemMenuVersionのデータがセットされていない場合は、ここでセットする。

Binary file not shown.

Binary file not shown.

View File

@ -27,6 +27,8 @@ include $(TWL_IPL_RED_ROOT)/build/buildtools/commondefs
include ./commondefs.DSHashTable
MY_DATA = $(DS_HASH_TABLE_DATA)
MY_DATA_EX = $(DS_HASH_TABLE_EX_DATA)
MY_DATA_ADHOC = $(DS_HASH_TABLE_ADHOC_DATA)
MY_APPEND = revision.bin
MY_DATA2 = data.bin
@ -49,8 +51,8 @@ do-build : $(MY_TAD)
$(MY_TAD): $(MY_DATA2)
$(MAKETAD) $(call empath,$<) $(DS_HASH_TABLE_MAKETAD_OPTION) -o $@
$(MY_DATA2): $(MY_DATA) $(MY_APPEND)
cat $(MY_DATA) $(MY_APPEND) > $@
$(MY_DATA2): $(MY_DATA) $(MY_DATA_EX) $(MY_DATA_ADHOC) $(MY_APPEND)
cat $(MY_DATA) $(MY_DATA_EX) $(MY_DATA_ADHOC) $(MY_APPEND) > $@
$(MY_APPEND)::
@if test -e $(SYSMENU_ROOT)/.svn; then \

View File

@ -17,8 +17,12 @@
#----------------------------------------------------------------------------
DS_HASH_TABLE_TITLE_NAME := DSHashTable
DS_HASH_TABLE_EX_TITLE_NAME := DSHashTableEx
DS_HASH_TABLE_ADHOC_TITLE_NAME:= DSHashTableAdHoc
DS_HASH_TABLE_DATA_DIR := $(SYSMENU_ROOT)/build/systemMenu_RED/DSHashTable
DS_HASH_TABLE_DATA := $(DS_HASH_TABLE_DATA_DIR)/$(DS_HASH_TABLE_TITLE_NAME).bin
DS_HASH_TABLE_EX_DATA := $(DS_HASH_TABLE_DATA_DIR)/$(DS_HASH_TABLE_EX_TITLE_NAME).bin
DS_HASH_TABLE_ADHOC_DATA := $(DS_HASH_TABLE_DATA_DIR)/$(DS_HASH_TABLE_ADHOC_TITLE_NAME).bin
DS_HASH_TABLE_TITLE := HNHA
DS_HASH_TABLE_TITLE_ID_HI := 0003000F
DS_HASH_TABLE_TITLE_ID_LO := $(shell perl -e 'printf "%02X%02X%02X%02X", unpack("C4", "'$(DS_HASH_TABLE_TITLE)'")')
@ -32,7 +36,7 @@ DS_HASH_TABLE_VERSION := $(shell perl -e 'open IN, "$(DS_HASH_TABLE_D
#DS_HASH_TABLE_MINOR_VERSION := $(shell expr $(DS_HASH_TABLE_VERSION) % 256)
DS_HASH_TABLE_MAJOR_VERSION := 0
DS_HASH_TABLE_MINOR_VERSION := 0
DS_HASH_TABLE_MINOR_VERSION := 1
DS_HASH_TABLE_MAKETAD_OPTION := -s -d $(DS_HASH_TABLE_TITLE_ID) $(DS_HASH_TABLE_GROUP_ID) $(DS_HASH_TABLE_MAJOR_VERSION) $(DS_HASH_TABLE_TITLE_NAME) \
-v $(DS_HASH_TABLE_MINOR_VERSION) -p

View File

@ -123,7 +123,9 @@ static const char *fatal_error_msg[FATAL_ERROR_MAX] =
"LOAD_AUTH_HEADER_FAILED",
"LOAD_NEVER_STARTED",
"EJECT_CARD_AFTER_LOAD_START",
"TITLEID_COMPARE_FAILED_NTR"
"TITLEID_COMPARE_FAILED_NTR",
"DHT_PHASE3_FAILED",
"DHT_PHASE4_FAILED"
};
//#define DEBUG_LAUNCHER_DUMP

View File

@ -2,7 +2,7 @@
Project: TwlIPL - DHT
File: dht.h
Copyright 2008 Nintendo. All rights reserved.
Copyright 2008,2009 Nintendo. All rights reserved.
These coded instructions, statements, and computer programs contain
proprietary information of Nintendo of America Inc. and/or Nintendo
@ -17,13 +17,28 @@
#ifndef SYSMENU_DHT_H_
#define SYSMENU_DHT_H_
/*
Phase
Phase1 DHTDatabase->hash[0] ROM_Header_Short->nitro_whitelist_phase1_digest
Phase2 DHTDatabase->hash[1] ROM_Header_Short->nitro_whitelist_phase2_digest
Phase3 DHTDatabaseEx->banner_hash ROM_Header_Short->banner_digest
Phase4 - -
Phase4のハッシュ値はdht_phase4_list.cに含まれる
*/
#include <twl/types.h>
#include <twl/os/common/format_rom.h>
#include <sysmenu/dht/dht_format.h>
#define nitro_whitelist_phase2_digest nitro_whitelist_phase2_diegst // for spell miss
#define DHT_FAT_PAGE_SIZE 512
#define DHT_FAT_CACHE_SIZE (DHT_FAT_PAGE_SIZE * 2)
#define DHT_PHASE3_MAX DHT_OVERLAY_MAX
/*
DHT_CheckHashPhase2で必要なワークメモリ
*/
@ -34,6 +49,17 @@ typedef struct DHTPhase2Work
}
DHTPhase2Work;
/*
DHT_CheckHashPhase4で必要なワークメモリ
(DHTPhase4Work <= DHTPhase2Workが必ず成り立つ)
*/
typedef struct DHTPhase4Work
{
u32 buffer[DHT_PHASE3_MAX/sizeof(u32)];
}
DHTPhase4Work;
/*
DHT_CheckHashPhase2Exで必要なワークメモリ
*/
@ -48,7 +74,7 @@ extern "C" {
#endif
/*
DHT_CheckHashPhase2/DHT_CheckHashPhase2Exで使用するRead関数
DHT_CheckHashPhase2/DHT_CheckHashPhase2Ex/DHT_CheckHashPhase4で使用するRead関数
dest
offset ROMオフセット
length
@ -59,7 +85,7 @@ extern "C" {
typedef BOOL (*DHTReadFunc)(void* dest, s32 offset, s32 length, void* arg);
/*
DHT_CheckHashPhase2Exで使用するRead関数
DHT_CheckHashPhase2Ex/DHT_CheckHashPhase4Exで使用するRead関数
DHT_CheckHashPhase2ExUpdateを呼び出すこと()
ctx DHT_CheckHashPhase2ExUpdateに渡す引数
@ -71,7 +97,7 @@ typedef BOOL (*DHTReadFunc)(void* dest, s32 offset, s32 length, void* arg);
*/
typedef BOOL (*DHTReadFuncEx)(SVCHMACSHA1Context* ctx, s32 offset, s32 length, void* arg);
/*---------------------------------------------------------------------------*
Name: DHT_PrepareDatabase
Name: DHT_GetDatabaseLength
Description:
@ -81,12 +107,34 @@ typedef BOOL (*DHTReadFuncEx)(SVCHMACSHA1Context* ctx, s32 offset, s32 length
*---------------------------------------------------------------------------*/
u32 DHT_GetDatabaseLength(const DHTFile* pDHT);
/*---------------------------------------------------------------------------*
Name: DHT_GetDatabaseExLength
Description:
Arguments: pDHT
Returns: 0
*---------------------------------------------------------------------------*/
u32 DHT_GetDatabaseExLength(const DHTFileEx* pDHT);
/*---------------------------------------------------------------------------*
Name: DHT_GetDatabaseAdHocLength
Description:
Arguments: pDHT
Returns: 0
*---------------------------------------------------------------------------*/
u32 DHT_GetDatabaseAdHocLength(const DHTFileAdHoc* pDHT);
/*---------------------------------------------------------------------------*
Name: DHT_PrepareDatabase
Description: FS関数を利用して全データベースを読み込みと検証を行う
Description: FS関数を利用してデータベースを読み込みと検証を行う
Arguments: pDHT
Arguments: pDHT
fp
DHTHeaderの先頭までシーク済みである必要がある
@ -94,18 +142,56 @@ u32 DHT_GetDatabaseLength(const DHTFile* pDHT);
*---------------------------------------------------------------------------*/
BOOL DHT_PrepareDatabase(DHTFile* pDHT, FSFile* fp);
/*---------------------------------------------------------------------------*
Name: DHT_PrepareDatabaseEx
Description: FS関数を利用して拡張データベースを読み込みと検証を行う
Arguments: pDHT
fp
DHTHeaderの先頭までシーク済みである必要がある
Returns: TRUE
*---------------------------------------------------------------------------*/
BOOL DHT_PrepareDatabaseEx(DHTFileEx* pDHT, FSFile* fp);
/*---------------------------------------------------------------------------*
Name: DHT_PrepareDatabaseAdHoc
Description: FS関数を利用して個別対応データベースを読み込みと検証を行う
Arguments: pDHT
fp
DHTHeaderの先頭までシーク済みである必要がある
Returns: TRUE
*---------------------------------------------------------------------------*/
BOOL DHT_PrepareDatabaseAdHoc(DHTFileAdHoc* pDHT, FSFile* fp);
/*---------------------------------------------------------------------------*
Name: DHT_GetDatabase
Description: ROMヘッダに対応するデータベースを検索する
Arguments: pDHT
Arguments: pDHT
pROMHeader ROMヘッダ格納先
Returns:
Returns: NULL
*---------------------------------------------------------------------------*/
const DHTDatabase* DHT_GetDatabase(const DHTFile* pDHT, const ROM_Header_Short* pROMHeader);
/*---------------------------------------------------------------------------*
Name: DHT_GetDatabaseEx
Description: ROMヘッダに対応する拡張データベースを検索する
Arguments: pDHT
pROMHeader ROMヘッダ格納先
Returns: NULL
*---------------------------------------------------------------------------*/
const DHTDatabaseEx* DHT_GetDatabaseEx(const DHTFileEx* pDHT, const ROM_Header_Short* pROMHeader);
/*---------------------------------------------------------------------------*
Name: DHT_CheckHashPhase1Init
@ -178,7 +264,6 @@ BOOL DHT_CheckHashPhase2(const u8* hash, const ROM_Header_Short* pROMHeader, DHT
Name: DHT_CheckHashPhase2Ex
Description:
(Read APIを登録できるべき)
Arguments: hash (db->hash[1])
pROMHeader ROMヘッダ格納先
@ -193,10 +278,11 @@ BOOL DHT_CheckHashPhase2(const u8* hash, const ROM_Header_Short* pROMHeader, DHT
BOOL DHT_CheckHashPhase2Ex(const u8* hash, const ROM_Header_Short* pROMHeader, DHTPhase2ExWork* work, DHTReadFunc func, DHTReadFuncEx funcEx, void* arg);
/*---------------------------------------------------------------------------*
Name: DHT_CheckHashPhase2ExUpdate
Name: DHT_CheckHashPhase2ExUpdate / DHT_CheckHashPhase4ExUpdate
Description:
Description:
DHTReadFuncExから呼び出すこと()
: Phase4でも流用している
Arguments: ctx SVCHMACSHA1コンテキスト
ptr
@ -205,6 +291,51 @@ BOOL DHT_CheckHashPhase2Ex(const u8* hash, const ROM_Header_Short* pROMHeader, D
Returns: None
*---------------------------------------------------------------------------*/
void DHT_CheckHashPhase2ExUpdate(SVCHMACSHA1Context* ctx, const void* ptr, s32 length);
#define DHT_CheckHashPhase4ExUpdate DHT_CheckHashPhase2ExUpdate
/*---------------------------------------------------------------------------*
Name: DHT_CheckHashPhase3
Description:
(使)
Arguments: hash (dbex->banner_hash)
pBanner
Returns: TRUE
*---------------------------------------------------------------------------*/
BOOL DHT_CheckHashPhase3(const u8* hash, const NTRBannerFile* pBanner);
/*---------------------------------------------------------------------------*
Name: DHT_CheckHashPhase4
Description:
Arguments: pDHT
pROMHeader ROMヘッダ格納先
work APIで使用するワーク (512KB)
phase2の使い回しでOK
func Read関数
arg Read関数に渡される引数
Returns: TRUE
*---------------------------------------------------------------------------*/
BOOL DHT_CheckHashPhase4(const DHTFileAdHoc* pDHT, const ROM_Header_Short* pROMHeader, DHTPhase4Work* work, DHTReadFunc func, void* arg);
/*---------------------------------------------------------------------------*
Name: DHT_CheckHashPhase4Ex
Description:
Arguments: pDHT
pROMHeader ROMヘッダ格納先
funcEx
DHT_CheckHashPhase2ExUpdateを呼び出す必要がある
arg Read関数に渡される引数
Returns: TRUE
*---------------------------------------------------------------------------*/
BOOL DHT_CheckHashPhase4Ex(const DHTFileAdHoc* pDHT, const ROM_Header_Short* pROMHeader, DHTReadFuncEx funcEx, void* arg);
#ifdef __cplusplus
} /* extern "C" */

View File

@ -21,7 +21,12 @@
#define DHT_DS_HEADER_SIZE 0x160
#define DHT_OVERLAY_MAX (512*1024)
#define DHT_MAGIC_CODE_EX (('N' << 0)|('D' << 8)|('H' << 16)|('X' << 24))
#define DHT_MAGIC_CODE_ADHOC (('N' << 0)|('D' << 8)|('H' << 16)|('I' << 24))
#include <twl/types.h>
#include <twl/os/common/banner.h>
#ifdef __cplusplus
extern "C" {
@ -35,6 +40,8 @@ typedef struct DHTHeader
}
DHTHeader;
#define DHTHeaderEx DHTHeader
typedef struct DHTDatabase
{
u8 game_code[4];
@ -44,6 +51,33 @@ typedef struct DHTDatabase
}
DHTDatabase;
typedef struct DHTDatabaseEx
{
u8 game_code[4];
u8 rom_version;
u8 reserved[3]; // for 4B alignment DHTDatabase array
u8 banner_hash[20];
}
DHTDatabaseEx;
/*
ad-hoc対処用
*/
#define DHT_INDIVIDUAL_ENTRY_MAX 8
typedef struct DHTDatabaseAdHoc
{
u8 game_code[4];
u8 rom_version;
u8 reserved[3]; // for 4B alignment DHTDatabase array
struct
{
u32 offset;
u32 length;
} entry[DHT_INDIVIDUAL_ENTRY_MAX];
u8 hash[20];
}
DHTDatabaseAdHoc;
typedef struct DHTFile
{
DHTHeader header;
@ -51,6 +85,20 @@ typedef struct DHTFile
}
DHTFile;
typedef struct DHTFileEx
{
DHTHeader header;
DHTDatabaseEx database[];
}
DHTFileEx;
typedef struct DHTFileAdHoc
{
DHTHeader header;
DHTDatabaseAdHoc database[];
}
DHTFileAdHoc;
#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, \
@ -58,16 +106,28 @@ DHTFile;
0x7f, 0xd9, 0x7c, 0xe9, 0x92, 0x44, 0x0f, 0xef, 0x6b, 0xb6, 0x12, 0x21, 0x68, 0x88, 0xd8, 0xee \
}
#define DHT_HMAC_KEY2 { \
0x85, 0x29, 0x48, 0xf3, 0xa1, 0xbb, 0x13, 0x30, 0x93, 0x5d, 0xb8, 0xc9, 0xa5, 0x9a, 0xe8, 0x30, \
0xc4, 0xd0, 0x4a, 0xdd, 0xa4, 0x92, 0x81, 0xfd, 0x4f, 0xa1, 0x32, 0xfa, 0x46, 0x05, 0xde, 0x68, \
0x7b, 0xa7, 0xd7, 0x5b, 0xc9, 0x3a, 0xc8, 0x8d, 0xcd, 0x25, 0x3a, 0x17, 0x3c, 0xc2, 0xd6, 0xe0, \
0xd2, 0xe5, 0xb9, 0xfb, 0x49, 0xf9, 0x4d, 0x05, 0x70, 0x10, 0x29, 0x51, 0x7a, 0xc5, 0x89, 0x49, \
}
/*
ƒ<EFBFBD>[ƒeƒBƒŠƒeƒB
hp:
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)
#define DHT_GET_SIGN_TARGET_ADDR_EX(hp) DHT_GET_SIGN_TARGET_ADDR(hp)
#define DHT_GET_SIGN_TARGET_SIZE_EX(hp) (((DHTHeader*)hp)->nums * sizeof(DHTDatabaseEx) + sizeof(u32))
#define DHT_GET_SIGN_TARGET_OFFSET_EX DHT_GET_SIGN_TARGET_OFFSET
#define DHT_GET_SIGN_TARGET_ADDR_ADHOC(hp) DHT_GET_SIGN_TARGET_ADDR(hp)
#define DHT_GET_SIGN_TARGET_SIZE_ADHOC(hp) (((DHTHeader*)hp)->nums * sizeof(DHTDatabaseAdHoc) + sizeof(u32))
#define DHT_GET_SIGN_TARGET_OFFSET_ADHOC DHT_GET_SIGN_TARGET_OFFSET
#ifdef __cplusplus
} /* extern "C" */

View File

@ -80,8 +80,10 @@ typedef enum FatalErrorCode {
FATAL_ERROR_LOAD_NEVER_STARTED = 48, // ロードが開始されていないのに、認証が開始された
FATAL_ERROR_EJECT_CARD_AFTER_LOAD_START = 49, // カードが抜かれているのに、カードアプリのロードが開始された
FATAL_ERROR_TITLEID_COMPARE_FAILED_NTR = 50, // ブート要求されたNTRアプリと実際にロードしたアプリのTitleIDが不一致
FATAL_ERROR_DHT_PHASE3_FAILED = 51, // アプリのNTRホワイトリスト認証失敗フェーズ
FATAL_ERROR_DHT_PHASE4_FAILED = 52, // アプリのNTRホワイトリスト認証失敗フェーズ
FATAL_ERROR_MAX = 51
FATAL_ERROR_MAX = 53
}FatalErrorCode;