Update to hekate bdk 5.6.0
This commit is contained in:
parent
a89e9b4d7f
commit
f2f3c5daf0
43 changed files with 1530 additions and 1533 deletions
|
@ -38,19 +38,14 @@ void set_default_configuration()
|
|||
h_cfg.autoboot = 0;
|
||||
h_cfg.autoboot_list = 0;
|
||||
h_cfg.bootwait = 3;
|
||||
h_cfg.se_keygen_done = 0;
|
||||
h_cfg.backlight = 100;
|
||||
h_cfg.autohosoff = 0;
|
||||
h_cfg.autonogc = 1;
|
||||
h_cfg.updater2p = 0;
|
||||
h_cfg.bootprotect = 0;
|
||||
h_cfg.errors = 0;
|
||||
h_cfg.eks = NULL;
|
||||
h_cfg.aes_slots_new = false;
|
||||
h_cfg.rcm_patched = fuse_check_patched_rcm();
|
||||
h_cfg.sbk_set = FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF;
|
||||
h_cfg.emummc_force_disable = false;
|
||||
h_cfg.t210b01 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01;
|
||||
|
||||
sd_power_cycle_time_start = 0;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#ifndef _CONFIG_H_
|
||||
#define _CONFIG_H_
|
||||
|
||||
#include "hos/hos.h"
|
||||
#include <utils/types.h>
|
||||
|
||||
typedef struct _hekate_config
|
||||
|
@ -33,13 +32,10 @@ typedef struct _hekate_config
|
|||
u32 bootprotect;
|
||||
// Global temporary config.
|
||||
bool t210b01;
|
||||
bool se_keygen_done;
|
||||
bool aes_slots_new;
|
||||
bool emummc_force_disable;
|
||||
bool rcm_patched;
|
||||
bool sbk_set;
|
||||
u32 errors;
|
||||
hos_eks_mbr_t *eks;
|
||||
} hekate_config;
|
||||
|
||||
void set_default_configuration();
|
||||
|
|
128
source/hos/hos.h
128
source/hos/hos.h
|
@ -18,122 +18,18 @@
|
|||
#ifndef _HOS_H_
|
||||
#define _HOS_H_
|
||||
|
||||
#include "pkg1.h"
|
||||
#include "pkg2.h"
|
||||
#include <sec/se_t210.h>
|
||||
#include <utils/types.h>
|
||||
#include <utils/ini.h>
|
||||
#include <sec/tsec.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#define KB_FIRMWARE_VERSION_100_200 0
|
||||
#define KB_FIRMWARE_VERSION_300 1
|
||||
#define KB_FIRMWARE_VERSION_301 2
|
||||
#define KB_FIRMWARE_VERSION_400 3
|
||||
#define KB_FIRMWARE_VERSION_500 4
|
||||
#define KB_FIRMWARE_VERSION_600 5
|
||||
#define KB_FIRMWARE_VERSION_620 6
|
||||
#define KB_FIRMWARE_VERSION_700 7
|
||||
#define KB_FIRMWARE_VERSION_810 8
|
||||
#define KB_FIRMWARE_VERSION_900 9
|
||||
#define KB_FIRMWARE_VERSION_910 10
|
||||
#define KB_FIRMWARE_VERSION_100 0
|
||||
#define KB_FIRMWARE_VERSION_300 1
|
||||
#define KB_FIRMWARE_VERSION_301 2
|
||||
#define KB_FIRMWARE_VERSION_400 3
|
||||
#define KB_FIRMWARE_VERSION_500 4
|
||||
#define KB_FIRMWARE_VERSION_600 5
|
||||
#define KB_FIRMWARE_VERSION_620 6
|
||||
#define KB_FIRMWARE_VERSION_700 7
|
||||
#define KB_FIRMWARE_VERSION_810 8
|
||||
#define KB_FIRMWARE_VERSION_900 9
|
||||
#define KB_FIRMWARE_VERSION_910 10
|
||||
#define KB_FIRMWARE_VERSION_1210 11
|
||||
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_1210
|
||||
|
||||
#define HOS_PKG11_MAGIC 0x31314B50
|
||||
#define HOS_EKS_MAGIC 0x30534B45
|
||||
|
||||
// Use official Mariko secmon when in stock.
|
||||
//#define HOS_MARIKO_STOCK_SECMON
|
||||
|
||||
typedef struct _exo_ctxt_t
|
||||
{
|
||||
bool fs_is_510;
|
||||
bool no_user_exceptions;
|
||||
bool user_pmu;
|
||||
bool *usb3_force;
|
||||
bool *cal0_blank;
|
||||
bool *cal0_allow_writes_sys;
|
||||
} exo_ctxt_t;
|
||||
|
||||
typedef struct _hos_eks_keys_t
|
||||
{
|
||||
u8 mkk[SE_KEY_128_SIZE];
|
||||
u8 fdk[SE_KEY_128_SIZE];
|
||||
} hos_eks_keys_t;
|
||||
|
||||
typedef struct _hos_eks_bis_keys_t
|
||||
{
|
||||
u8 crypt[SE_KEY_128_SIZE];
|
||||
u8 tweak[SE_KEY_128_SIZE];
|
||||
} hos_eks_bis_keys_t;
|
||||
|
||||
typedef struct _hos_eks_mbr_t
|
||||
{
|
||||
u32 magic;
|
||||
u8 enabled[5];
|
||||
u8 enabled_bis;
|
||||
u8 rsvd[2];
|
||||
u32 lot0;
|
||||
u8 dkg[SE_KEY_128_SIZE];
|
||||
u8 dkk[SE_KEY_128_SIZE];
|
||||
hos_eks_keys_t keys[5];
|
||||
hos_eks_bis_keys_t bis_keys[3];
|
||||
} hos_eks_mbr_t;
|
||||
|
||||
static_assert(sizeof(hos_eks_mbr_t) == 304, "HOS EKS size is wrong!");
|
||||
|
||||
typedef struct _launch_ctxt_t
|
||||
{
|
||||
void *keyblob;
|
||||
|
||||
void *pkg1;
|
||||
const pkg1_id_t *pkg1_id;
|
||||
const pkg2_kernel_id_t *pkg2_kernel_id;
|
||||
|
||||
void *warmboot;
|
||||
u32 warmboot_size;
|
||||
void *secmon;
|
||||
u32 secmon_size;
|
||||
void *exofatal;
|
||||
u32 exofatal_size;
|
||||
|
||||
void *pkg2;
|
||||
u32 pkg2_size;
|
||||
bool new_pkg2;
|
||||
|
||||
void *kernel;
|
||||
u32 kernel_size;
|
||||
|
||||
link_t kip1_list;
|
||||
char* kip1_patches;
|
||||
|
||||
bool svcperm;
|
||||
bool debugmode;
|
||||
bool stock;
|
||||
bool emummc_forced;
|
||||
|
||||
char *fss0_main_path;
|
||||
u32 fss0_hosver;
|
||||
bool fss0_experimental;
|
||||
bool atmosphere;
|
||||
|
||||
exo_ctxt_t exo_ctx;
|
||||
|
||||
ini_sec_t *cfg;
|
||||
} launch_ctxt_t;
|
||||
|
||||
typedef struct _merge_kip_t
|
||||
{
|
||||
void *kip1;
|
||||
link_t link;
|
||||
} merge_kip_t;
|
||||
|
||||
void hos_eks_get();
|
||||
void hos_eks_save(u32 kb);
|
||||
void hos_eks_clear(u32 kb);
|
||||
int hos_launch(ini_sec_t *cfg);
|
||||
int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt);
|
||||
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_1210 //!TODO: Update on mkey changes.
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,210 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
* Copyright (c) 2018 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "pkg2.h"
|
||||
#include <libs/compr/blz.h>
|
||||
#include <mem/heap.h>
|
||||
#include <sec/se.h>
|
||||
#include <utils/aarch64_util.h>
|
||||
|
||||
#include <gfx_utils.h>
|
||||
|
||||
u32 pkg2_newkern_ini1_val;
|
||||
u32 pkg2_newkern_ini1_start;
|
||||
u32 pkg2_newkern_ini1_end;
|
||||
|
||||
/*#include "util.h"
|
||||
#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||
#define DEBUG_PRINTING*/
|
||||
#define DPRINTF(...)
|
||||
|
||||
static u32 _pkg2_calc_kip1_size(pkg2_kip1_t *kip1)
|
||||
{
|
||||
u32 size = sizeof(pkg2_kip1_t);
|
||||
for (u32 j = 0; j < KIP1_NUM_SECTIONS; j++)
|
||||
size += kip1->sections[j].size_comp;
|
||||
return size;
|
||||
}
|
||||
|
||||
void pkg2_get_newkern_info(u8 *kern_data)
|
||||
{
|
||||
u32 pkg2_newkern_ini1_off = 0;
|
||||
pkg2_newkern_ini1_start = 0;
|
||||
|
||||
// Find static OP offset that is close to INI1 offset.
|
||||
u32 counter_ops = 0x100;
|
||||
while (counter_ops)
|
||||
{
|
||||
if (*(u32 *)(kern_data + 0x100 - counter_ops) == PKG2_NEWKERN_GET_INI1_HEURISTIC)
|
||||
{
|
||||
pkg2_newkern_ini1_off = 0x100 - counter_ops + 12; // OP found. Add 12 for the INI1 offset.
|
||||
break;
|
||||
}
|
||||
|
||||
counter_ops -= 4;
|
||||
}
|
||||
|
||||
// Offset not found?
|
||||
if (!counter_ops)
|
||||
return;
|
||||
|
||||
u32 info_op = *(u32 *)(kern_data + pkg2_newkern_ini1_off);
|
||||
pkg2_newkern_ini1_val = ((info_op & 0xFFFF) >> 3) + pkg2_newkern_ini1_off; // Parse ADR and PC.
|
||||
|
||||
pkg2_newkern_ini1_start = *(u32 *)(kern_data + pkg2_newkern_ini1_val);
|
||||
pkg2_newkern_ini1_end = *(u32 *)(kern_data + pkg2_newkern_ini1_val + 0x8);
|
||||
}
|
||||
|
||||
bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2)
|
||||
{
|
||||
u8 *ptr;
|
||||
// Check for new pkg2 type.
|
||||
if (!pkg2->sec_size[PKG2_SEC_INI1])
|
||||
{
|
||||
pkg2_get_newkern_info(pkg2->data);
|
||||
|
||||
if (!pkg2_newkern_ini1_start)
|
||||
return false;
|
||||
|
||||
ptr = pkg2->data + pkg2_newkern_ini1_start;
|
||||
*new_pkg2 = true;
|
||||
}
|
||||
else
|
||||
ptr = pkg2->data + pkg2->sec_size[PKG2_SEC_KERNEL];
|
||||
|
||||
pkg2_ini1_t *ini1 = (pkg2_ini1_t *)ptr;
|
||||
ptr += sizeof(pkg2_ini1_t);
|
||||
|
||||
for (u32 i = 0; i < ini1->num_procs; i++)
|
||||
{
|
||||
pkg2_kip1_t *kip1 = (pkg2_kip1_t *)ptr;
|
||||
pkg2_kip1_info_t *ki = (pkg2_kip1_info_t *)malloc(sizeof(pkg2_kip1_info_t));
|
||||
ki->kip1 = kip1;
|
||||
ki->size = _pkg2_calc_kip1_size(kip1);
|
||||
list_append(info, &ki->link);
|
||||
ptr += ki->size;
|
||||
DPRINTF(" kip1 %d:%s @ %08X (%08X)\n", i, kip1->name, (u32)kip1, ki->size);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)
|
||||
{
|
||||
u32 compClearMask = ~sectsToDecomp;
|
||||
if ((ki->kip1->flags & compClearMask) == ki->kip1->flags)
|
||||
return 0; // Already decompressed, nothing to do.
|
||||
|
||||
pkg2_kip1_t hdr;
|
||||
memcpy(&hdr, ki->kip1, sizeof(hdr));
|
||||
|
||||
unsigned int newKipSize = sizeof(hdr);
|
||||
for (u32 sectIdx = 0; sectIdx < KIP1_NUM_SECTIONS; sectIdx++)
|
||||
{
|
||||
u32 sectCompBit = 1u << sectIdx;
|
||||
// For compressed, cant get actual decompressed size without doing it, so use safe "output size".
|
||||
if (sectIdx < 3 && (sectsToDecomp & sectCompBit) && (hdr.flags & sectCompBit))
|
||||
newKipSize += hdr.sections[sectIdx].size_decomp;
|
||||
else
|
||||
newKipSize += hdr.sections[sectIdx].size_comp;
|
||||
}
|
||||
|
||||
pkg2_kip1_t* newKip = malloc(newKipSize);
|
||||
unsigned char* dstDataPtr = newKip->data;
|
||||
const unsigned char* srcDataPtr = ki->kip1->data;
|
||||
for (u32 sectIdx = 0; sectIdx < KIP1_NUM_SECTIONS; sectIdx++)
|
||||
{
|
||||
u32 sectCompBit = 1u << sectIdx;
|
||||
// Easy copy path for uncompressed or ones we dont want to uncompress.
|
||||
if (sectIdx >= 3 || !(sectsToDecomp & sectCompBit) || !(hdr.flags & sectCompBit))
|
||||
{
|
||||
unsigned int dataSize = hdr.sections[sectIdx].size_comp;
|
||||
if (dataSize == 0)
|
||||
continue;
|
||||
|
||||
memcpy(dstDataPtr, srcDataPtr, dataSize);
|
||||
srcDataPtr += dataSize;
|
||||
dstDataPtr += dataSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int compSize = hdr.sections[sectIdx].size_comp;
|
||||
unsigned int outputSize = hdr.sections[sectIdx].size_decomp;
|
||||
//gfx_printf("Decomping %s KIP1 sect %d of size %d...\n", (const char*)hdr.name, sectIdx, compSize);
|
||||
if (blz_uncompress_srcdest(srcDataPtr, compSize, dstDataPtr, outputSize) == 0)
|
||||
{
|
||||
gfx_printf("%kERROR decomping sect %d of %s KIP!%k\n", 0xFFFF0000, sectIdx, (char*)hdr.name, 0xFFCCCCCC);
|
||||
free(newKip);
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINTF("Done! Decompressed size is %d!\n", outputSize);
|
||||
}
|
||||
hdr.sections[sectIdx].size_comp = outputSize;
|
||||
srcDataPtr += compSize;
|
||||
dstDataPtr += outputSize;
|
||||
}
|
||||
|
||||
hdr.flags &= compClearMask;
|
||||
memcpy(newKip, &hdr, sizeof(hdr));
|
||||
newKipSize = dstDataPtr-(unsigned char*)(newKip);
|
||||
|
||||
free(ki->kip1);
|
||||
ki->kip1 = newKip;
|
||||
ki->size = newKipSize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pkg2_hdr_t *pkg2_decrypt(void *data)
|
||||
{
|
||||
u8 *pdata = (u8 *)data;
|
||||
|
||||
// Skip signature.
|
||||
pdata += 0x100;
|
||||
|
||||
pkg2_hdr_t *hdr = (pkg2_hdr_t *)pdata;
|
||||
|
||||
// Skip header.
|
||||
pdata += sizeof(pkg2_hdr_t);
|
||||
|
||||
// Decrypt header.
|
||||
se_aes_crypt_ctr(8, hdr, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr);
|
||||
//gfx_hexdump((u32)hdr, hdr, 0x100);
|
||||
|
||||
if (hdr->magic != PKG2_MAGIC)
|
||||
return NULL;
|
||||
|
||||
for (u32 i = 0; i < 4; i++)
|
||||
{
|
||||
DPRINTF("sec %d has size %08X\n", i, hdr->sec_size[i]);
|
||||
if (!hdr->sec_size[i])
|
||||
continue;
|
||||
|
||||
se_aes_crypt_ctr(8, pdata, hdr->sec_size[i], pdata, hdr->sec_size[i], &hdr->sec_ctr[i * 0x10]);
|
||||
//gfx_hexdump((u32)pdata, pdata, 0x100);
|
||||
|
||||
pdata += hdr->sec_size[i];
|
||||
}
|
||||
|
||||
return hdr;
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _PKG2_H_
|
||||
#define _PKG2_H_
|
||||
|
||||
#include <utils/types.h>
|
||||
#include <utils/list.h>
|
||||
|
||||
#define PKG2_MAGIC 0x31324B50
|
||||
#define PKG2_SEC_BASE 0x80000000
|
||||
#define PKG2_SEC_KERNEL 0
|
||||
#define PKG2_SEC_INI1 1
|
||||
|
||||
#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // Offset of OP + 12 is the INI1 offset.
|
||||
|
||||
extern u32 pkg2_newkern_ini1_val;
|
||||
extern u32 pkg2_newkern_ini1_start;
|
||||
extern u32 pkg2_newkern_ini1_end;
|
||||
|
||||
typedef struct _kernel_patch_t
|
||||
{
|
||||
u32 id;
|
||||
u32 off;
|
||||
u32 val;
|
||||
u32 *ptr;
|
||||
} kernel_patch_t;
|
||||
|
||||
typedef struct _pkg2_hdr_t
|
||||
{
|
||||
u8 ctr[0x10];
|
||||
u8 sec_ctr[0x40];
|
||||
u32 magic;
|
||||
u32 base;
|
||||
u32 pad0;
|
||||
u8 pkg2_ver;
|
||||
u8 bl_ver;
|
||||
u16 pad1;
|
||||
u32 sec_size[4];
|
||||
u32 sec_off[4];
|
||||
u8 sec_sha256[0x80];
|
||||
u8 data[];
|
||||
} pkg2_hdr_t;
|
||||
|
||||
typedef struct _pkg2_ini1_t
|
||||
{
|
||||
u32 magic;
|
||||
u32 size;
|
||||
u32 num_procs;
|
||||
u32 pad;
|
||||
} pkg2_ini1_t;
|
||||
|
||||
typedef struct _pkg2_kip1_sec_t
|
||||
{
|
||||
u32 offset;
|
||||
u32 size_decomp;
|
||||
u32 size_comp;
|
||||
u32 attrib;
|
||||
} pkg2_kip1_sec_t;
|
||||
|
||||
#define KIP1_NUM_SECTIONS 6
|
||||
|
||||
typedef struct _pkg2_kip1_t
|
||||
{
|
||||
u32 magic;
|
||||
u8 name[12];
|
||||
u64 tid;
|
||||
u32 proc_cat;
|
||||
u8 main_thrd_prio;
|
||||
u8 def_cpu_core;
|
||||
u8 res;
|
||||
u8 flags;
|
||||
pkg2_kip1_sec_t sections[KIP1_NUM_SECTIONS];
|
||||
u32 caps[0x20];
|
||||
u8 data[];
|
||||
} pkg2_kip1_t;
|
||||
|
||||
typedef struct _pkg2_kip1_info_t
|
||||
{
|
||||
pkg2_kip1_t *kip1;
|
||||
u32 size;
|
||||
link_t link;
|
||||
} pkg2_kip1_info_t;
|
||||
|
||||
typedef struct _pkg2_kernel_id_t
|
||||
{
|
||||
u8 hash[8];
|
||||
kernel_patch_t *kernel_patchset;
|
||||
} pkg2_kernel_id_t;
|
||||
|
||||
bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2);
|
||||
int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp);
|
||||
pkg2_hdr_t *pkg2_decrypt(void *data);
|
||||
|
||||
#endif
|
|
@ -23,7 +23,6 @@
|
|||
#include <gfx_utils.h>
|
||||
#include "../gfx/tui.h"
|
||||
#include "../hos/pkg1.h"
|
||||
#include "../hos/pkg2.h"
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <libs/nx_savedata/save.h>
|
||||
#include <mem/heap.h>
|
||||
|
@ -79,21 +78,6 @@ static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device
|
|||
// titlekey functions
|
||||
static bool _test_key_pair(const void *E, const void *D, const void *N);
|
||||
|
||||
static ALWAYS_INLINE u8 *_find_tsec_fw(const u8 *pkg1) {
|
||||
const u32 tsec_fw_align = 0x100;
|
||||
const u32 tsec_fw_first_instruction = 0xCF42004D;
|
||||
|
||||
for (const u32 *pos = (const u32 *)pkg1; (u8 *)pos < pkg1 + PKG1_MAX_SIZE; pos += tsec_fw_align / sizeof(u32))
|
||||
if (*pos == tsec_fw_first_instruction)
|
||||
return (u8 *)pos;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE u32 _get_tsec_fw_size(tsec_key_data_t *key_data) {
|
||||
return key_data->blob0_size + sizeof(tsec_key_data_t) + key_data->blob1_size + key_data->blob2_size + key_data->blob3_size + key_data->blob4_size;
|
||||
}
|
||||
|
||||
static u8 *_read_pkg1(const pkg1_id_t **pkg1_id) {
|
||||
if (emummc_storage_init_mmc()) {
|
||||
EPRINTF("Unable to init MMC.");
|
||||
|
@ -125,17 +109,18 @@ static u8 *_read_pkg1(const pkg1_id_t **pkg1_id) {
|
|||
|
||||
static void _derive_master_key_mariko(key_derivation_ctx_t *keys, bool is_dev) {
|
||||
// Relies on the SBK being properly set in slot 14
|
||||
se_aes_crypt_block_ecb(14, 0, keys->device_key_4x, device_master_key_source_kek_source);
|
||||
se_aes_crypt_block_ecb(14, DECRYPT, keys->device_key_4x, device_master_key_source_kek_source);
|
||||
// Relies on the Mariko KEK being properly set in slot 12
|
||||
se_aes_unwrap_key(8, 12, is_dev ? &mariko_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600] : &mariko_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600]);
|
||||
se_aes_crypt_block_ecb(8, 0, keys->master_key[KB_FIRMWARE_VERSION_MAX], master_key_source);
|
||||
se_aes_crypt_block_ecb(8, DECRYPT, keys->master_key[KB_FIRMWARE_VERSION_MAX], master_key_source);
|
||||
}
|
||||
|
||||
static int _run_ams_keygen(key_derivation_ctx_t *keys) {
|
||||
tsec_ctxt_t tsec_ctxt;
|
||||
tsec_ctxt.fw = tsec_keygen;
|
||||
tsec_ctxt.size = sizeof(tsec_keygen);
|
||||
int res = tsec_run_fw(&tsec_ctxt);
|
||||
tsec_ctxt.type = TSEC_FW_TYPE_NEW;
|
||||
int res = tsec_query(keys->temp_key, &tsec_ctxt);
|
||||
|
||||
if (res) {
|
||||
EPRINTFARGS("ERROR %d running keygen.\n", res);
|
||||
|
@ -149,19 +134,19 @@ static void _derive_master_keys_from_latest_key(key_derivation_ctx_t *keys, bool
|
|||
u32 tsec_root_key_slot = is_dev ? 11 : 13;
|
||||
// Derive all master keys based on current root key
|
||||
for (u32 i = KB_FIRMWARE_VERSION_810 - KB_FIRMWARE_VERSION_620; i < ARRAY_SIZE(master_kek_sources); i++) {
|
||||
se_aes_crypt_block_ecb(tsec_root_key_slot, 0, keys->master_kek[i + KB_FIRMWARE_VERSION_620], master_kek_sources[i]); // mkek = unwrap(tsec_root, mkeks)
|
||||
se_aes_crypt_block_ecb(tsec_root_key_slot, DECRYPT, keys->master_kek[i + KB_FIRMWARE_VERSION_620], master_kek_sources[i]); // mkek = unwrap(tsec_root, mkeks)
|
||||
se_aes_key_set(8, keys->master_kek[i + KB_FIRMWARE_VERSION_620], AES_128_KEY_SIZE); // mkey = unwrap(mkek, mkeys)
|
||||
se_aes_crypt_block_ecb(8, 0, keys->master_key[i + KB_FIRMWARE_VERSION_620], master_key_source);
|
||||
se_aes_crypt_block_ecb(8, DECRYPT, keys->master_key[i + KB_FIRMWARE_VERSION_620], master_key_source);
|
||||
}
|
||||
}
|
||||
|
||||
// Derive all lower master keys
|
||||
for (u32 i = KB_FIRMWARE_VERSION_MAX; i > 0; i--) {
|
||||
se_aes_key_set(8, keys->master_key[i], AES_128_KEY_SIZE);
|
||||
se_aes_crypt_block_ecb(8, 0, keys->master_key[i - 1], is_dev ? master_key_vectors_dev[i] : master_key_vectors[i]);
|
||||
se_aes_crypt_block_ecb(8, DECRYPT, keys->master_key[i - 1], is_dev ? master_key_vectors_dev[i] : master_key_vectors[i]);
|
||||
}
|
||||
se_aes_key_set(8, keys->master_key[0], AES_128_KEY_SIZE);
|
||||
se_aes_crypt_block_ecb(8, 0, keys->temp_key, is_dev ? master_key_vectors_dev[0] : master_key_vectors[0]);
|
||||
se_aes_crypt_block_ecb(8, DECRYPT, keys->temp_key, is_dev ? master_key_vectors_dev[0] : master_key_vectors[0]);
|
||||
|
||||
if (_key_exists(keys->temp_key)) {
|
||||
EPRINTFARGS("Unable to derive master keys for %s.", is_dev ? "dev" : "prod");
|
||||
|
@ -174,7 +159,7 @@ static void _derive_keyblob_keys(key_derivation_ctx_t *keys) {
|
|||
encrypted_keyblob_t *current_keyblob = (encrypted_keyblob_t *)keyblob_block;
|
||||
u32 keyblob_mac[AES_128_KEY_SIZE / 4] = {0};
|
||||
|
||||
if (h_cfg.sbk_set) {
|
||||
if (FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF) {
|
||||
u8 *aes_keys = (u8 *)calloc(0x1000, 1);
|
||||
se_get_aes_keys(aes_keys + 0x800, aes_keys, AES_128_KEY_SIZE);
|
||||
memcpy(keys->sbk, aes_keys + 14 * AES_128_KEY_SIZE, AES_128_KEY_SIZE);
|
||||
|
@ -192,13 +177,13 @@ static void _derive_keyblob_keys(key_derivation_ctx_t *keys) {
|
|||
|
||||
for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++, current_keyblob++) {
|
||||
minerva_periodic_training();
|
||||
se_aes_crypt_block_ecb(12, 0, keys->keyblob_key[i], keyblob_key_sources[i]); // temp = unwrap(kbks, tsec)
|
||||
se_aes_crypt_block_ecb(14, 0, keys->keyblob_key[i], keys->keyblob_key[i]); // kbk = unwrap(temp, sbk)
|
||||
se_aes_crypt_block_ecb(12, DECRYPT, keys->keyblob_key[i], keyblob_key_sources[i]); // temp = unwrap(kbks, tsec)
|
||||
se_aes_crypt_block_ecb(14, DECRYPT, keys->keyblob_key[i], keys->keyblob_key[i]); // kbk = unwrap(temp, sbk)
|
||||
se_aes_key_set(7, keys->keyblob_key[i], sizeof(keys->keyblob_key[i]));
|
||||
se_aes_crypt_block_ecb(7, 0, keys->keyblob_mac_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk)
|
||||
se_aes_crypt_block_ecb(7, DECRYPT, keys->keyblob_mac_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk)
|
||||
if (i == 0) {
|
||||
se_aes_crypt_block_ecb(7, 0, keys->device_key, per_console_key_source); // devkey = unwrap(pcks, kbk0)
|
||||
se_aes_crypt_block_ecb(7, 0, keys->device_key_4x, device_master_key_source_kek_source);
|
||||
se_aes_crypt_block_ecb(7, DECRYPT, keys->device_key, per_console_key_source); // devkey = unwrap(pcks, kbk0)
|
||||
se_aes_crypt_block_ecb(7, DECRYPT, keys->device_key_4x, device_master_key_source_kek_source);
|
||||
}
|
||||
|
||||
// verify keyblob is not corrupt
|
||||
|
@ -217,7 +202,7 @@ static void _derive_keyblob_keys(key_derivation_ctx_t *keys) {
|
|||
memcpy(keys->master_kek[i], keys->keyblob[i].master_kek, sizeof(keys->master_kek[i]));
|
||||
se_aes_key_set(7, keys->master_kek[i], sizeof(keys->master_kek[i]));
|
||||
if (!_key_exists(keys->master_key[i])) {
|
||||
se_aes_crypt_block_ecb(7, 0, keys->master_key[i], master_key_source);
|
||||
se_aes_crypt_block_ecb(7, DECRYPT, keys->master_key[i], master_key_source);
|
||||
}
|
||||
}
|
||||
free(keyblob_block);
|
||||
|
@ -238,15 +223,15 @@ static void _derive_bis_keys(key_derivation_ctx_t *keys) {
|
|||
_generate_specific_aes_key(8, keys, &keys->bis_key[0], &bis_key_sources[0], key_generation);
|
||||
// kek = generate_kek(bkeks, devkey, aeskek, aeskey)
|
||||
_generate_kek(8, bis_kek_source, keys->temp_key, aes_kek_generation_source, aes_key_generation_source);
|
||||
se_aes_crypt_ecb(8, 0, keys->bis_key[1], AES_128_KEY_SIZE * 2, bis_key_sources[1], AES_128_KEY_SIZE * 2); // bkey = unwrap(bkeys, kek)
|
||||
se_aes_crypt_ecb(8, 0, keys->bis_key[2], AES_128_KEY_SIZE * 2, bis_key_sources[2], AES_128_KEY_SIZE * 2);
|
||||
se_aes_crypt_ecb(8, DECRYPT, keys->bis_key[1], AES_128_KEY_SIZE * 2, bis_key_sources[1], AES_128_KEY_SIZE * 2); // bkey = unwrap(bkeys, kek)
|
||||
se_aes_crypt_ecb(8, DECRYPT, keys->bis_key[2], AES_128_KEY_SIZE * 2, bis_key_sources[2], AES_128_KEY_SIZE * 2);
|
||||
memcpy(keys->bis_key[3], keys->bis_key[2], 0x20);
|
||||
}
|
||||
|
||||
static void _derive_non_unique_keys(key_derivation_ctx_t *keys, bool is_dev) {
|
||||
if (_key_exists(keys->master_key[0])) {
|
||||
_generate_kek(8, header_kek_source, keys->master_key[0], aes_kek_generation_source, aes_key_generation_source);
|
||||
se_aes_crypt_ecb(8, 0, keys->header_key, AES_128_KEY_SIZE * 2, header_key_source, AES_128_KEY_SIZE * 2);
|
||||
se_aes_crypt_ecb(8, DECRYPT, keys->header_key, AES_128_KEY_SIZE * 2, header_key_source, AES_128_KEY_SIZE * 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -254,19 +239,19 @@ static void _derive_misc_keys(key_derivation_ctx_t *keys, bool is_dev) {
|
|||
if (_key_exists(keys->device_key) || (_key_exists(keys->master_key[0]) && _key_exists(keys->device_key_4x))) {
|
||||
_get_device_key(8, keys, keys->temp_key, 0);
|
||||
_generate_kek(8, save_mac_kek_source, keys->temp_key, aes_kek_generation_source, NULL);
|
||||
se_aes_crypt_block_ecb(8, 0, keys->save_mac_key, save_mac_key_source);
|
||||
se_aes_crypt_block_ecb(8, DECRYPT, keys->save_mac_key, save_mac_key_source);
|
||||
}
|
||||
|
||||
if (_key_exists(keys->master_key[0])) {
|
||||
for (u32 i = 0; i < AES_128_KEY_SIZE; i++)
|
||||
keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i];
|
||||
_generate_kek(8, eticket_rsa_kekek_source, keys->master_key[0], keys->temp_key, NULL);
|
||||
se_aes_crypt_block_ecb(8, 0, keys->eticket_rsa_kek, is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source);
|
||||
se_aes_crypt_block_ecb(8, DECRYPT, keys->eticket_rsa_kek, is_dev ? eticket_rsa_kek_source_dev : eticket_rsa_kek_source);
|
||||
|
||||
for (u32 i = 0; i < AES_128_KEY_SIZE; i++)
|
||||
keys->temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i];
|
||||
_generate_kek(8, ssl_rsa_kek_source_x, keys->master_key[0], keys->temp_key, NULL);
|
||||
se_aes_crypt_block_ecb(8, 0, keys->ssl_rsa_kek, ssl_rsa_kek_source_y);
|
||||
se_aes_crypt_block_ecb(8, DECRYPT, keys->ssl_rsa_kek, ssl_rsa_kek_source_y);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,11 +261,11 @@ static void _derive_master_key_per_generation_keys(key_derivation_ctx_t *keys) {
|
|||
continue;
|
||||
for (u32 j = 0; j < 3; j++) {
|
||||
_generate_kek(8, key_area_key_sources[j], keys->master_key[i], aes_kek_generation_source, NULL);
|
||||
se_aes_crypt_block_ecb(8, 0, keys->key_area_key[j][i], aes_key_generation_source);
|
||||
se_aes_crypt_block_ecb(8, DECRYPT, keys->key_area_key[j][i], aes_key_generation_source);
|
||||
}
|
||||
se_aes_key_set(8, keys->master_key[i], AES_128_KEY_SIZE);
|
||||
se_aes_crypt_block_ecb(8, 0, keys->package2_key[i], package2_key_source);
|
||||
se_aes_crypt_block_ecb(8, 0, keys->titlekek[i], titlekek_source);
|
||||
se_aes_crypt_block_ecb(8, DECRYPT, keys->package2_key[i], package2_key_source);
|
||||
se_aes_crypt_block_ecb(8, DECRYPT, keys->titlekek[i], titlekek_source);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -478,7 +463,7 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit
|
|||
return false;
|
||||
}
|
||||
|
||||
se_aes_xts_crypt(1, 0, 0, 0, titlekey_buffer->read_buffer, titlekey_buffer->read_buffer, XTS_CLUSTER_SIZE, NX_EMMC_CALIBRATION_SIZE / XTS_CLUSTER_SIZE);
|
||||
se_aes_xts_crypt(1, 0, DECRYPT, 0, titlekey_buffer->read_buffer, titlekey_buffer->read_buffer, XTS_CLUSTER_SIZE, NX_EMMC_CALIBRATION_SIZE / XTS_CLUSTER_SIZE);
|
||||
|
||||
nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)titlekey_buffer->read_buffer;
|
||||
if (cal0->magic != MAGIC_CAL0) {
|
||||
|
@ -496,7 +481,7 @@ static bool _derive_titlekeys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit
|
|||
u32 temp_device_key[AES_128_KEY_SIZE / 4] = {0};
|
||||
_get_device_key(7, keys, temp_device_key, keypair_generation);
|
||||
_generate_kek(7, eticket_rsa_kekek_source, temp_device_key, keys->temp_key, NULL);
|
||||
se_aes_crypt_block_ecb(7, 0, keys->eticket_rsa_kek_personalized, eticket_rsa_kek_source);
|
||||
se_aes_crypt_block_ecb(7, DECRYPT, keys->eticket_rsa_kek_personalized, eticket_rsa_kek_source);
|
||||
memcpy(keys->temp_key, keys->eticket_rsa_kek_personalized, sizeof(keys->temp_key));
|
||||
} else {
|
||||
memcpy(keys->temp_key, keys->eticket_rsa_kek, sizeof(keys->temp_key));
|
||||
|
@ -594,21 +579,21 @@ static void _save_mariko_partial_keys(u32 start, u32 count, bool append) {
|
|||
for (u32 ks = start; ks < start + count; ks++) {
|
||||
// Check if key is as expected
|
||||
if (ks < ARRAY_SIZE(mariko_key_vectors)) {
|
||||
se_aes_crypt_block_ecb(ks, 0, &data[0], mariko_key_vectors[ks]);
|
||||
se_aes_crypt_block_ecb(ks, DECRYPT, &data[0], mariko_key_vectors[ks]);
|
||||
if (_key_exists(data)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Encrypt zeros with complete key
|
||||
se_aes_crypt_block_ecb(ks, 1, &data[3 * AES_128_KEY_SIZE], zeros);
|
||||
se_aes_crypt_block_ecb(ks, ENCRYPT, &data[3 * AES_128_KEY_SIZE], zeros);
|
||||
|
||||
// We only need to overwrite 3 of the dwords of the key
|
||||
for (u32 i = 0; i < 3; i++) {
|
||||
// Overwrite ith dword of key with zeros
|
||||
se_aes_key_partial_set(ks, i, 0);
|
||||
// Encrypt zeros with more of the key zeroed out
|
||||
se_aes_crypt_block_ecb(ks, 1, &data[(2 - i) * AES_128_KEY_SIZE], zeros);
|
||||
se_aes_crypt_block_ecb(ks, ENCRYPT, &data[(2 - i) * AES_128_KEY_SIZE], zeros);
|
||||
}
|
||||
|
||||
// Skip saving key if two results are the same indicating unsuccessful overwrite or empty slot
|
||||
|
@ -785,7 +770,7 @@ static bool _check_keyslot_access() {
|
|||
u8 test_data[AES_128_KEY_SIZE] = {0};
|
||||
const u8 test_ciphertext[AES_128_KEY_SIZE] = {0};
|
||||
se_aes_key_set(8, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", SE_KEY_128_SIZE);
|
||||
se_aes_crypt_block_ecb(8, 0, test_data, test_ciphertext);
|
||||
se_aes_crypt_block_ecb(8, DECRYPT, test_data, test_ciphertext);
|
||||
|
||||
return memcmp(test_data, "\x7b\x1d\x29\xa1\x6c\xf8\xcc\xab\x84\xf0\xb8\xa5\x98\xe4\x2f\xa6", SE_KEY_128_SIZE) == 0;
|
||||
}
|
||||
|
@ -944,14 +929,14 @@ static void _generate_specific_aes_key(u32 ks, key_derivation_ctx_t *keys, void
|
|||
_get_device_key(ks, keys, keys->temp_key, key_generation);
|
||||
se_aes_key_set(ks, keys->temp_key, AES_128_KEY_SIZE);
|
||||
se_aes_unwrap_key(ks, ks, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey)
|
||||
se_aes_crypt_ecb(ks, 0, out_key, AES_128_KEY_SIZE * 2, key_source, AES_128_KEY_SIZE * 2); // bkey = unwrap(bkeys, kek)
|
||||
se_aes_crypt_ecb(ks, DECRYPT, out_key, AES_128_KEY_SIZE * 2, key_source, AES_128_KEY_SIZE * 2); // bkey = unwrap(bkeys, kek)
|
||||
} else {
|
||||
_get_secure_data(keys, out_key);
|
||||
}
|
||||
}
|
||||
|
||||
static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device_key, u32 revision) {
|
||||
if (revision == KB_FIRMWARE_VERSION_100_200 && !h_cfg.t210b01) {
|
||||
if (revision == KB_FIRMWARE_VERSION_100 && !h_cfg.t210b01) {
|
||||
memcpy(out_device_key, keys->device_key, AES_128_KEY_SIZE);
|
||||
return;
|
||||
}
|
||||
|
@ -963,11 +948,11 @@ static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device
|
|||
}
|
||||
u32 temp_key[AES_128_KEY_SIZE / 4] = {0};
|
||||
se_aes_key_set(ks, keys->device_key_4x, AES_128_KEY_SIZE);
|
||||
se_aes_crypt_block_ecb(ks, 0, temp_key, device_master_key_source_sources[revision]);
|
||||
se_aes_crypt_block_ecb(ks, DECRYPT, temp_key, device_master_key_source_sources[revision]);
|
||||
se_aes_key_set(ks, keys->master_key[0], AES_128_KEY_SIZE);
|
||||
const void *kek_source = fuse_read_hw_state() == FUSE_NX_HW_STATE_PROD ? device_master_kek_sources[revision] : device_master_kek_sources_dev[revision];
|
||||
se_aes_unwrap_key(ks, ks, kek_source);
|
||||
se_aes_crypt_block_ecb(ks, 0, out_device_key, temp_key);
|
||||
se_aes_crypt_block_ecb(ks, DECRYPT, out_device_key, temp_key);
|
||||
}
|
||||
|
||||
static bool _test_key_pair(const void *public_exponent, const void *private_exponent, const void *modulus) {
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <display/di.h>
|
||||
#include <gfx_utils.h>
|
||||
#include "gfx/tui.h"
|
||||
#include "hos/pkg1.h"
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <mem/heap.h>
|
||||
#include <mem/minerva.h>
|
||||
|
|
|
@ -160,7 +160,7 @@ static int nx_emmc_bis_write_block(u32 sector, u32 count, void *buff, bool force
|
|||
}
|
||||
|
||||
// Encrypt and write.
|
||||
if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 1, tweak, true, sector_index_in_cluster, cluster, bis_cache->emmc_buffer, buff, count * NX_EMMC_BLOCKSIZE) ||
|
||||
if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, ENCRYPT, tweak, true, sector_index_in_cluster, cluster, bis_cache->emmc_buffer, buff, count * NX_EMMC_BLOCKSIZE) ||
|
||||
!nx_emmc_part_write(&emmc_storage, system_part, sector, count, bis_cache->emmc_buffer)
|
||||
)
|
||||
return 1; // R/W error.
|
||||
|
@ -227,7 +227,7 @@ static int nx_emmc_bis_read_block(u32 sector, u32 count, void *buff)
|
|||
|
||||
// Read and decrypt the whole cluster the sector resides in.
|
||||
if (!nx_emmc_part_read(&emmc_storage, system_part, aligned_sector, SECTORS_PER_CLUSTER, bis_cache->emmc_buffer) ||
|
||||
!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 0, cache_tweak, true, 0, cluster, bis_cache->emmc_buffer, bis_cache->emmc_buffer, XTS_CLUSTER_SIZE)
|
||||
!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, DECRYPT, cache_tweak, true, 0, cluster, bis_cache->emmc_buffer, bis_cache->emmc_buffer, XTS_CLUSTER_SIZE)
|
||||
)
|
||||
return 1; // R/W error.
|
||||
|
||||
|
@ -257,7 +257,7 @@ static int nx_emmc_bis_read_block(u32 sector, u32 count, void *buff)
|
|||
tweak_exp = sector_index_in_cluster;
|
||||
|
||||
// Maximum one cluster (1 XTS crypto block 16KB).
|
||||
if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, bis_cache->emmc_buffer, count * NX_EMMC_BLOCKSIZE))
|
||||
if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, DECRYPT, tweak, regen_tweak, tweak_exp, prev_cluster, buff, bis_cache->emmc_buffer, count * NX_EMMC_BLOCKSIZE))
|
||||
return 1; // R/W error.
|
||||
prev_sector = sector + count - 1;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue