mirror of
https://github.com/CTCaer/hekate.git
synced 2024-11-26 11:42:09 +00:00
keygen for 3.0.x, 4.0.x, 5.0.x added, 3.0.X FW booting, fixed TSEC wrong offset for 4.0.X
This commit is contained in:
parent
e7373548fa
commit
8b9e65e76f
4 changed files with 192 additions and 55 deletions
159
ipl/hos.c
159
ipl/hos.c
|
@ -59,6 +59,13 @@ static const u8 ckey_keyseed[0x10] =
|
||||||
static const u8 key8_keyseed[] =
|
static const u8 key8_keyseed[] =
|
||||||
{ 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 };
|
{ 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 };
|
||||||
|
|
||||||
|
static const u8 new_masterkey_seed[0x10] =
|
||||||
|
{ 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 };
|
||||||
|
|
||||||
|
static const u8 new_per_console_key[0x10] =
|
||||||
|
{ 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 };
|
||||||
|
|
||||||
|
|
||||||
static void _se_lock()
|
static void _se_lock()
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < 16; i++)
|
for (u32 i = 0; i < 16; i++)
|
||||||
|
@ -86,8 +93,8 @@ static void _se_lock()
|
||||||
gfx_hexdump(&gfx_con, SE_BASE, (void *)SE_BASE, 0x400);*/
|
gfx_hexdump(&gfx_con, SE_BASE, (void *)SE_BASE, 0x400);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
//Key derivation for < 4.0.0
|
// <-- key derivation algorithm
|
||||||
static int _keygen_1(u8 *keyblob, u32 kb, void *tsec_fw)
|
static int keygen(u8 *keyblob, u32 kb, void *tsec_fw)
|
||||||
{
|
{
|
||||||
u8 *tmp = (u8 *)malloc(0x10);
|
u8 *tmp = (u8 *)malloc(0x10);
|
||||||
|
|
||||||
|
@ -97,13 +104,8 @@ static int _keygen_1(u8 *keyblob, u32 kb, void *tsec_fw)
|
||||||
//Get TSEC key.
|
//Get TSEC key.
|
||||||
if (tsec_query(tmp, 1, tsec_fw) < 0)
|
if (tsec_query(tmp, 1, tsec_fw) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
se_aes_key_set(13, tmp, 0x10);
|
|
||||||
|
|
||||||
//Derive keyblob key from TSEC+SBK.
|
se_aes_key_set(13, tmp, 0x10);
|
||||||
memcpy(tmp, keyblob_keyseeds[kb], 0x10);
|
|
||||||
se_aes_crypt_block_ecb(13, 0, tmp, tmp);
|
|
||||||
se_aes_unwrap_key(13, 14, tmp);
|
|
||||||
se_aes_key_clear(14);
|
|
||||||
|
|
||||||
//TODO: verify keyblob CMAC.
|
//TODO: verify keyblob CMAC.
|
||||||
//se_aes_unwrap_key(11, 13, cmac_keyseed);
|
//se_aes_unwrap_key(11, 13, cmac_keyseed);
|
||||||
|
@ -111,7 +113,16 @@ static int _keygen_1(u8 *keyblob, u32 kb, void *tsec_fw)
|
||||||
//if (!memcmp(keyblob, tmp, 0x10))
|
//if (!memcmp(keyblob, tmp, 0x10))
|
||||||
// return 0;
|
// return 0;
|
||||||
|
|
||||||
//Decrypt keyblob and set keyslots.
|
switch(kb) {
|
||||||
|
// 1.0.0~2.0.0 FW
|
||||||
|
case 0: {
|
||||||
|
|
||||||
|
//Derive keyblob key from TSEC+SBK.
|
||||||
|
memcpy(tmp, keyblob_keyseeds[kb], 0x10);
|
||||||
|
se_aes_crypt_block_ecb(13, 0, tmp, tmp);
|
||||||
|
se_aes_unwrap_key(13, 14, tmp);
|
||||||
|
se_aes_key_clear(14);
|
||||||
|
|
||||||
se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10);
|
se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10);
|
||||||
se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10);
|
se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10);
|
||||||
se_aes_key_set(12, keyblob + 0x20, 0x10);
|
se_aes_key_set(12, keyblob + 0x20, 0x10);
|
||||||
|
@ -124,20 +135,112 @@ static int _keygen_1(u8 *keyblob, u32 kb, void *tsec_fw)
|
||||||
memcpy(tmp, mkey_keyseed_retail, 0x10);
|
memcpy(tmp, mkey_keyseed_retail, 0x10);
|
||||||
se_aes_unwrap_key(12, 12, tmp);
|
se_aes_unwrap_key(12, 12, tmp);
|
||||||
|
|
||||||
memcpy(tmp, key8_keyseed, 0x10);
|
|
||||||
se_key_acc_ctrl(8, 0x15);
|
|
||||||
se_aes_unwrap_key(8, 12, tmp);
|
|
||||||
|
|
||||||
//Generate console specific key.
|
//Generate console specific key.
|
||||||
memcpy(tmp, ckey_keyseed, 0x10);
|
memcpy(tmp, ckey_keyseed, 0x10);
|
||||||
se_aes_unwrap_key(13, 13, tmp);
|
se_aes_unwrap_key(13, 13, tmp);
|
||||||
|
|
||||||
|
memcpy(tmp, key8_keyseed, 0x10);
|
||||||
|
se_key_acc_ctrl(8, 0x15);
|
||||||
|
se_aes_unwrap_key(8, 12, tmp);
|
||||||
|
|
||||||
se_key_acc_ctrl(12, 0xFF);
|
se_key_acc_ctrl(12, 0xFF);
|
||||||
se_key_acc_ctrl(13, 0xFF);
|
se_key_acc_ctrl(13, 0xFF);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// 3.0.0~3.0.1 FW
|
||||||
|
case 1:
|
||||||
|
case 2: {
|
||||||
|
|
||||||
|
// keyslot 10
|
||||||
|
memcpy(tmp, keyblob_keyseeds[0], 0x10);
|
||||||
|
se_aes_crypt_block_ecb(13, 0, tmp, tmp);
|
||||||
|
se_aes_unwrap_key(10, 14, tmp);
|
||||||
|
|
||||||
|
// keyslot 13
|
||||||
|
memcpy(tmp, keyblob_keyseeds[kb], 0x10);
|
||||||
|
se_aes_crypt_block_ecb(13, 0, tmp, tmp);
|
||||||
|
se_aes_unwrap_key(13, 14, tmp);
|
||||||
|
|
||||||
|
se_aes_key_clear(14);
|
||||||
|
se_aes_key_clear(15);
|
||||||
|
|
||||||
|
se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10);
|
||||||
|
se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10);
|
||||||
|
se_aes_key_set(12, keyblob + 0x20, 0x10);
|
||||||
|
|
||||||
|
//TODO: for some reason SE likes to hang if we don't execute an operation here.
|
||||||
|
memcpy(tmp, mkey_keyseed_retail, 0x10);
|
||||||
|
se_aes_crypt_block_ecb(12, 0, tmp, tmp);
|
||||||
|
|
||||||
|
//Generate retail master key.
|
||||||
|
memcpy(tmp, mkey_keyseed_retail, 0x10);
|
||||||
|
se_aes_unwrap_key(12, 12, tmp);
|
||||||
|
|
||||||
|
//Generate console specific key.
|
||||||
|
memcpy(tmp, ckey_keyseed, 0x10);
|
||||||
|
se_aes_unwrap_key(13, 10, tmp);
|
||||||
|
se_aes_key_clear(10);
|
||||||
|
|
||||||
|
memcpy(tmp, key8_keyseed, 0x10);
|
||||||
|
se_key_acc_ctrl(8, 0x15);
|
||||||
|
se_aes_unwrap_key(8, 12, tmp);
|
||||||
|
|
||||||
|
se_key_acc_ctrl(12, 0xFF);
|
||||||
|
se_key_acc_ctrl(13, 0xFF);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 4.0.0~5.0.1 FW
|
||||||
|
case 3:
|
||||||
|
case 4: {
|
||||||
|
se_key_acc_ctrl(14, 0x15);
|
||||||
|
se_key_acc_ctrl(15, 0x15);
|
||||||
|
|
||||||
|
// keyslot 15
|
||||||
|
memcpy(tmp, keyblob_keyseeds[0], 0x10);
|
||||||
|
se_aes_crypt_block_ecb(13, 0, tmp, tmp);
|
||||||
|
se_aes_unwrap_key(15, 14, tmp);
|
||||||
|
|
||||||
|
// keyslot 13
|
||||||
|
memcpy(tmp, keyblob_keyseeds[kb], 0x10);
|
||||||
|
se_aes_crypt_block_ecb(13, 0, tmp, tmp);
|
||||||
|
se_aes_unwrap_key(13, 14, tmp);
|
||||||
|
|
||||||
|
se_aes_key_clear(14);
|
||||||
|
|
||||||
|
se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10);
|
||||||
|
|
||||||
|
// keyslot 11
|
||||||
|
se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10);
|
||||||
|
se_aes_key_set(12, keyblob + 0x20, 0x10);
|
||||||
|
|
||||||
|
// keyslot 14
|
||||||
|
memcpy(tmp, new_masterkey_seed, 0x10);
|
||||||
|
se_aes_unwrap_key(14, 12, tmp);
|
||||||
|
|
||||||
|
// keyslot 12
|
||||||
|
memcpy(tmp, mkey_keyseed_retail, 0x10);
|
||||||
|
se_aes_unwrap_key(12, 12, tmp);
|
||||||
|
|
||||||
|
// keyslot 13
|
||||||
|
memcpy(tmp, new_per_console_key, 0x10);
|
||||||
|
se_aes_unwrap_key(13, 15, tmp);
|
||||||
|
|
||||||
|
// keyslot 15
|
||||||
|
memcpy(tmp, ckey_keyseed, 0x10);
|
||||||
|
se_aes_unwrap_key(15, 13, tmp);
|
||||||
|
|
||||||
|
se_key_acc_ctrl(12, 0xFF);
|
||||||
|
se_key_acc_ctrl(15, 0xFF);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
free(tmp);
|
free(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef struct _launch_ctxt_t
|
typedef struct _launch_ctxt_t
|
||||||
{
|
{
|
||||||
void *keyblob;
|
void *keyblob;
|
||||||
|
@ -324,13 +427,17 @@ int hos_launch(ini_sec_t *cfg)
|
||||||
if (!_read_emmc_pkg1(&ctxt))
|
if (!_read_emmc_pkg1(&ctxt))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
//XXX: remove this once we support 3+.
|
//Read package1 and the correct keyblob.
|
||||||
if (ctxt.pkg1_id->kb > 0)
|
if (!_read_emmc_pkg1(&ctxt))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
//XXX: remove this once we support 3+.
|
||||||
|
//if (ctxt.pkg1_id->kb > 0)
|
||||||
|
// return 0;
|
||||||
|
|
||||||
DPRINTF("loaded pkg1 and keyblob\n");
|
DPRINTF("loaded pkg1 and keyblob\n");
|
||||||
//Generate keys.
|
//Generate keys.
|
||||||
_keygen_1(ctxt.keyblob, ctxt.pkg1_id->kb, (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off);
|
keygen(ctxt.keyblob, ctxt.pkg1_id->kb, (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off);
|
||||||
DPRINTF("generated keys\n");
|
DPRINTF("generated keys\n");
|
||||||
//Decrypt and unpack package1 if we require parts of it.
|
//Decrypt and unpack package1 if we require parts of it.
|
||||||
if (!ctxt.warmboot || !ctxt.secmon)
|
if (!ctxt.warmboot || !ctxt.secmon)
|
||||||
|
@ -347,27 +454,32 @@ DPRINTF("decrypted and unpacked pkg1\n");
|
||||||
//Set warmboot address in PMC.
|
//Set warmboot address in PMC.
|
||||||
PMC(APBDEV_PMC_SCRATCH1) = 0x8000D000;
|
PMC(APBDEV_PMC_SCRATCH1) = 0x8000D000;
|
||||||
//Replace 'SecureMonitor' if requested.
|
//Replace 'SecureMonitor' if requested.
|
||||||
if (ctxt.secmon)
|
if (ctxt.secmon) {
|
||||||
memcpy((void *)ctxt.pkg1_id->secmon_base, ctxt.secmon, ctxt.secmon_size);
|
memcpy((void *)ctxt.pkg1_id->secmon_base, ctxt.secmon, ctxt.secmon_size);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Else we patch it to allow for an unsigned package2.
|
//Else we patch it to allow for an unsigned package2.
|
||||||
patch_t *secmon_patchset = ctxt.pkg1_id->secmon_patchset;
|
patch_t *secmon_patchset = ctxt.pkg1_id->secmon_patchset;
|
||||||
|
if (secmon_patchset != NULL) {
|
||||||
for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++)
|
for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++)
|
||||||
*(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val;
|
*(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val;
|
||||||
}
|
|
||||||
DPRINTF("loaded warmboot.bin and secmon\n");
|
DPRINTF("loaded warmboot.bin and secmon\n");
|
||||||
|
|
||||||
//Read package2.
|
//Read package2.
|
||||||
if (!_read_emmc_pkg2(&ctxt))
|
if (!_read_emmc_pkg2(&ctxt))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
DPRINTF("read pkg2\n");
|
DPRINTF("read pkg2\n");
|
||||||
//Decrypt package2 and parse KIP1 blobs in INI1 section.
|
//Decrypt package2 and parse KIP1 blobs in INI1 section.
|
||||||
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2);
|
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2);
|
||||||
|
|
||||||
LIST_INIT(kip1_info);
|
LIST_INIT(kip1_info);
|
||||||
pkg2_parse_kips(&kip1_info, pkg2_hdr);
|
pkg2_parse_kips(&kip1_info, pkg2_hdr);
|
||||||
|
|
||||||
DPRINTF("parsed ini1\n");
|
DPRINTF("parsed ini1\n");
|
||||||
|
|
||||||
//Use the kernel included in package2 in case we didn't load one already.
|
//Use the kernel included in package2 in case we didn't load one already.
|
||||||
if (!ctxt.kernel)
|
if (!ctxt.kernel)
|
||||||
{
|
{
|
||||||
|
@ -382,6 +494,17 @@ DPRINTF("parsed ini1\n");
|
||||||
//Rebuild and encrypt package2.
|
//Rebuild and encrypt package2.
|
||||||
pkg2_build_encrypt((void *)0xA9800000, ctxt.kernel, ctxt.kernel_size, &kip1_info);
|
pkg2_build_encrypt((void *)0xA9800000, ctxt.kernel, ctxt.kernel_size, &kip1_info);
|
||||||
DPRINTF("rebuilt pkg2\n");
|
DPRINTF("rebuilt pkg2\n");
|
||||||
|
} else {
|
||||||
|
//Read package2.
|
||||||
|
if (!_read_emmc_pkg2(&ctxt))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
DPRINTF("read pkg2\n");
|
||||||
|
memcpy((void *)0xA9800000, ctxt.pkg2, ctxt.pkg2_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//Clear 'BootConfig'.
|
//Clear 'BootConfig'.
|
||||||
memset((void *)0x4003D000, 0, 0x3000);
|
memset((void *)0x4003D000, 0, 0x3000);
|
||||||
|
|
||||||
|
|
|
@ -171,6 +171,10 @@ void config_se_brom()
|
||||||
SE(SE_INT_STATUS_REG_OFFSET) = 0x1F;
|
SE(SE_INT_STATUS_REG_OFFSET) = 0x1F;
|
||||||
//Lock SSK (although it's not set and unused anyways).
|
//Lock SSK (although it's not set and unused anyways).
|
||||||
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 15 * 4) = 0x7E;
|
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 15 * 4) = 0x7E;
|
||||||
|
// Clear the boot reason to avoid problems later
|
||||||
|
PMC(APBDEV_PMC_SCRATCH200) = 0x0;
|
||||||
|
PMC(APBDEV_PMC_RST_STATUS_0) = 0x0;
|
||||||
|
PMC(APBDEV_PMC_SCRATCH49_0) = 0x0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void config_hw()
|
void config_hw()
|
||||||
|
|
|
@ -40,6 +40,13 @@ PATCHSET_DEF(_secmon_2_patchset,
|
||||||
{ 0xAC8 + 0xB58, _NOP() } //Sections SHA2.
|
{ 0xAC8 + 0xB58, _NOP() } //Sections SHA2.
|
||||||
);
|
);
|
||||||
|
|
||||||
|
PATCHSET_DEF(_secmon_3_patchset,
|
||||||
|
//Patch package2 decryption and signature/hash checks.
|
||||||
|
{ 0xAC8 + 0xA30, _NOP() }, //Header signature.
|
||||||
|
{ 0xAC8 + 0xAC0, _NOP() }, //Version.
|
||||||
|
{ 0xAC8 + 0xADC, _NOP() } //Sections SHA2.
|
||||||
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* package1.1 header: <wb, ldr, sm>
|
* package1.1 header: <wb, ldr, sm>
|
||||||
* package1.1 layout:
|
* package1.1 layout:
|
||||||
|
@ -56,7 +63,7 @@ static const pkg1_id_t _pkg1_ids[] = {
|
||||||
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, _secmon_2_patchset }, //2.0.0
|
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, _secmon_2_patchset }, //2.0.0
|
||||||
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, NULL }, //3.0.0
|
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, NULL }, //3.0.0
|
||||||
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, NULL }, //3.0.1
|
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, NULL }, //3.0.1
|
||||||
{ "20170921172629", 3, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, NULL }, //4.0.0
|
{ "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, NULL }, //4.0.0
|
||||||
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, NULL }, //5.0.0
|
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, NULL }, //5.0.0
|
||||||
{ NULL, 0, 0, 0, 0 } //End.
|
{ NULL, 0, 0, 0, 0 } //End.
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,5 +41,8 @@
|
||||||
#define APBDEV_PMC_SCRATCH188 0x810
|
#define APBDEV_PMC_SCRATCH188 0x810
|
||||||
#define APBDEV_PMC_SCRATCH190 0x818
|
#define APBDEV_PMC_SCRATCH190 0x818
|
||||||
#define APBDEV_PMC_SCRATCH200 0x840
|
#define APBDEV_PMC_SCRATCH200 0x840
|
||||||
|
#define APBDEV_PMC_RST_STATUS_0 0x1B4
|
||||||
|
#define APBDEV_PMC_SECURE_SCRATCH49_0 0x3A4
|
||||||
|
#define APBDEV_PMC_SCRATCH49_0 0x244
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue