mirror of
https://github.com/rvtr/TwlToolsRED.git
synced 2025-10-31 06:41:18 -04:00
digest1, digest2 の各テーブルを検証する機能の追加
git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/TwlToolsRED@567 7061adef-622a-194b-ae81-725974e89856
This commit is contained in:
parent
47983519a2
commit
a438710879
468
build/tools/TamperDetectorForSrl/card_hash.cpp
Normal file
468
build/tools/TamperDetectorForSrl/card_hash.cpp
Normal file
@ -0,0 +1,468 @@
|
|||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <openssl/hmac.h> /* libcrypto.a */
|
||||||
|
#include "twl_format_rom.h"
|
||||||
|
#include "card_hash.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define MATH_SHA1_DIGEST_SIZE (160/8)
|
||||||
|
#define CARD_ROM_HASH_SIZE (20)
|
||||||
|
|
||||||
|
static u8 CARDiHmacKey[] =
|
||||||
|
{
|
||||||
|
0x21, 0x06, 0xc0, 0xde, 0xba, 0x98, 0xce, 0x3f,
|
||||||
|
0xa6, 0x92, 0xe3, 0x9d, 0x46, 0xf2, 0xed, 0x01,
|
||||||
|
0x76, 0xe3, 0xcc, 0x08, 0x56, 0x23, 0x63, 0xfa,
|
||||||
|
0xca, 0xd4, 0xec, 0xdf, 0x9a, 0x62, 0x78, 0x34,
|
||||||
|
0x8f, 0x6d, 0x63, 0x3c, 0xfe, 0x22, 0xca, 0x92,
|
||||||
|
0x20, 0x88, 0x97, 0x23, 0xd2, 0xcf, 0xae, 0xc2,
|
||||||
|
0x32, 0x67, 0x8d, 0xfe, 0xca, 0x83, 0x64, 0x98,
|
||||||
|
0xac, 0xfd, 0x3e, 0x37, 0x87, 0x46, 0x58, 0x24,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
unsigned char *HMAC(const EVP_MD *evp_md, const void *key,
|
||||||
|
int key_len, const unsigned char *d, int n,
|
||||||
|
unsigned char *md, unsigned int *md_len);
|
||||||
|
*/
|
||||||
|
|
||||||
|
HMAC_CTX myHmacContext;
|
||||||
|
|
||||||
|
|
||||||
|
void MATH_CalcHMACSHA1(void *digest, const void *bin_ptr, u32 bin_len, const void *key_ptr, u32 key_len)
|
||||||
|
{
|
||||||
|
unsigned int res_len;
|
||||||
|
|
||||||
|
HMAC( EVP_sha1(),
|
||||||
|
key_ptr, key_len,
|
||||||
|
(const unsigned char*)bin_ptr, (size_t)bin_len,
|
||||||
|
(unsigned char*)digest, &res_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool CARDi_CompareHash(const void *hash, void *buffer, u32 length)
|
||||||
|
{
|
||||||
|
bool ret = true;
|
||||||
|
u8 tmphash[CARD_ROM_HASH_SIZE];
|
||||||
|
|
||||||
|
MATH_CalcHMACSHA1(tmphash, buffer, length, CARDiHmacKey, sizeof(CARDiHmacKey));
|
||||||
|
|
||||||
|
if (memcmp(hash, tmphash, sizeof(tmphash)) != 0)
|
||||||
|
{
|
||||||
|
ret = false;
|
||||||
|
printf("ROM-hash comparation error!\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// printf("ROM-hash comparation success.\n");
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
u8* myhash = (u8*)hash;
|
||||||
|
printf( "digest2:0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
|
||||||
|
myhash[0], myhash[1], myhash[2], myhash[3], myhash[4], myhash[5],
|
||||||
|
myhash[6], myhash[7], myhash[8], myhash[9], myhash[10], myhash[11],
|
||||||
|
myhash[12], myhash[13], myhash[14], myhash[15], myhash[16], myhash[17],
|
||||||
|
myhash[18], myhash[19]);
|
||||||
|
printf( "tmphash:0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
|
||||||
|
tmphash[0], tmphash[1], tmphash[2], tmphash[3], tmphash[4], tmphash[5],
|
||||||
|
tmphash[6], tmphash[7], tmphash[8], tmphash[9], tmphash[10], tmphash[11],
|
||||||
|
tmphash[12], tmphash[13], tmphash[14], tmphash[15], tmphash[16], tmphash[17],
|
||||||
|
tmphash[18], tmphash[19]);
|
||||||
|
*/
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CARDi_Init( CARDRomHashContext *context, RomHeader* header)
|
||||||
|
{
|
||||||
|
context->bytes_per_sector = header->digest1_block_size;
|
||||||
|
context->sectors_per_block = header->digest2_covered_digest1_num;
|
||||||
|
|
||||||
|
context->area_ntr.offset = header->nitro_digest_area_rom_offset;
|
||||||
|
context->area_ntr.length = header->nitro_digest_area_size;
|
||||||
|
context->area_ltd.offset = header->twl_digest_area_rom_offset;
|
||||||
|
context->area_ltd.length = header->twl_digest_area_size;
|
||||||
|
|
||||||
|
context->sector_hash.offset = header->digest1_table_offset;
|
||||||
|
context->sector_hash.length = header->digest1_table_size;
|
||||||
|
context->block_hash.offset = header->digest2_table_offset;
|
||||||
|
context->block_hash.length = header->digest2_table_size;
|
||||||
|
|
||||||
|
context->block_max = CARD_ROM_HASH_BLOCK_MAX;
|
||||||
|
context->sector_max = CARD_ROM_HASH_SECTOR_MAX;
|
||||||
|
|
||||||
|
// digest2
|
||||||
|
context->master_hash = (u8*)malloc( (1024*1024*1024/8) /
|
||||||
|
(header->digest1_block_size * header->digest2_covered_digest1_num) *
|
||||||
|
CARD_ROM_HASH_SIZE);
|
||||||
|
// digest1
|
||||||
|
context->hash = (u8*)malloc( header->digest2_covered_digest1_num * CARD_ROM_HASH_SIZE);
|
||||||
|
// rom image
|
||||||
|
context->buffer = (u8*)malloc( header->digest1_block_size);
|
||||||
|
|
||||||
|
// rom size
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
u32 rom_size;
|
||||||
|
for( i=0; i<header->rom_size; i++)
|
||||||
|
{
|
||||||
|
rom_size *= 2;
|
||||||
|
}
|
||||||
|
context->rom_size = (rom_size * 1024 / 8 * 1024);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*
|
||||||
|
Name: CARDi_GetHashSectorIndex
|
||||||
|
|
||||||
|
Description: 指定のROMオフセットが属するセクタ番号を取得。
|
||||||
|
|
||||||
|
Arguments: context : CARDRomHashContext構造体
|
||||||
|
offset : ROMオフセット
|
||||||
|
|
||||||
|
Returns: 指定のROMオフセットが属するセクタ番号。
|
||||||
|
*---------------------------------------------------------------------------*/
|
||||||
|
u32 CARDi_GetHashSectorIndex(const CARDRomHashContext *context, u32 offset)
|
||||||
|
{
|
||||||
|
offset -= context->area_ntr.offset;
|
||||||
|
if (offset >= context->area_ntr.length)
|
||||||
|
{
|
||||||
|
offset += (context->area_ntr.offset - context->area_ltd.offset);
|
||||||
|
if (offset < context->area_ltd.length)
|
||||||
|
{
|
||||||
|
offset += context->area_ntr.length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("specified ROM address is outof-range.(unsafe without secure hash)\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return offset / context->bytes_per_sector;
|
||||||
|
}
|
||||||
|
|
||||||
|
//static CARDRomHashBlock* CARDi_TouchRomHashBlock(CARDRomHashContext *context, u32 sector)
|
||||||
|
//{
|
||||||
|
//}
|
||||||
|
|
||||||
|
void CARDi_CheckHash(CARDRomHashContext *context, FILE* fp, u32 start, u32 size, RomHeader* header)
|
||||||
|
{
|
||||||
|
long nowfp;
|
||||||
|
u32 offset;
|
||||||
|
int linear_rom_sector;
|
||||||
|
u32 i, j;
|
||||||
|
|
||||||
|
nowfp = ftell( fp);
|
||||||
|
|
||||||
|
for( j=0; j<(size/(context->bytes_per_sector * context->sectors_per_block)); j++)
|
||||||
|
{
|
||||||
|
for( i=0; i<context->sectors_per_block; i++)
|
||||||
|
{
|
||||||
|
offset = start +
|
||||||
|
(i * context->bytes_per_sector) +
|
||||||
|
(j * (context->sectors_per_block * context->bytes_per_sector));
|
||||||
|
|
||||||
|
printf( "%s, %d (offset:0x%lx), 0x%lx, 0x%lx, %ld, %ld\n", __FUNCTION__, __LINE__, offset, context->bytes_per_sector, context->sectors_per_block, i, j);
|
||||||
|
/* ROMデータを読む */
|
||||||
|
fseek( fp, offset, SEEK_SET);
|
||||||
|
fread( context->buffer, context->bytes_per_sector, 1, fp);
|
||||||
|
|
||||||
|
/* Digest1を読む */
|
||||||
|
linear_rom_sector = CARDi_GetHashSectorIndex( context, offset);
|
||||||
|
fseek( fp, (header->digest1_table_offset + (linear_rom_sector * CARD_ROM_HASH_SIZE)), SEEK_SET);
|
||||||
|
fread( &(context->hash[i * CARD_ROM_HASH_SIZE]), CARD_ROM_HASH_SIZE, 1, fp);
|
||||||
|
|
||||||
|
printf( "-----digest1 check-----\n");
|
||||||
|
printf( "i = %ld, linear = %d\n", i, linear_rom_sector);
|
||||||
|
/* ROMデータのHashをDigest1と比較 */
|
||||||
|
CARDi_CompareHash( &(context->hash[i * CARD_ROM_HASH_SIZE]),
|
||||||
|
context->buffer, context->bytes_per_sector);
|
||||||
|
printf( "-----------------------\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek( fp, nowfp, SEEK_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Digest1Check(CARDRomHashContext *context, FILE* fp, RomHeader* header, u32 start_offset, u32 size)
|
||||||
|
{
|
||||||
|
int digest1_index;
|
||||||
|
u32 offset, rest;
|
||||||
|
bool ret = true;
|
||||||
|
|
||||||
|
rest = size;
|
||||||
|
offset = start_offset;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if( !(((start_offset >= header->aes_target_rom_offset)&&
|
||||||
|
(start_offset <= (header->aes_target_rom_offset + header->aes_target_size))) ||
|
||||||
|
(((start_offset + size) >= header->aes_target_rom_offset)&&
|
||||||
|
((start_offset + size) <= (header->aes_target_rom_offset + header->aes_target_size)))))
|
||||||
|
{
|
||||||
|
|
||||||
|
/* ROMデータを読む */
|
||||||
|
fseek( fp, offset, SEEK_SET);
|
||||||
|
fread( context->buffer, context->bytes_per_sector, 1, fp);
|
||||||
|
|
||||||
|
/* Digest1を読む */
|
||||||
|
digest1_index = CARDi_GetHashSectorIndex( context, offset);
|
||||||
|
fseek( fp, (header->digest1_table_offset + (digest1_index * CARD_ROM_HASH_SIZE)), SEEK_SET);
|
||||||
|
fread( context->hash, CARD_ROM_HASH_SIZE, 1, fp);
|
||||||
|
|
||||||
|
/* ROMデータのHashをDigest1と比較 */
|
||||||
|
if( !CARDi_CompareHash( context->hash, context->buffer, context->bytes_per_sector))
|
||||||
|
{
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rest -= context->bytes_per_sector;
|
||||||
|
offset += context->bytes_per_sector;
|
||||||
|
}
|
||||||
|
while( rest);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Digest2Check(CARDRomHashContext *context, FILE* fp, RomHeader* header)
|
||||||
|
{
|
||||||
|
bool ret = true;
|
||||||
|
int i, j;
|
||||||
|
int digest1_index_num = (header->digest1_table_size / header->digest1_block_size);
|
||||||
|
|
||||||
|
for( i=0; i<digest1_index_num; )
|
||||||
|
{
|
||||||
|
for( j=0; j<(int)(header->digest2_covered_digest1_num); j++)
|
||||||
|
{
|
||||||
|
fseek( fp, (header->digest1_table_offset + ((i+j) * CARD_ROM_HASH_SIZE)), SEEK_SET);
|
||||||
|
fread( &(context->hash[j * CARD_ROM_HASH_SIZE]), CARD_ROM_HASH_SIZE, 1, fp);
|
||||||
|
}
|
||||||
|
/* Digest1をDigest2と比較 */
|
||||||
|
if( !CARDi_CompareHash( &(context->master_hash[(i/context->sectors_per_block) * CARD_ROM_HASH_SIZE]),
|
||||||
|
context->hash, (CARD_ROM_HASH_SIZE * context->sectors_per_block)))
|
||||||
|
{
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
i+= header->digest2_covered_digest1_num;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CARD_CheckHash(CARDRomHashContext *context, RomHeader* header, FILE* fp)
|
||||||
|
{
|
||||||
|
long nowfp;
|
||||||
|
nowfp = ftell( fp);
|
||||||
|
fseek( fp, header->digest2_table_offset, SEEK_SET);
|
||||||
|
fread( context->master_hash, header->digest2_table_size, 1, fp);
|
||||||
|
fseek( fp, nowfp, SEEK_SET);
|
||||||
|
|
||||||
|
printf( "\n");
|
||||||
|
printf( "nitro digest area check\n");
|
||||||
|
printf( "-----------------------\n");
|
||||||
|
// NITROダイジェストエリア検証
|
||||||
|
if( Digest1Check( context, fp, header, header->nitro_digest_area_rom_offset, header->nitro_digest_area_size))
|
||||||
|
{
|
||||||
|
printf( "(検証OK.)\n");
|
||||||
|
}
|
||||||
|
printf( "-----------------------\n\n");
|
||||||
|
|
||||||
|
printf( "twl digest area check\n");
|
||||||
|
printf( "-----------------------\n");
|
||||||
|
// TWLダイジェストエリア検証
|
||||||
|
if( Digest1Check( context, fp, header, header->twl_digest_area_rom_offset, header->twl_digest_area_size))
|
||||||
|
{
|
||||||
|
printf( "(検証OK.)\n");
|
||||||
|
}
|
||||||
|
printf( "-----------------------\n\n");
|
||||||
|
|
||||||
|
printf( "digest2 check\n");
|
||||||
|
printf( "-----------------------\n");
|
||||||
|
if( Digest2Check( context, fp, header))
|
||||||
|
{
|
||||||
|
printf( "(検証OK.)\n");
|
||||||
|
}
|
||||||
|
printf( "-----------------------\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
static void CARDi_ReadRomHashImageDirect(CARDRomHashContext *context, void *buffer, u32 offset, u32 length)
|
||||||
|
{
|
||||||
|
const u32 sectunit = context->bytes_per_sector;
|
||||||
|
const u32 blckunit = context->sectors_per_block;
|
||||||
|
u32 position = offset;
|
||||||
|
u32 end = length + offset;
|
||||||
|
u32 sector = CARDi_GetHashSectorIndex(context, position);
|
||||||
|
long nowgfp;
|
||||||
|
FILE* gfp;
|
||||||
|
|
||||||
|
while (position < end)
|
||||||
|
{
|
||||||
|
// 今回取得可能な最小単位のイメージを同期読み込み。
|
||||||
|
nowgfp = ftell( gfp);
|
||||||
|
fseek( gfp, position, SEEK_SET);
|
||||||
|
u32 available = fread( buffer, end - position, 1, gfp);
|
||||||
|
// 今回の検証中に必要となりそうなブロックを前もってアクセス。
|
||||||
|
// (void)CARDi_TouchRomHashBlock(context, sector);
|
||||||
|
// 取得したイメージの正当性を検証。
|
||||||
|
while (available >= sectunit)
|
||||||
|
{
|
||||||
|
CARDRomHashBlock *block = CARDi_TouchRomHashBlock(context, sector);
|
||||||
|
u32 slot = sector - block->index * blckunit;
|
||||||
|
while ((slot < blckunit) && (available >= sectunit))
|
||||||
|
{
|
||||||
|
// 必要ならここでブロック単位のハッシュテーブルを検証。
|
||||||
|
if (block != context->valid_block)
|
||||||
|
{
|
||||||
|
OSIntrMode bak_cpsr = OS_DisableInterrupts();
|
||||||
|
while (context->loading_block)
|
||||||
|
{
|
||||||
|
OS_SleepThread(NULL);
|
||||||
|
}
|
||||||
|
if (block == context->loaded_block)
|
||||||
|
{
|
||||||
|
context->loaded_block = block->next;
|
||||||
|
}
|
||||||
|
(void)OS_RestoreInterrupts(bak_cpsr);
|
||||||
|
CARDi_CompareHash(&context->master_hash[block->index * CARD_ROM_HASH_SIZE],
|
||||||
|
block->hash, CARD_ROM_HASH_SIZE * blckunit);
|
||||||
|
block->next = context->valid_block;
|
||||||
|
context->valid_block = block;
|
||||||
|
}
|
||||||
|
// イメージのハッシュを計算。
|
||||||
|
CARDi_CompareHash(&block->hash[slot * CARD_ROM_HASH_SIZE], buffer, sectunit);
|
||||||
|
position += sectunit;
|
||||||
|
available -= sectunit;
|
||||||
|
buffer = ((u8 *)buffer) + sectunit;
|
||||||
|
slot += 1;
|
||||||
|
sector += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/*---------------------------------------------------------------------------*
|
||||||
|
Name: CARDi_ReadRomHashImageDirect
|
||||||
|
|
||||||
|
Description: ハッシュコンテキストへキャッシュせずに転送先へ直接コピー。
|
||||||
|
|
||||||
|
Arguments: context : CARDRomHashContext構造体。
|
||||||
|
buffer : 転送先バッファ。(4バイト整合されている必要がある)
|
||||||
|
offset : アクセスするROMオフセット。
|
||||||
|
length : 転送サイズ。
|
||||||
|
|
||||||
|
Returns: None.
|
||||||
|
*---------------------------------------------------------------------------*/
|
||||||
|
static void CARDi_ReadRomHashImageDirect(CARDRomHashContext *context, void *buffer, u32 offset, u32 length)
|
||||||
|
{
|
||||||
|
const u32 sectunit = context->bytes_per_sector;
|
||||||
|
const u32 blckunit = context->sectors_per_block;
|
||||||
|
u32 position = offset;
|
||||||
|
u32 end = length + offset;
|
||||||
|
u32 sector = CARDi_GetHashSectorIndex(context, position);
|
||||||
|
while (position < end)
|
||||||
|
{
|
||||||
|
// 今回取得可能な最小単位のイメージを同期読み込み。
|
||||||
|
u32 available = (u32)(*context->ReadSync)(context->userdata, buffer, position, end - position);
|
||||||
|
// 今回の検証中に必要となりそうなブロックを前もってアクセス。
|
||||||
|
(void)CARDi_TouchRomHashBlock(context, sector);
|
||||||
|
// 次回に必要となる分の読み込み準備を要求。
|
||||||
|
if (context->ReadAsync && (position + available < end))
|
||||||
|
{
|
||||||
|
(void)(*context->ReadAsync)(context->userdata, NULL, position + available, end - (position + available));
|
||||||
|
}
|
||||||
|
// 取得したイメージの正当性を検証。
|
||||||
|
while (available >= sectunit)
|
||||||
|
{
|
||||||
|
CARDRomHashBlock *block = CARDi_TouchRomHashBlock(context, sector);
|
||||||
|
u32 slot = sector - block->index * blckunit;
|
||||||
|
while ((slot < blckunit) && (available >= sectunit))
|
||||||
|
{
|
||||||
|
// 必要ならここでブロック単位のハッシュテーブルを検証。
|
||||||
|
if (block != context->valid_block)
|
||||||
|
{
|
||||||
|
OSIntrMode bak_cpsr = OS_DisableInterrupts();
|
||||||
|
while (context->loading_block)
|
||||||
|
{
|
||||||
|
OS_SleepThread(NULL);
|
||||||
|
}
|
||||||
|
if (block == context->loaded_block)
|
||||||
|
{
|
||||||
|
context->loaded_block = block->next;
|
||||||
|
}
|
||||||
|
(void)OS_RestoreInterrupts(bak_cpsr);
|
||||||
|
CARDi_CompareHash(&context->master_hash[block->index * CARD_ROM_HASH_SIZE],
|
||||||
|
block->hash, CARD_ROM_HASH_SIZE * blckunit);
|
||||||
|
block->next = context->valid_block;
|
||||||
|
context->valid_block = block;
|
||||||
|
}
|
||||||
|
// イメージのハッシュを計算。
|
||||||
|
CARDi_CompareHash(&block->hash[slot * CARD_ROM_HASH_SIZE], buffer, sectunit);
|
||||||
|
position += sectunit;
|
||||||
|
available -= sectunit;
|
||||||
|
buffer = ((u8 *)buffer) + sectunit;
|
||||||
|
slot += 1;
|
||||||
|
sector += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*
|
||||||
|
Name: MATH_CalcHMACSHA1
|
||||||
|
|
||||||
|
Description: HMAC-SHA-1 を計算する。
|
||||||
|
|
||||||
|
Arguments: digest HMAC-SHA-1 値を格納する場所へのポインタ
|
||||||
|
data 入力データのポインタ
|
||||||
|
dataLength 入力データ長
|
||||||
|
key 鍵のポインタ
|
||||||
|
keyLength 鍵の長さ
|
||||||
|
|
||||||
|
Returns: None.
|
||||||
|
*---------------------------------------------------------------------------*/
|
||||||
|
void MATH_CalcHMACSHA1(void *digest, const void *bin_ptr, u32 bin_len, const void *key_ptr, u32 key_len)
|
||||||
|
{
|
||||||
|
MATHSHA1Context context;
|
||||||
|
unsigned char hash_buf[ MATH_SHA1_DIGEST_SIZE ]; /* ハッシュ関数から得るハッシュ値 */
|
||||||
|
|
||||||
|
MATHiHMACFuncs hash2funcs = {
|
||||||
|
MATH_SHA1_DIGEST_SIZE,
|
||||||
|
(512/8),
|
||||||
|
};
|
||||||
|
|
||||||
|
hash2funcs.context = &context;
|
||||||
|
hash2funcs.hash_buf = hash_buf;
|
||||||
|
hash2funcs.HashReset = (void (*)(void*)) MATH_SHA1Init;
|
||||||
|
hash2funcs.HashSetSource = (void (*)(void*, const void*, u32)) MATH_SHA1Update;
|
||||||
|
hash2funcs.HashGetDigest = (void (*)(void*, void*)) MATH_SHA1GetHash;
|
||||||
|
|
||||||
|
MATHi_CalcHMAC(digest, bin_ptr, bin_len, key_ptr, key_len, &hash2funcs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*
|
||||||
|
Name: CARDi_CompareHash
|
||||||
|
|
||||||
|
Description: ハッシュによる正当性チェック。(HMAC-SHA1)
|
||||||
|
|
||||||
|
Arguments: hash : 比較基準となるハッシュ値
|
||||||
|
src : チェック対象のイメージ
|
||||||
|
len : チェック対象のサイズ
|
||||||
|
|
||||||
|
Returns: None.
|
||||||
|
*---------------------------------------------------------------------------*/
|
||||||
|
static void CARDi_CompareHash(const void *hash, void *buffer, u32 length)
|
||||||
|
{
|
||||||
|
u8 tmphash[CARD_ROM_HASH_SIZE];
|
||||||
|
|
||||||
|
MATH_CalcHMACSHA1(tmphash, buffer, length, CARDiHmacKey, sizeof(CARDiHmacKey));
|
||||||
|
|
||||||
|
if (MI_CpuComp8(hash, tmphash, sizeof(tmphash)) != 0)
|
||||||
|
{
|
||||||
|
printf("ROM-hash comparation error!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
90
build/tools/TamperDetectorForSrl/card_hash.h
Normal file
90
build/tools/TamperDetectorForSrl/card_hash.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
|
||||||
|
#ifndef CARD_HASH_H_
|
||||||
|
#define CARD_HASH_H_
|
||||||
|
|
||||||
|
|
||||||
|
// 現時点でCARDライブラリが妥当と判断した定数。
|
||||||
|
// パフォーマンス計測の結果によって適宜変更してもよい。
|
||||||
|
static const u32 CARD_ROM_HASH_BLOCK_MAX = 4;
|
||||||
|
static const u32 CARD_ROM_HASH_SECTOR_MAX = 32;
|
||||||
|
|
||||||
|
|
||||||
|
// ROM領域情報構造体
|
||||||
|
typedef struct CARDRomRegion
|
||||||
|
{
|
||||||
|
u32 offset;
|
||||||
|
u32 length;
|
||||||
|
}
|
||||||
|
CARDRomRegion;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// SRLファイルのハッシュ管理構造体。
|
||||||
|
// 所要サイズはプログラムごとに異なり静的に算出できないため
|
||||||
|
// 初期化時にアリーナから適量だけ動的に確保する予定。
|
||||||
|
// 必要となるメモリは以下の通り。
|
||||||
|
// - マスターハッシュテーブル:
|
||||||
|
// ROMヘッダとハッシュ比較して正当性を判定する必要上、
|
||||||
|
// 初期化時にROMから一括ロードして常駐させておく。
|
||||||
|
// (ROMサイズ/セクタサイズ/セクタ単位)*20(SHA1)バイト必要で、
|
||||||
|
// 1Gbits:1024バイト:32セクタならば約80kBとなる。
|
||||||
|
// - ブロックキャッシュ:
|
||||||
|
// ブロック単位でROMイメージキャッシュとそのハッシュを管理する。
|
||||||
|
// ブロック境界をまたいだ離散的なアクセスを考慮して
|
||||||
|
// 常に複数を保持できるリスト構造にしておく必要がある。
|
||||||
|
// (20 * セクタ単位 + α) の構造体をリスト総数の分だけ必要。
|
||||||
|
// - セクタキャッシュ:
|
||||||
|
// 実際のイメージキャッシュを保持する。
|
||||||
|
// ブロックが全セクタをあまねく参照するとは限らないため
|
||||||
|
// セクタも別途リスト構造として管理する必要がある。
|
||||||
|
typedef struct CARDRomHashContext
|
||||||
|
{
|
||||||
|
u32 rom_size;
|
||||||
|
// ROMヘッダから取得する基本設定
|
||||||
|
CARDRomRegion area_ntr;
|
||||||
|
CARDRomRegion area_ltd;
|
||||||
|
CARDRomRegion sector_hash;
|
||||||
|
CARDRomRegion block_hash;
|
||||||
|
u32 bytes_per_sector;
|
||||||
|
u32 sectors_per_block;
|
||||||
|
u32 block_max;
|
||||||
|
u32 sector_max;
|
||||||
|
|
||||||
|
// データとハッシュをロードするデバイスインタフェース
|
||||||
|
// void *userdata;
|
||||||
|
// MIDeviceReadFunction ReadSync;
|
||||||
|
// MIDeviceReadFunction ReadAsync;
|
||||||
|
|
||||||
|
// ロード処理中のスレッド。
|
||||||
|
// OSThread *loader;
|
||||||
|
// void *recent_load;
|
||||||
|
/*
|
||||||
|
// セクタとブロックのキャッシュ
|
||||||
|
CARDRomHashSector *loading_sector; // メディアロード待ちセクタ
|
||||||
|
CARDRomHashSector *loaded_sector; // ハッシュ検証待ちセクタ
|
||||||
|
CARDRomHashSector *valid_sector; // 正当性検証済みセクタ
|
||||||
|
CARDRomHashBlock *loading_block; // メディアロード待ちブロック
|
||||||
|
CARDRomHashBlock *loaded_block; // ハッシュ検証待ちブロック
|
||||||
|
CARDRomHashBlock *valid_block; // 正当性検証済みブロック
|
||||||
|
*/
|
||||||
|
// アリーナから確保した配列
|
||||||
|
u8 *master_hash; // ブロックのハッシュ配列
|
||||||
|
/*
|
||||||
|
u8 *images; // セクタイメージ
|
||||||
|
u8 *hashes; // ブロック内のハッシュ配列
|
||||||
|
CARDRomHashSector *sectors; // セクタ情報
|
||||||
|
CARDRomHashBlock *blocks; // ブロック情報
|
||||||
|
*/
|
||||||
|
u8 *buffer;
|
||||||
|
u8 *hash;
|
||||||
|
}
|
||||||
|
CARDRomHashContext;
|
||||||
|
|
||||||
|
|
||||||
|
void CARDi_Init( CARDRomHashContext *context, RomHeader* header);
|
||||||
|
void CARDi_CheckHash(CARDRomHashContext *context, FILE* fp, u32 sect, u32 size, RomHeader* header);
|
||||||
|
bool Digest2Check(CARDRomHashContext *context, FILE* fp, RomHeader* header);
|
||||||
|
void CARD_CheckHash(CARDRomHashContext *context, RomHeader* header, FILE* fp);
|
||||||
|
|
||||||
|
|
||||||
|
#endif //CARD_HASH_H_
|
||||||
@ -286,6 +286,14 @@ void Checker::AnalyzeHeader( RomHeader* gHeaderBuf, Entry* gEntry, RomHeader* mH
|
|||||||
(u32)(mHeaderBuf->digest2_table_size),
|
(u32)(mHeaderBuf->digest2_table_size),
|
||||||
false, PRINT_LEVEL_1);
|
false, PRINT_LEVEL_1);
|
||||||
printf( "------------------\n");
|
printf( "------------------\n");
|
||||||
|
|
||||||
|
printf( "AES TARGET\n");
|
||||||
|
Diff( (u32)(gHeaderBuf->aes_target_rom_offset),
|
||||||
|
(u32)(gHeaderBuf->aes_target_size),
|
||||||
|
(u32)(mHeaderBuf->aes_target_rom_offset),
|
||||||
|
(u32)(mHeaderBuf->aes_target_size),
|
||||||
|
false, PRINT_LEVEL_1);
|
||||||
|
printf( "------------------\n");
|
||||||
};
|
};
|
||||||
|
|
||||||
// genuine 領域を登録
|
// genuine 領域を登録
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
//#include "nitro_romheader.h"
|
//#include "nitro_romheader.h"
|
||||||
#include "twl_format_rom.h"
|
#include "twl_format_rom.h"
|
||||||
#include "checker.h"
|
#include "checker.h"
|
||||||
|
#include "card_hash.h"
|
||||||
|
|
||||||
|
|
||||||
extern char* output_fname;
|
extern char* output_fname;
|
||||||
@ -87,6 +88,14 @@ int main (int argc, char *argv[])
|
|||||||
|
|
||||||
checker.Initialize( gfp, mfp, gBuf, mBuf, BUFFER_SIZE);
|
checker.Initialize( gfp, mfp, gBuf, mBuf, BUFFER_SIZE);
|
||||||
checker.LoadHeader( &gHeaderBuf, &mHeaderBuf);
|
checker.LoadHeader( &gHeaderBuf, &mHeaderBuf);
|
||||||
|
|
||||||
|
// ダイジェスト検証(digest1, digest2)
|
||||||
|
{
|
||||||
|
CARDRomHashContext context;
|
||||||
|
|
||||||
|
CARDi_Init( &context, &mHeaderBuf);
|
||||||
|
CARD_CheckHash( &context, &mHeaderBuf, mfp);
|
||||||
|
}
|
||||||
|
|
||||||
printf( "------------------\n");
|
printf( "------------------\n");
|
||||||
printf( "Nitro Rom Header\n");
|
printf( "Nitro Rom Header\n");
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user