mirror of
https://github.com/rvtr/TwlIPL.git
synced 2025-10-31 06:01:12 -04:00
ホワイトリスト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:
parent
3ac6387837
commit
a938401b08
@ -21,6 +21,8 @@ TWL_IPL_COMMONDEFS_ = TRUE
|
|||||||
#FIRM_USE_PRODUCT_KEYS = TRUE
|
#FIRM_USE_PRODUCT_KEYS = TRUE
|
||||||
#SYSM_BUILD_FOR_DEBUGGER = TRUE
|
#SYSM_BUILD_FOR_DEBUGGER = TRUE
|
||||||
SYSM_DEV_WHITELIST_CHECK_SKIP ?= TRUE
|
SYSM_DEV_WHITELIST_CHECK_SKIP ?= TRUE
|
||||||
|
#SYSM_IGNORE_DHT_PHASE_3 = TRUE
|
||||||
|
SYSM_IGNORE_DHT_EX_NOT_FOUND ?= TRUE
|
||||||
|
|
||||||
ifeq ($(TARGET_FIRM),SYSTEMMENU)
|
ifeq ($(TARGET_FIRM),SYSTEMMENU)
|
||||||
include $(TWL_IPL_RED_ROOT)/build/buildtools/commondefs.sysmenu
|
include $(TWL_IPL_RED_ROOT)/build/buildtools/commondefs.sysmenu
|
||||||
|
|||||||
@ -49,7 +49,8 @@ static const u8 g_pubkey_DER[ 0xa2 ] = {
|
|||||||
0x00, 0x01
|
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 DHTReadFunc imageReadFunc;
|
||||||
static void* imageBuffer;
|
static void* imageBuffer;
|
||||||
@ -114,6 +115,25 @@ u32 DHT_GetDatabaseLength(const DHTFile* pDHT)
|
|||||||
}
|
}
|
||||||
return sizeof(DHTHeader) + pDHT->header.nums * sizeof(DHTDatabase);
|
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)
|
static BOOL DHT_CheckDatabase(const DHTFile* pDHT)
|
||||||
{
|
{
|
||||||
SVCSignHeapContext pool;
|
SVCSignHeapContext pool;
|
||||||
@ -216,6 +236,219 @@ const DHTDatabase* DHT_GetDatabase(const DHTFile* pDHT, const ROM_Header_Short*
|
|||||||
#endif
|
#endif
|
||||||
return db;
|
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)
|
ハッシュ計算 (1)
|
||||||
読み込み済みデータをチェックする
|
読み込み済みデータをチェックする
|
||||||
@ -468,3 +701,141 @@ void DHT_CheckHashPhase2ExUpdate(SVCHMACSHA1Context* ctx, const void* ptr, s32 l
|
|||||||
SVC_HMACSHA1Update(ctx, ptr, (u32)length);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -62,6 +62,16 @@ include $(TWL_IPL_RED_ROOT)/build/buildtools/commondefs
|
|||||||
|
|
||||||
ifeq ($(SYSM_DEV_WHITELIST_CHECK_SKIP),TRUE)
|
ifeq ($(SYSM_DEV_WHITELIST_CHECK_SKIP),TRUE)
|
||||||
MACRO_FLAGS += -DDEV_WHITELIST_CHECK_SKIP
|
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
|
endif
|
||||||
|
|
||||||
INSTALL_TARGETS = $(TARGETS)
|
INSTALL_TARGETS = $(TARGETS)
|
||||||
|
|||||||
@ -59,7 +59,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <sysmenu/dht/dht.h>
|
#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
|
#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_b_dev = FALSE;
|
||||||
static BOOL s_result_phase1 = FALSE;
|
static BOOL s_result_phase1 = FALSE;
|
||||||
|
|
||||||
static DHTFile *dht = NULL;
|
static struct
|
||||||
static const u8* hash0 = NULL;
|
{
|
||||||
static const u8* hash1 = NULL;
|
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------------------------------------------------------------------
|
// const data------------------------------------------------------------------
|
||||||
static const OSBootType s_launcherToOSBootType[ LAUNCHER_BOOTTYPE_MAX ] = {
|
static const OSBootType s_launcherToOSBootType[ LAUNCHER_BOOTTYPE_MAX ] = {
|
||||||
@ -218,35 +226,159 @@ static BOOL GetDatabaseFilepath(char *path)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrepareDHTDatabase(void)
|
// open and read every database (フェーズ4があるので常に実行すること)
|
||||||
|
static BOOL PrepareDHTDatabase(void)
|
||||||
{
|
{
|
||||||
char path[256];
|
char path[256];
|
||||||
if ( GetDatabaseFilepath( path ) )
|
int length;
|
||||||
{
|
|
||||||
FSFile file;
|
FSFile file;
|
||||||
if ( FS_OpenFileEx(&file, path, FS_FILEMODE_R) )
|
|
||||||
|
if ( s_dht.buffer )
|
||||||
{
|
{
|
||||||
#if 0 // 1 if using attach_dummyromheader
|
return TRUE; // already done !?
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MI_CpuClear8(dht, sizeof(DHTHeader));
|
if ( !GetDatabaseFilepath( path ) )
|
||||||
dht = NULL;
|
{
|
||||||
|
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)
|
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" );
|
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 )
|
if( head->s.exFlags.enable_nitro_whitelist_signature )
|
||||||
{
|
{
|
||||||
// マスタリング済みNTRカードアプリの署名チェック(実はTWLアプリと同じ)
|
// マスタリング済みNTRカードアプリの署名チェック(実はTWLアプリと同じ)
|
||||||
ret = SYSMi_AuthenticateHeaderWithSign( pBootTitle, head );
|
ret = SYSMi_AuthenticateHeaderWithSign( pBootTitle, head );
|
||||||
if( ret == TRUE )
|
if( ret == TRUE )
|
||||||
{
|
{
|
||||||
hash0 = head->s.nitro_whitelist_phase1_digest;
|
s_dht.hash1 = head->s.nitro_whitelist_phase1_digest;
|
||||||
hash1 = head->s.nitro_whitelist_phase2_diegst;
|
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
|
}else
|
||||||
{
|
{
|
||||||
// ホワイトリスト検索
|
// ホワイトリスト検索
|
||||||
const DHTDatabase* db;
|
const DHTDatabase* db;
|
||||||
PrepareDHTDatabase();// 60msくらいなので、ここでやってしまってOKとする。
|
if(!s_dht.dht)
|
||||||
if(!dht)
|
|
||||||
{
|
{
|
||||||
OS_TPrintf(" Search DHT : database init Failed.\n");
|
OS_TPrintf(" Search DHT : database init Failed.\n");
|
||||||
if(!s_b_dev)
|
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);
|
UTL_SetFatalError(FATAL_ERROR_WHITELIST_INITDB_FAILED);
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
}
|
}
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
OS_TPrintf("Searching DHT for %.4s(%02X)...", head->s.game_code, head->s.rom_version);
|
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 )
|
if ( !db )
|
||||||
{
|
{
|
||||||
OS_TPrintf(" Search DHT : Failed.\n");
|
OS_TPrintf(" Search DHT : Failed.\n");
|
||||||
if(!s_b_dev)
|
if(!s_b_dev)
|
||||||
{
|
{
|
||||||
|
ERRORLOG_Printf( "WHITELIST_NOTFOUND (sub info): no entry for phase 1/2.\n" );
|
||||||
UTL_SetFatalError(FATAL_ERROR_WHITELIST_NOTFOUND);
|
UTL_SetFatalError(FATAL_ERROR_WHITELIST_NOTFOUND);
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
}
|
}
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
hash0 = db->hash[0];
|
s_dht.hash1 = db->hash[0];
|
||||||
hash1 = db->hash[1];
|
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;
|
ret = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1475,21 +1659,23 @@ static BOOL SYSMi_AuthenticateNTRCardTitle( TitleProperty *pBootTitle)
|
|||||||
DHTPhase2Work* p2work = NULL;
|
DHTPhase2Work* p2work = NULL;
|
||||||
ROM_Header_Short *hs = ( ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF;
|
ROM_Header_Short *hs = ( ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF;
|
||||||
|
|
||||||
// phase1最終検証
|
// DHTチェックphase1
|
||||||
if(s_calc_hash)
|
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");
|
OS_TPrintf("DHT Phase1 failed: hash check failed.\n");
|
||||||
if(!s_b_dev) {
|
if(!s_b_dev) {
|
||||||
// デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提
|
// デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提
|
||||||
ERRORLOG_Printf( "DHT_PAHSE1_FAILED (sub info): hash0Addr-%08x\n", hash0 );
|
ERRORLOG_Printf( "DHT_PAHSE1_FAILED (sub info): hash1Addr-%08x\n", s_dht.hash1 );
|
||||||
if(hash0)
|
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",
|
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",
|
||||||
hash0[0], hash0[1], hash0[2], hash0[3], hash0[4], hash0[5], hash0[6], hash0[7], hash0[8], hash0[9],
|
s_dht.hash1[0], s_dht.hash1[1], s_dht.hash1[2], s_dht.hash1[3], s_dht.hash1[4],
|
||||||
hash0[10], hash0[11], hash0[12], hash0[13], hash0[14], hash0[15], hash0[16], hash0[17], hash0[18], hash0[19]);
|
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",
|
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[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],
|
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
|
// DHTチェックphase2
|
||||||
OS_TPrintf("DHT Phase2...");
|
OS_TPrintf("DHT Phase2...");
|
||||||
p2work = SYSM_Alloc( sizeof(DHTPhase2Work) );
|
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");
|
OS_TPrintf(" DHT Phase2 : Failed.\n");
|
||||||
if(!s_b_dev){
|
if(!s_b_dev){
|
||||||
// デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提
|
// デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提
|
||||||
ERRORLOG_Printf( "DHT_PAHSE2_FAILED (sub info): p2workAddr-%08x hash1Addr-%08x\n", p2work, hash1 );
|
ERRORLOG_Printf( "DHT_PAHSE2_FAILED (sub info): p2workAddr-%08x hash2Addr-%08x\n", p2work, s_dht.hash2 );
|
||||||
if( p2work ) SYSM_Free(p2work);
|
SYSM_Free(p2work);
|
||||||
UTL_SetFatalError(FATAL_ERROR_DHT_PHASE2_FAILED);
|
UTL_SetFatalError(FATAL_ERROR_DHT_PHASE2_FAILED);
|
||||||
return FALSE;
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -1678,9 +1921,9 @@ static void SYSMi_AuthenticateTitleThreadFunc( TitleProperty *pBootTitle )
|
|||||||
// ロード成功?
|
// ロード成功?
|
||||||
if( SYSMi_GetWork()->flags.arm9.isLoadSucceeded == FALSE )
|
if( SYSMi_GetWork()->flags.arm9.isLoadSucceeded == FALSE )
|
||||||
{
|
{
|
||||||
UTL_SetFatalError(FATAL_ERROR_TITLE_LOAD_FAILED);
|
|
||||||
// デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提
|
// デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提
|
||||||
ERRORLOG_Printf( "SYSMi_AuthenticateTitleThreadFunc: loaded %d times.\n", s_loadTimes );
|
ERRORLOG_Printf( "SYSMi_AuthenticateTitleThreadFunc: loaded %d times.\n", s_loadTimes );
|
||||||
|
UTL_SetFatalError(FATAL_ERROR_TITLE_LOAD_FAILED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// パラメータチェック
|
// パラメータチェック
|
||||||
@ -1831,11 +2074,11 @@ void SYSM_TryToBootTitle( TitleProperty *pBootTitle )
|
|||||||
s_calc_hash = NULL;
|
s_calc_hash = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dht)
|
if(s_dht.buffer)
|
||||||
{
|
{
|
||||||
// dht用バッファが確保されていたら解放
|
// DHT用バッファが確保されていたら解放
|
||||||
SYSM_Free( dht );
|
SYSM_Free( s_dht.buffer );
|
||||||
dht = NULL;
|
s_dht.buffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ダイレクトブート時など、まだSystemMenuVersionのデータがセットされていない場合は、ここでセットする。
|
// ダイレクトブート時など、まだSystemMenuVersionのデータがセットされていない場合は、ここでセットする。
|
||||||
|
|||||||
BIN
build/systemMenu_RED/DSHashTable/DSHashTableAdHoc.bin
Normal file
BIN
build/systemMenu_RED/DSHashTable/DSHashTableAdHoc.bin
Normal file
Binary file not shown.
BIN
build/systemMenu_RED/DSHashTable/DSHashTableEx.bin
Normal file
BIN
build/systemMenu_RED/DSHashTable/DSHashTableEx.bin
Normal file
Binary file not shown.
@ -27,6 +27,8 @@ include $(TWL_IPL_RED_ROOT)/build/buildtools/commondefs
|
|||||||
include ./commondefs.DSHashTable
|
include ./commondefs.DSHashTable
|
||||||
|
|
||||||
MY_DATA = $(DS_HASH_TABLE_DATA)
|
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_APPEND = revision.bin
|
||||||
MY_DATA2 = data.bin
|
MY_DATA2 = data.bin
|
||||||
|
|
||||||
@ -49,8 +51,8 @@ do-build : $(MY_TAD)
|
|||||||
$(MY_TAD): $(MY_DATA2)
|
$(MY_TAD): $(MY_DATA2)
|
||||||
$(MAKETAD) $(call empath,$<) $(DS_HASH_TABLE_MAKETAD_OPTION) -o $@
|
$(MAKETAD) $(call empath,$<) $(DS_HASH_TABLE_MAKETAD_OPTION) -o $@
|
||||||
|
|
||||||
$(MY_DATA2): $(MY_DATA) $(MY_APPEND)
|
$(MY_DATA2): $(MY_DATA) $(MY_DATA_EX) $(MY_DATA_ADHOC) $(MY_APPEND)
|
||||||
cat $(MY_DATA) $(MY_APPEND) > $@
|
cat $(MY_DATA) $(MY_DATA_EX) $(MY_DATA_ADHOC) $(MY_APPEND) > $@
|
||||||
|
|
||||||
$(MY_APPEND)::
|
$(MY_APPEND)::
|
||||||
@if test -e $(SYSMENU_ROOT)/.svn; then \
|
@if test -e $(SYSMENU_ROOT)/.svn; then \
|
||||||
|
|||||||
@ -17,8 +17,12 @@
|
|||||||
#----------------------------------------------------------------------------
|
#----------------------------------------------------------------------------
|
||||||
|
|
||||||
DS_HASH_TABLE_TITLE_NAME := DSHashTable
|
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_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_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 := HNHA
|
||||||
DS_HASH_TABLE_TITLE_ID_HI := 0003000F
|
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)'")')
|
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_MINOR_VERSION := $(shell expr $(DS_HASH_TABLE_VERSION) % 256)
|
||||||
|
|
||||||
DS_HASH_TABLE_MAJOR_VERSION := 0
|
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) \
|
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
|
-v $(DS_HASH_TABLE_MINOR_VERSION) -p
|
||||||
|
|||||||
@ -123,7 +123,9 @@ static const char *fatal_error_msg[FATAL_ERROR_MAX] =
|
|||||||
"LOAD_AUTH_HEADER_FAILED",
|
"LOAD_AUTH_HEADER_FAILED",
|
||||||
"LOAD_NEVER_STARTED",
|
"LOAD_NEVER_STARTED",
|
||||||
"EJECT_CARD_AFTER_LOAD_START",
|
"EJECT_CARD_AFTER_LOAD_START",
|
||||||
"TITLEID_COMPARE_FAILED_NTR"
|
"TITLEID_COMPARE_FAILED_NTR",
|
||||||
|
"DHT_PHASE3_FAILED",
|
||||||
|
"DHT_PHASE4_FAILED"
|
||||||
};
|
};
|
||||||
|
|
||||||
//#define DEBUG_LAUNCHER_DUMP
|
//#define DEBUG_LAUNCHER_DUMP
|
||||||
|
|||||||
Binary file not shown.
@ -2,7 +2,7 @@
|
|||||||
Project: TwlIPL - DHT
|
Project: TwlIPL - DHT
|
||||||
File: dht.h
|
File: dht.h
|
||||||
|
|
||||||
Copyright 2008 Nintendo. All rights reserved.
|
Copyright 2008,2009 Nintendo. All rights reserved.
|
||||||
|
|
||||||
These coded instructions, statements, and computer programs contain
|
These coded instructions, statements, and computer programs contain
|
||||||
proprietary information of Nintendo of America Inc. and/or Nintendo
|
proprietary information of Nintendo of America Inc. and/or Nintendo
|
||||||
@ -17,13 +17,28 @@
|
|||||||
#ifndef SYSMENU_DHT_H_
|
#ifndef SYSMENU_DHT_H_
|
||||||
#define 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/types.h>
|
||||||
#include <twl/os/common/format_rom.h>
|
#include <twl/os/common/format_rom.h>
|
||||||
#include <sysmenu/dht/dht_format.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_PAGE_SIZE 512
|
||||||
#define DHT_FAT_CACHE_SIZE (DHT_FAT_PAGE_SIZE * 2)
|
#define DHT_FAT_CACHE_SIZE (DHT_FAT_PAGE_SIZE * 2)
|
||||||
|
|
||||||
|
#define DHT_PHASE3_MAX DHT_OVERLAY_MAX
|
||||||
|
|
||||||
/*
|
/*
|
||||||
DHT_CheckHashPhase2で必要なワークメモリ
|
DHT_CheckHashPhase2で必要なワークメモリ
|
||||||
*/
|
*/
|
||||||
@ -34,6 +49,17 @@ typedef struct DHTPhase2Work
|
|||||||
}
|
}
|
||||||
DHTPhase2Work;
|
DHTPhase2Work;
|
||||||
|
|
||||||
|
/*
|
||||||
|
DHT_CheckHashPhase4で必要なワークメモリ
|
||||||
|
(DHTPhase4Work <= DHTPhase2Workが必ず成り立つ)
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct DHTPhase4Work
|
||||||
|
{
|
||||||
|
u32 buffer[DHT_PHASE3_MAX/sizeof(u32)];
|
||||||
|
}
|
||||||
|
DHTPhase4Work;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
DHT_CheckHashPhase2Exで必要なワークメモリ
|
DHT_CheckHashPhase2Exで必要なワークメモリ
|
||||||
*/
|
*/
|
||||||
@ -48,7 +74,7 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
DHT_CheckHashPhase2/DHT_CheckHashPhase2Exで使用するRead関数
|
DHT_CheckHashPhase2/DHT_CheckHashPhase2Ex/DHT_CheckHashPhase4で使用するRead関数
|
||||||
dest 転送先アドレス
|
dest 転送先アドレス
|
||||||
offset 転送元ROMオフセット
|
offset 転送元ROMオフセット
|
||||||
length 転送サイズ
|
length 転送サイズ
|
||||||
@ -59,7 +85,7 @@ extern "C" {
|
|||||||
typedef BOOL (*DHTReadFunc)(void* dest, s32 offset, s32 length, void* arg);
|
typedef BOOL (*DHTReadFunc)(void* dest, s32 offset, s32 length, void* arg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
DHT_CheckHashPhase2Exで使用するRead関数
|
DHT_CheckHashPhase2Ex/DHT_CheckHashPhase4Exで使用するRead関数
|
||||||
転送先アドレスは存在せず、代わりに独自バッファに読み込んだ後
|
転送先アドレスは存在せず、代わりに独自バッファに読み込んだ後
|
||||||
DHT_CheckHashPhase2ExUpdateを呼び出すこと(細分化可能)
|
DHT_CheckHashPhase2ExUpdateを呼び出すこと(細分化可能)
|
||||||
ctx 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);
|
typedef BOOL (*DHTReadFuncEx)(SVCHMACSHA1Context* ctx, s32 offset, s32 length, void* arg);
|
||||||
/*---------------------------------------------------------------------------*
|
/*---------------------------------------------------------------------------*
|
||||||
Name: DHT_PrepareDatabase
|
Name: DHT_GetDatabaseLength
|
||||||
|
|
||||||
Description: 読み込み済みのデータベースのヘッダからサイズを返す
|
Description: 読み込み済みのデータベースのヘッダからサイズを返す
|
||||||
|
|
||||||
@ -81,12 +107,34 @@ typedef BOOL (*DHTReadFuncEx)(SVCHMACSHA1Context* ctx, s32 offset, s32 length
|
|||||||
*---------------------------------------------------------------------------*/
|
*---------------------------------------------------------------------------*/
|
||||||
u32 DHT_GetDatabaseLength(const DHTFile* pDHT);
|
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
|
Name: DHT_PrepareDatabase
|
||||||
|
|
||||||
Description: FS関数を利用して全データベースを読み込みと検証を行う
|
Description: FS関数を利用してデータベースを読み込みと検証を行う
|
||||||
|
|
||||||
Arguments: pDHT 全データベースの格納先
|
Arguments: pDHT データベースの格納先
|
||||||
fp ファイル構造体へのポインタ
|
fp ファイル構造体へのポインタ
|
||||||
DHTHeaderの先頭までシーク済みである必要がある
|
DHTHeaderの先頭までシーク済みである必要がある
|
||||||
|
|
||||||
@ -94,18 +142,56 @@ u32 DHT_GetDatabaseLength(const DHTFile* pDHT);
|
|||||||
*---------------------------------------------------------------------------*/
|
*---------------------------------------------------------------------------*/
|
||||||
BOOL DHT_PrepareDatabase(DHTFile* pDHT, FSFile* fp);
|
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
|
Name: DHT_GetDatabase
|
||||||
|
|
||||||
Description: ROMヘッダに対応するデータベースを検索する
|
Description: ROMヘッダに対応するデータベースを検索する
|
||||||
|
|
||||||
Arguments: pDHT 全データベースの格納先
|
Arguments: pDHT データベースの格納先
|
||||||
pROMHeader 対象となるROMヘッダ格納先
|
pROMHeader 対象となるROMヘッダ格納先
|
||||||
|
|
||||||
Returns: 対象データベースへのポインタ
|
Returns: 対象エントリへのポインタ、見つからなければNULL
|
||||||
*---------------------------------------------------------------------------*/
|
*---------------------------------------------------------------------------*/
|
||||||
const DHTDatabase* DHT_GetDatabase(const DHTFile* pDHT, const ROM_Header_Short* pROMHeader);
|
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
|
Name: DHT_CheckHashPhase1Init
|
||||||
|
|
||||||
@ -178,7 +264,6 @@ BOOL DHT_CheckHashPhase2(const u8* hash, const ROM_Header_Short* pROMHeader, DHT
|
|||||||
Name: DHT_CheckHashPhase2Ex
|
Name: DHT_CheckHashPhase2Ex
|
||||||
|
|
||||||
Description: オーバーレイ領域の検証
|
Description: オーバーレイ領域の検証
|
||||||
(デバイスのRead APIを登録できるべき)
|
|
||||||
|
|
||||||
Arguments: hash 対応するハッシュ (db->hash[1])
|
Arguments: hash 対応するハッシュ (db->hash[1])
|
||||||
pROMHeader 対象となるROMヘッダ格納先
|
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);
|
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から呼び出すこと(さらなる細分化は自由)
|
DHTReadFuncExから呼び出すこと(さらなる細分化は自由)
|
||||||
|
注意: Phase4でも流用している
|
||||||
|
|
||||||
Arguments: ctx 検証用のSVCHMACSHA1コンテキスト
|
Arguments: ctx 検証用のSVCHMACSHA1コンテキスト
|
||||||
ptr 対象となるデータ領域
|
ptr 対象となるデータ領域
|
||||||
@ -205,6 +291,51 @@ BOOL DHT_CheckHashPhase2Ex(const u8* hash, const ROM_Header_Short* pROMHeader, D
|
|||||||
Returns: None
|
Returns: None
|
||||||
*---------------------------------------------------------------------------*/
|
*---------------------------------------------------------------------------*/
|
||||||
void DHT_CheckHashPhase2ExUpdate(SVCHMACSHA1Context* ctx, const void* ptr, s32 length);
|
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
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|||||||
@ -21,7 +21,12 @@
|
|||||||
#define DHT_DS_HEADER_SIZE 0x160
|
#define DHT_DS_HEADER_SIZE 0x160
|
||||||
#define DHT_OVERLAY_MAX (512*1024)
|
#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/types.h>
|
||||||
|
#include <twl/os/common/banner.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -35,6 +40,8 @@ typedef struct DHTHeader
|
|||||||
}
|
}
|
||||||
DHTHeader;
|
DHTHeader;
|
||||||
|
|
||||||
|
#define DHTHeaderEx DHTHeader
|
||||||
|
|
||||||
typedef struct DHTDatabase
|
typedef struct DHTDatabase
|
||||||
{
|
{
|
||||||
u8 game_code[4];
|
u8 game_code[4];
|
||||||
@ -44,6 +51,33 @@ typedef struct DHTDatabase
|
|||||||
}
|
}
|
||||||
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
|
typedef struct DHTFile
|
||||||
{
|
{
|
||||||
DHTHeader header;
|
DHTHeader header;
|
||||||
@ -51,6 +85,20 @@ typedef struct DHTFile
|
|||||||
}
|
}
|
||||||
DHTFile;
|
DHTFile;
|
||||||
|
|
||||||
|
typedef struct DHTFileEx
|
||||||
|
{
|
||||||
|
DHTHeader header;
|
||||||
|
DHTDatabaseEx database[];
|
||||||
|
}
|
||||||
|
DHTFileEx;
|
||||||
|
|
||||||
|
typedef struct DHTFileAdHoc
|
||||||
|
{
|
||||||
|
DHTHeader header;
|
||||||
|
DHTDatabaseAdHoc database[];
|
||||||
|
}
|
||||||
|
DHTFileAdHoc;
|
||||||
|
|
||||||
#define DHT_HMAC_KEY { \
|
#define DHT_HMAC_KEY { \
|
||||||
0x61, 0xbd, 0xdd, 0x72, 0x7e, 0x72, 0xbe, 0xde, 0xad, 0x3a, 0xdf, 0x7f, 0x3d, 0x2d, 0xf7, 0xa5, \
|
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, \
|
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 \
|
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
|
ƒ†<EFBFBD>[ƒeƒBƒŠƒeƒB
|
||||||
hp: メモリ上のファイルの先頭アドレス
|
hp: メモリ上のデータベースの先頭アドレス
|
||||||
*/
|
*/
|
||||||
#define DHT_GET_SIGN_TARGET_ADDR(hp) (&((DHTHeader*)hp)->nums)
|
#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_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_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
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|||||||
@ -80,8 +80,10 @@ typedef enum FatalErrorCode {
|
|||||||
FATAL_ERROR_LOAD_NEVER_STARTED = 48, // ロードが開始されていないのに、認証が開始された
|
FATAL_ERROR_LOAD_NEVER_STARTED = 48, // ロードが開始されていないのに、認証が開始された
|
||||||
FATAL_ERROR_EJECT_CARD_AFTER_LOAD_START = 49, // カードが抜かれているのに、カードアプリのロードが開始された
|
FATAL_ERROR_EJECT_CARD_AFTER_LOAD_START = 49, // カードが抜かれているのに、カードアプリのロードが開始された
|
||||||
FATAL_ERROR_TITLEID_COMPARE_FAILED_NTR = 50, // ブート要求されたNTRアプリと実際にロードしたアプリのTitleIDが不一致
|
FATAL_ERROR_TITLEID_COMPARE_FAILED_NTR = 50, // ブート要求されたNTRアプリと実際にロードしたアプリのTitleIDが不一致
|
||||||
|
FATAL_ERROR_DHT_PHASE3_FAILED = 51, // アプリのNTRホワイトリスト認証失敗(フェーズ3)
|
||||||
|
FATAL_ERROR_DHT_PHASE4_FAILED = 52, // アプリのNTRホワイトリスト認証失敗(フェーズ4)
|
||||||
|
|
||||||
FATAL_ERROR_MAX = 51
|
FATAL_ERROR_MAX = 53
|
||||||
}FatalErrorCode;
|
}FatalErrorCode;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user