2019-03-05 00:05:42 +01:00
/*
2021-08-25 01:44:25 +02:00
* Copyright ( c ) 2019 - 2021 shchmue
2019-03-05 00:05:42 +01:00
*
* 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 "keys.h"
2019-09-17 06:18:41 +02:00
2021-08-25 01:44:25 +02:00
# include "../../keygen/tsec_keygen.h"
2020-06-26 22:17:06 +02:00
# include "../config.h"
2021-05-12 23:38:34 +02:00
# include <display/di.h>
2020-06-26 22:17:06 +02:00
# include <gfx_utils.h>
2019-09-17 17:51:30 +02:00
# include "../gfx/tui.h"
2019-03-05 00:05:42 +01:00
# include "../hos/pkg1.h"
# include "../hos/pkg2.h"
2020-06-26 22:17:06 +02:00
# include <libs/fatfs/ff.h>
2020-07-13 19:31:51 +02:00
# include <libs/nx_savedata/save.h>
2020-06-26 22:17:06 +02:00
# include <mem/heap.h>
# include <mem/minerva.h>
# include <mem/sdram.h>
# include <sec/se.h>
# include <sec/se_t210.h>
# include <sec/tsec.h>
# include <soc/fuse.h>
# include <mem/smmu.h>
# include <soc/t210.h>
2019-09-17 17:51:30 +02:00
# include "../storage/emummc.h"
2019-03-05 00:05:42 +01:00
# include "../storage/nx_emmc.h"
2020-06-26 22:17:06 +02:00
# include "../storage/nx_emmc_bis.h"
# include <storage/nx_sd.h>
# include <storage/sdmmc.h>
# include <utils/btn.h>
# include <utils/list.h>
# include <utils/sprintf.h>
# include <utils/util.h>
2019-03-05 00:05:42 +01:00
2019-05-12 19:15:23 +02:00
# include "key_sources.inl"
2019-03-05 00:05:42 +01:00
# include <string.h>
2019-09-17 06:18:41 +02:00
extern hekate_config h_cfg ;
2020-06-26 22:17:06 +02:00
static u32 _key_count = 0 , _titlekey_count = 0 ;
static u32 start_time , end_time ;
2019-09-25 20:18:08 +02:00
u32 color_idx = 0 ;
2019-03-05 00:05:42 +01:00
2020-12-04 02:16:55 +01:00
static ALWAYS_INLINE u32 _read_le_u32 ( const void * buffer , u32 offset ) {
2019-12-30 17:18:02 +01:00
return ( * ( u8 * ) ( buffer + offset + 0 ) ) |
( * ( u8 * ) ( buffer + offset + 1 ) < < 0x08 ) |
( * ( u8 * ) ( buffer + offset + 2 ) < < 0x10 ) |
( * ( u8 * ) ( buffer + offset + 3 ) < < 0x18 ) ;
}
2020-12-04 02:16:55 +01:00
static ALWAYS_INLINE u32 _read_be_u32 ( const void * buffer , u32 offset ) {
return ( * ( u8 * ) ( buffer + offset + 3 ) ) |
( * ( u8 * ) ( buffer + offset + 2 ) < < 0x08 ) |
( * ( u8 * ) ( buffer + offset + 1 ) < < 0x10 ) |
( * ( u8 * ) ( buffer + offset + 0 ) < < 0x18 ) ;
}
2019-03-05 00:05:42 +01:00
// key functions
2021-08-28 20:35:26 +02:00
static int _key_exists ( const void * data ) { return memcmp ( data , " \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 " , 8 ) ! = 0 ; } ;
static void _save_key ( const char * name , const void * data , u32 len , char * outbuf ) ;
static void _save_key_family ( const char * name , const void * data , u32 start_key , u32 num_keys , u32 len , char * outbuf ) ;
static void _generate_kek ( u32 ks , const void * key_source , void * master_key , const void * kek_seed , const void * key_seed ) ;
static void _generate_specific_aes_key ( u32 ks , key_derivation_ctx_t * keys , void * out_key , const void * key_source , u32 key_generation ) ;
static void _get_device_key ( u32 ks , key_derivation_ctx_t * keys , void * out_device_key , u32 revision ) ;
2019-09-25 20:18:08 +02:00
// titlekey functions
2021-08-28 20:35:26 +02:00
static bool _test_key_pair ( const void * E , const void * D , const void * N ) ;
2019-03-05 00:05:42 +01:00
2020-12-04 02:16:55 +01:00
static ALWAYS_INLINE u8 * _find_tsec_fw ( const u8 * pkg1 ) {
2020-07-13 19:31:51 +02:00
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 )
2020-07-14 00:22:36 +02:00
return ( u8 * ) pos ;
2020-07-13 19:31:51 +02:00
return NULL ;
}
2020-12-04 02:16:55 +01:00
static ALWAYS_INLINE u32 _get_tsec_fw_size ( tsec_key_data_t * key_data ) {
2020-07-14 00:22:36 +02:00
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 ;
2020-07-13 19:31:51 +02:00
}
2021-05-12 23:38:34 +02:00
static u8 * _read_pkg1 ( const pkg1_id_t * * pkg1_id ) {
if ( emummc_storage_init_mmc ( ) ) {
2020-12-05 02:28:05 +01:00
EPRINTF ( " Unable to init MMC. " ) ;
return NULL ;
}
TPRINTFARGS ( " %kMMC init... " , colors [ ( color_idx + + ) % 6 ] ) ;
// Read package1.
u8 * pkg1 = ( u8 * ) malloc ( PKG1_MAX_SIZE ) ;
2021-05-12 23:38:34 +02:00
if ( ! emummc_storage_set_mmc_partition ( EMMC_BOOT0 ) ) {
2020-12-05 02:28:05 +01:00
EPRINTF ( " Unable to set partition. " ) ;
return NULL ;
}
2021-05-12 23:38:34 +02:00
if ( ! emummc_storage_read ( PKG1_OFFSET / NX_EMMC_BLOCKSIZE , PKG1_MAX_SIZE / NX_EMMC_BLOCKSIZE , pkg1 ) ) {
2020-12-05 02:28:05 +01:00
EPRINTF ( " Unable to read pkg1. " ) ;
return NULL ;
}
2020-12-08 03:11:33 +01:00
u32 pk1_offset = h_cfg . t210b01 ? sizeof ( bl_hdr_t210b01_t ) : 0 ; // Skip T210B01 OEM header.
* pkg1_id = pkg1_identify ( pkg1 + pk1_offset ) ;
2020-12-05 02:28:05 +01:00
if ( ! * pkg1_id ) {
EPRINTF ( " Unknown pkg1 version. \n Make sure you have the latest Lockpick_RCM. \n If a new firmware version just came out, \n Lockpick_RCM must be updated. \n Check Github for new release. " ) ;
2020-12-08 03:11:33 +01:00
gfx_hexdump ( 0 , pkg1 , 0x20 ) ;
2020-12-05 02:28:05 +01:00
return NULL ;
}
return pkg1 ;
}
2021-08-28 20:35:26 +02:00
static void _derive_master_key_mariko ( key_derivation_ctx_t * keys , bool is_dev ) {
2021-08-25 01:44:25 +02:00
// 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 ) ;
// Relies on the Mariko KEK being properly set in slot 12
2021-08-28 20:35:26 +02:00
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 ] ) ;
2021-08-25 01:44:25 +02:00
se_aes_crypt_block_ecb ( 8 , 0 , keys - > master_key [ KB_FIRMWARE_VERSION_MAX ] , master_key_source ) ;
2020-12-04 21:07:46 +01:00
}
2021-08-25 01:44:25 +02:00
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 ) ;
2020-12-04 21:07:46 +01:00
2021-08-25 01:44:25 +02:00
if ( res ) {
EPRINTFARGS ( " ERROR %d running keygen. \n " , res ) ;
2020-12-04 21:07:46 +01:00
}
2021-08-25 01:44:25 +02:00
return res ;
}
2020-12-04 21:07:46 +01:00
2021-08-28 20:35:26 +02:00
static void _derive_master_keys_from_latest_key ( key_derivation_ctx_t * keys , bool is_dev ) {
2021-08-25 01:44:25 +02:00
if ( ! h_cfg . t210b01 ) {
2021-08-28 20:35:26 +02:00
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_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 ) ;
}
2020-12-04 21:07:46 +01:00
}
2021-08-25 01:44:25 +02:00
// 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 ) ;
2021-08-28 20:35:26 +02:00
se_aes_crypt_block_ecb ( 8 , 0 , keys - > master_key [ i - 1 ] , is_dev ? master_key_vectors_dev [ i ] : master_key_vectors [ i ] ) ;
2020-12-04 21:07:46 +01:00
}
2021-08-25 01:44:25 +02:00
se_aes_key_set ( 8 , keys - > master_key [ 0 ] , AES_128_KEY_SIZE ) ;
2021-08-28 20:35:26 +02:00
se_aes_crypt_block_ecb ( 8 , 0 , keys - > temp_key , is_dev ? master_key_vectors_dev [ 0 ] : master_key_vectors [ 0 ] ) ;
2020-12-04 21:07:46 +01:00
2021-08-25 01:44:25 +02:00
if ( _key_exists ( keys - > temp_key ) ) {
2021-08-28 20:35:26 +02:00
EPRINTFARGS ( " Unable to derive master keys for %s. " , is_dev ? " dev " : " prod " ) ;
2021-08-25 01:44:25 +02:00
memset ( keys - > master_key , 0 , sizeof ( keys - > master_key ) ) ;
2020-12-05 02:28:05 +01:00
}
}
2021-08-25 01:44:25 +02:00
static void _derive_keyblob_keys ( key_derivation_ctx_t * keys ) {
2020-12-05 02:28:05 +01:00
u8 * keyblob_block = ( u8 * ) calloc ( KB_FIRMWARE_VERSION_600 + 1 , NX_EMMC_BLOCKSIZE ) ;
encrypted_keyblob_t * current_keyblob = ( encrypted_keyblob_t * ) keyblob_block ;
2020-12-08 03:11:33 +01:00
u32 keyblob_mac [ AES_128_KEY_SIZE / 4 ] = { 0 } ;
2021-07-11 23:00:34 +02:00
if ( h_cfg . sbk_set ) {
2020-12-08 03:11:33 +01:00
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 ) ;
free ( aes_keys ) ;
2021-07-11 23:00:34 +02:00
} else {
keys - > sbk [ 0 ] = FUSE ( FUSE_PRIVATE_KEY0 ) ;
keys - > sbk [ 1 ] = FUSE ( FUSE_PRIVATE_KEY1 ) ;
keys - > sbk [ 2 ] = FUSE ( FUSE_PRIVATE_KEY2 ) ;
keys - > sbk [ 3 ] = FUSE ( FUSE_PRIVATE_KEY3 ) ;
2020-12-08 03:11:33 +01:00
}
2021-05-12 23:38:34 +02:00
if ( ! emummc_storage_read ( KEYBLOB_OFFSET / NX_EMMC_BLOCKSIZE , KB_FIRMWARE_VERSION_600 + 1 , keyblob_block ) ) {
2020-12-05 02:28:05 +01:00
EPRINTF ( " Unable to read keyblobs. " ) ;
}
for ( u32 i = 0 ; i < = KB_FIRMWARE_VERSION_600 ; i + + , current_keyblob + + ) {
minerva_periodic_training ( ) ;
2021-08-25 01:44:25 +02:00
se_aes_crypt_block_ecb ( 12 , 0 , keys - > keyblob_key [ i ] , keyblob_key_sources [ i ] ) ; // temp = unwrap(kbks, tsec)
2020-12-11 02:05:36 +01:00
se_aes_crypt_block_ecb ( 14 , 0 , keys - > keyblob_key [ i ] , keys - > keyblob_key [ i ] ) ; // kbk = unwrap(temp, sbk)
2020-12-05 02:28:05 +01:00
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)
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 ) ;
}
// verify keyblob is not corrupt
se_aes_key_set ( 10 , keys - > keyblob_mac_key [ i ] , sizeof ( keys - > keyblob_mac_key [ i ] ) ) ;
se_aes_cmac ( 10 , keyblob_mac , sizeof ( keyblob_mac ) , current_keyblob - > iv , sizeof ( current_keyblob - > iv ) + sizeof ( keyblob_t ) ) ;
2021-07-11 20:58:43 +02:00
if ( memcmp ( current_keyblob - > cmac , keyblob_mac , sizeof ( keyblob_mac ) ) ! = 0 ) {
2020-12-05 02:28:05 +01:00
EPRINTFARGS ( " Keyblob %x corrupt. " , i ) ;
continue ;
}
// decrypt keyblobs
se_aes_key_set ( 6 , keys - > keyblob_key [ i ] , sizeof ( keys - > keyblob_key [ i ] ) ) ;
se_aes_crypt_ctr ( 6 , & keys - > keyblob [ i ] , sizeof ( keyblob_t ) , & current_keyblob - > key_data , sizeof ( keyblob_t ) , current_keyblob - > iv ) ;
memcpy ( keys - > package1_key [ i ] , keys - > keyblob [ i ] . package1_key , sizeof ( keys - > package1_key [ i ] ) ) ;
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 ) ;
}
}
free ( keyblob_block ) ;
}
static void _derive_bis_keys ( key_derivation_ctx_t * keys ) {
/* key = unwrap(source, wrapped_key):
key_set ( ks , wrapped_key ) , block_ecb ( ks , 0 , key , source ) - > final key in key
*/
minerva_periodic_training ( ) ;
u32 key_generation = fuse_read_odm_keygen_rev ( ) ;
if ( key_generation )
key_generation - - ;
2020-12-08 03:11:33 +01:00
if ( ! ( _key_exists ( keys - > device_key ) | | ( key_generation & & _key_exists ( keys - > master_key [ 0 ] ) & & _key_exists ( keys - > device_key_4x ) ) ) ) {
return ;
2020-12-05 02:28:05 +01:00
}
2021-08-28 20:35:26 +02:00
_generate_specific_aes_key ( 8 , keys , & keys - > bis_key [ 0 ] , & bis_key_sources [ 0 ] , key_generation ) ;
2020-12-08 03:11:33 +01:00
// kek = generate_kek(bkeks, devkey, aeskek, aeskey)
_generate_kek ( 8 , bis_kek_source , keys - > temp_key , aes_kek_generation_source , aes_key_generation_source ) ;
2021-08-28 20:35:26 +02:00
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 ) ;
2020-12-08 03:11:33 +01:00
memcpy ( keys - > bis_key [ 3 ] , keys - > bis_key [ 2 ] , 0x20 ) ;
2020-12-05 02:28:05 +01:00
}
2021-08-28 20:35:26 +02:00
static void _derive_non_unique_keys ( key_derivation_ctx_t * keys , bool is_dev ) {
2020-12-05 02:28:05 +01:00
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 ) ;
2021-08-28 20:35:26 +02:00
se_aes_crypt_ecb ( 8 , 0 , keys - > header_key , AES_128_KEY_SIZE * 2 , header_key_source , AES_128_KEY_SIZE * 2 ) ;
2020-12-05 02:28:05 +01:00
}
2021-08-28 20:35:26 +02:00
}
2020-12-05 02:28:05 +01:00
2021-08-28 20:35:26 +02:00
static void _derive_misc_keys ( key_derivation_ctx_t * keys , bool is_dev ) {
2020-12-10 03:08:24 +01:00
if ( _key_exists ( keys - > device_key ) | | ( _key_exists ( keys - > master_key [ 0 ] ) & & _key_exists ( keys - > device_key_4x ) ) ) {
2021-08-28 20:35:26 +02:00
_get_device_key ( 8 , keys , keys - > temp_key , 0 ) ;
2020-12-10 03:08:24 +01:00
_generate_kek ( 8 , save_mac_kek_source , keys - > temp_key , aes_kek_generation_source , NULL ) ;
2020-12-05 02:28:05 +01:00
se_aes_crypt_block_ecb ( 8 , 0 , keys - > save_mac_key , save_mac_key_source ) ;
}
2021-08-28 20:35:26 +02:00
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 ) ;
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 ) ;
}
}
static void _derive_master_key_per_generation_keys ( key_derivation_ctx_t * keys ) {
2021-08-25 01:44:25 +02:00
for ( u32 i = 0 ; i < KB_FIRMWARE_VERSION_MAX + 1 ; i + + ) {
2020-12-05 02:28:05 +01:00
if ( ! _key_exists ( keys - > master_key [ i ] ) )
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_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 ) ;
}
}
2020-12-04 02:16:55 +01:00
static bool _get_titlekeys_from_save ( u32 buf_size , const u8 * save_mac_key , titlekey_buffer_t * titlekey_buffer , rsa_keypair_t * rsa_keypair ) {
FIL fp ;
u64 br = buf_size ;
u64 offset = 0 ;
u32 file_tkey_count = 0 ;
u32 save_x = gfx_con . x , save_y = gfx_con . y ;
bool is_personalized = rsa_keypair ! = NULL ;
u32 start_titlekey_count = _titlekey_count ;
char titlekey_save_path [ 32 ] = " bis:/save/80000000000000E1 " ;
if ( is_personalized ) {
titlekey_save_path [ 25 ] = ' 2 ' ;
gfx_printf ( " \n %kPersonalized... " , colors [ color_idx % 6 ] ) ;
} else {
gfx_printf ( " \n %kCommon... " , colors [ color_idx % 6 ] ) ;
}
if ( f_open ( & fp , titlekey_save_path , FA_READ | FA_OPEN_EXISTING ) ) {
EPRINTF ( " Unable to open e1 save. Skipping. " ) ;
return false ;
}
save_ctx_t * save_ctx = calloc ( 1 , sizeof ( save_ctx_t ) ) ;
save_init ( save_ctx , & fp , save_mac_key , 0 ) ;
bool save_process_success = save_process ( save_ctx ) ;
TPRINTF ( " \n Save process... " ) ;
if ( ! save_process_success ) {
EPRINTF ( " Failed to process es save. " ) ;
f_close ( & fp ) ;
save_free_contexts ( save_ctx ) ;
free ( save_ctx ) ;
return false ;
}
2020-12-11 02:05:36 +01:00
const char ticket_bin_path [ 32 ] = " /ticket.bin " ;
const char ticket_list_bin_path [ 32 ] = " /ticket_list.bin " ;
2020-12-04 02:16:55 +01:00
save_data_file_ctx_t ticket_file ;
if ( ! save_open_file ( save_ctx , & ticket_file , ticket_list_bin_path , OPEN_MODE_READ ) ) {
EPRINTF ( " Unable to locate ticket_list.bin in save. " ) ;
f_close ( & fp ) ;
save_free_contexts ( save_ctx ) ;
free ( save_ctx ) ;
return false ;
}
bool terminator_reached = false ;
while ( offset < ticket_file . size & & ! terminator_reached ) {
if ( ! save_data_file_read ( & ticket_file , & br , offset , titlekey_buffer - > read_buffer , buf_size ) | | titlekey_buffer - > read_buffer [ 0 ] = = 0 | | br ! = buf_size )
break ;
offset + = br ;
minerva_periodic_training ( ) ;
ticket_record_t * curr_ticket_record = ( ticket_record_t * ) titlekey_buffer - > read_buffer ;
for ( u32 i = 0 ; i < buf_size ; i + = sizeof ( ticket_record_t ) , curr_ticket_record + + ) {
if ( curr_ticket_record - > rights_id [ 0 ] = = 0xFF ) {
terminator_reached = true ;
break ;
}
file_tkey_count + + ;
}
}
TPRINTF ( " Count keys... " ) ;
if ( ! save_open_file ( save_ctx , & ticket_file , ticket_bin_path , OPEN_MODE_READ ) ) {
EPRINTF ( " Unable to locate ticket.bin in save. " ) ;
f_close ( & fp ) ;
save_free_contexts ( save_ctx ) ;
free ( save_ctx ) ;
return false ;
}
const u32 ticket_sig_type_rsa2048_sha256 = 0x10004 ;
offset = 0 ;
terminator_reached = false ;
2020-12-10 20:39:09 +01:00
u32 pct = 0 , last_pct = 0 , i = 0 ;
2020-12-04 02:16:55 +01:00
while ( offset < ticket_file . size & & ! terminator_reached ) {
if ( ! save_data_file_read ( & ticket_file , & br , offset , titlekey_buffer - > read_buffer , buf_size ) | | titlekey_buffer - > read_buffer [ 0 ] = = 0 | | br ! = buf_size )
break ;
offset + = br ;
ticket_t * curr_ticket = ( ticket_t * ) titlekey_buffer - > read_buffer ;
for ( u32 j = 0 ; j < buf_size ; j + = sizeof ( ticket_t ) , curr_ticket + + ) {
minerva_periodic_training ( ) ;
pct = ( _titlekey_count - start_titlekey_count ) * 100 / file_tkey_count ;
if ( pct > last_pct & & pct < = 100 ) {
last_pct = pct ;
tui_pbar ( save_x , save_y , pct , COLOR_GREEN , 0xFF155500 ) ;
}
2020-12-10 20:39:09 +01:00
if ( i = = file_tkey_count | | curr_ticket - > signature_type = = 0 ) {
2020-12-04 02:16:55 +01:00
terminator_reached = true ;
break ;
}
2020-12-10 20:39:09 +01:00
if ( curr_ticket - > signature_type ! = ticket_sig_type_rsa2048_sha256 ) {
i + + ;
continue ;
}
2020-12-04 02:16:55 +01:00
if ( is_personalized ) {
se_rsa_exp_mod ( 0 , curr_ticket - > titlekey_block , sizeof ( curr_ticket - > titlekey_block ) , curr_ticket - > titlekey_block , sizeof ( curr_ticket - > titlekey_block ) ) ;
if ( se_rsa_oaep_decode (
curr_ticket - > titlekey_block , sizeof ( titlekey_buffer - > titlekeys [ 0 ] ) ,
null_hash , sizeof ( null_hash ) ,
curr_ticket - > titlekey_block , sizeof ( curr_ticket - > titlekey_block )
) ! = sizeof ( titlekey_buffer - > titlekeys [ 0 ] )
)
continue ;
}
memcpy ( titlekey_buffer - > rights_ids [ _titlekey_count ] , curr_ticket - > rights_id , sizeof ( titlekey_buffer - > rights_ids [ 0 ] ) ) ;
memcpy ( titlekey_buffer - > titlekeys [ _titlekey_count ] , curr_ticket - > titlekey_block , sizeof ( titlekey_buffer - > titlekeys [ 0 ] ) ) ;
_titlekey_count + + ;
2020-12-10 20:39:09 +01:00
i + + ;
2020-12-04 02:16:55 +01:00
}
}
tui_pbar ( save_x , save_y , 100 , COLOR_GREEN , 0xFF155500 ) ;
f_close ( & fp ) ;
save_free_contexts ( save_ctx ) ;
free ( save_ctx ) ;
gfx_con_setpos ( 0 , save_y ) ;
if ( is_personalized ) {
TPRINTFARGS ( " \n %kPersonalized... " , colors [ ( color_idx + + ) % 6 ] ) ;
} else {
TPRINTFARGS ( " \n %kCommon... " , colors [ ( color_idx + + ) % 6 ] ) ;
}
gfx_printf ( " \n \n \n " ) ;
return true ;
}
2020-12-10 20:39:09 +01:00
static bool _derive_sd_seed ( key_derivation_ctx_t * keys ) {
2020-07-13 19:31:51 +02:00
FIL fp ;
u32 read_bytes = 0 ;
2020-12-10 20:39:09 +01:00
char * private_path = malloc ( 200 ) ;
strcpy ( private_path , " sd:/ " ) ;
2020-07-13 19:31:51 +02:00
2019-12-09 20:50:08 +01:00
if ( emu_cfg . nintendo_path & & ( emu_cfg . enabled | | ! h_cfg . emummc_force_disable ) ) {
strcat ( private_path , emu_cfg . nintendo_path ) ;
} else {
strcat ( private_path , " Nintendo " ) ;
}
strcat ( private_path , " /Contents/private " ) ;
2020-12-10 20:39:09 +01:00
FRESULT fr = f_open ( & fp , private_path , FA_READ | FA_OPEN_EXISTING ) ;
free ( private_path ) ;
if ( fr ) {
2019-09-25 20:18:08 +02:00
EPRINTF ( " Unable to open SD seed vector. Skipping. " ) ;
2020-12-10 20:39:09 +01:00
return false ;
2019-03-05 00:05:42 +01:00
}
// get sd seed verification vector
2020-12-10 20:39:09 +01:00
if ( f_read ( & fp , keys - > temp_key , AES_128_KEY_SIZE , & read_bytes ) | | read_bytes ! = AES_128_KEY_SIZE ) {
2019-09-25 20:18:08 +02:00
EPRINTF ( " Unable to read SD seed vector. Skipping. " ) ;
2019-03-05 00:05:42 +01:00
f_close ( & fp ) ;
2020-12-10 20:39:09 +01:00
return false ;
2019-03-05 00:05:42 +01:00
}
f_close ( & fp ) ;
2020-12-10 20:39:09 +01:00
// this file is small enough that parsing the savedata properly is slower
2020-06-26 22:17:06 +02:00
if ( f_open ( & fp , " bis:/save/8000000000000043 " , FA_READ | FA_OPEN_EXISTING ) ) {
2019-09-25 20:18:08 +02:00
EPRINTF ( " Unable to open ns_appman save. \n Skipping SD seed. " ) ;
2020-12-10 20:39:09 +01:00
return false ;
2019-03-05 00:05:42 +01:00
}
2020-12-08 03:11:33 +01:00
u8 read_buf [ 0x20 ] __attribute__ ( ( aligned ( 4 ) ) ) = { 0 } ;
2019-09-15 05:37:43 +02:00
for ( u32 i = 0x8000 ; i < f_size ( & fp ) ; i + = 0x4000 ) {
2019-03-05 00:05:42 +01:00
if ( f_lseek ( & fp , i ) | | f_read ( & fp , read_buf , 0x20 , & read_bytes ) | | read_bytes ! = 0x20 )
break ;
2020-12-10 20:39:09 +01:00
if ( ! memcmp ( keys - > temp_key , read_buf , sizeof ( keys - > temp_key ) ) ) {
memcpy ( keys - > sd_seed , read_buf + 0x10 , sizeof ( keys - > sd_seed ) ) ;
2019-03-05 00:05:42 +01:00
break ;
}
}
f_close ( & fp ) ;
2019-09-17 06:18:41 +02:00
TPRINTFARGS ( " %kSD Seed... " , colors [ ( color_idx + + ) % 6 ] ) ;
2020-12-10 20:39:09 +01:00
return true ;
}
static bool _derive_titlekeys ( key_derivation_ctx_t * keys , titlekey_buffer_t * titlekey_buffer ) {
if ( ! _key_exists ( keys - > eticket_rsa_kek ) ) {
return false ;
}
2019-09-25 20:18:08 +02:00
2020-12-04 02:16:55 +01:00
gfx_printf ( " %kTitlekeys... \n " , colors [ ( color_idx + + ) % 6 ] ) ;
2019-09-25 20:18:08 +02:00
2020-12-04 02:16:55 +01:00
rsa_keypair_t rsa_keypair = { 0 } ;
2019-09-25 20:18:08 +02:00
2021-05-12 23:38:34 +02:00
if ( ! emummc_storage_read ( NX_EMMC_CALIBRATION_OFFSET / NX_EMMC_BLOCKSIZE , NX_EMMC_CALIBRATION_SIZE / NX_EMMC_BLOCKSIZE , titlekey_buffer - > read_buffer ) ) {
2020-07-02 17:42:49 +02:00
EPRINTF ( " Unable to read PRODINFO. " ) ;
2020-12-10 20:39:09 +01:00
return false ;
2020-07-02 17:42:49 +02:00
}
2019-09-25 20:18:08 +02:00
2020-12-04 02:16:55 +01:00
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 ) ;
2019-09-25 20:18:08 +02:00
2020-12-04 02:16:55 +01:00
nx_emmc_cal0_t * cal0 = ( nx_emmc_cal0_t * ) titlekey_buffer - > read_buffer ;
2020-12-10 03:08:24 +01:00
if ( cal0 - > magic ! = MAGIC_CAL0 ) {
2020-12-04 02:16:55 +01:00
EPRINTF ( " Invalid CAL0 magic. Check BIS key 0. " ) ;
2020-12-10 20:39:09 +01:00
return false ;
2019-09-25 20:18:08 +02:00
}
2020-12-04 02:16:55 +01:00
// settings sysmodule manually zeroes this out below cal version 9
u32 keypair_generation = cal0 - > version < = 8 ? 0 : cal0 - > ext_ecc_rsa2048_eticket_key_ver ;
2019-12-30 17:18:02 +01:00
if ( keypair_generation ) {
keypair_generation - - ;
2020-12-04 21:07:46 +01:00
for ( u32 i = 0 ; i < AES_128_KEY_SIZE ; i + + )
2020-12-10 20:39:09 +01:00
keys - > temp_key [ i ] = aes_kek_generation_source [ i ] ^ aes_kek_seed_03 [ i ] ;
2020-12-08 03:11:33 +01:00
u32 temp_device_key [ AES_128_KEY_SIZE / 4 ] = { 0 } ;
2021-08-28 20:35:26 +02:00
_get_device_key ( 7 , keys , temp_device_key , keypair_generation ) ;
2020-12-10 20:39:09 +01:00
_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 ) ;
memcpy ( keys - > temp_key , keys - > eticket_rsa_kek_personalized , sizeof ( keys - > temp_key ) ) ;
2019-12-30 17:18:02 +01:00
} else {
2020-12-10 20:39:09 +01:00
memcpy ( keys - > temp_key , keys - > eticket_rsa_kek , sizeof ( keys - > temp_key ) ) ;
2019-12-30 17:18:02 +01:00
}
2020-12-10 20:39:09 +01:00
se_aes_key_set ( 6 , keys - > temp_key , sizeof ( keys - > temp_key ) ) ;
2020-12-04 02:16:55 +01:00
se_aes_crypt_ctr ( 6 , & rsa_keypair , sizeof ( rsa_keypair ) , cal0 - > ext_ecc_rsa2048_eticket_key , sizeof ( cal0 - > ext_ecc_rsa2048_eticket_key ) , cal0 - > ext_ecc_rsa2048_eticket_key_iv ) ;
2019-09-25 20:18:08 +02:00
2020-12-04 02:16:55 +01:00
// Check public exponent is 65537 big endian
if ( _read_be_u32 ( rsa_keypair . public_exponent , 0 ) ! = 65537 ) {
2019-09-25 20:18:08 +02:00
EPRINTF ( " Invalid public exponent. " ) ;
2020-12-10 20:39:09 +01:00
return false ;
2019-09-25 20:18:08 +02:00
}
2020-12-04 02:16:55 +01:00
if ( ! _test_key_pair ( rsa_keypair . public_exponent , rsa_keypair . private_exponent , rsa_keypair . modulus ) ) {
2019-09-25 20:18:08 +02:00
EPRINTF ( " Invalid keypair. Check eticket_rsa_kek. " ) ;
2020-12-10 20:39:09 +01:00
return false ;
2019-09-25 20:18:08 +02:00
}
2020-12-04 02:16:55 +01:00
se_rsa_key_set ( 0 , rsa_keypair . modulus , sizeof ( rsa_keypair . modulus ) , rsa_keypair . private_exponent , sizeof ( rsa_keypair . private_exponent ) ) ;
2020-07-02 17:42:49 +02:00
2021-01-05 23:24:54 +01:00
const u32 buf_size = 0x4000 ;
2020-12-10 20:39:09 +01:00
_get_titlekeys_from_save ( buf_size , keys - > save_mac_key , titlekey_buffer , NULL ) ;
_get_titlekeys_from_save ( buf_size , keys - > save_mac_key , titlekey_buffer , & rsa_keypair ) ;
2019-10-27 03:29:36 +01:00
2021-08-28 20:35:26 +02:00
gfx_printf ( " \n %k Found %d titlekeys. \n \n " , colors [ ( color_idx + + ) % 6 ] , _titlekey_count ) ;
2019-09-25 20:18:08 +02:00
2020-12-10 20:39:09 +01:00
return true ;
}
2020-06-26 22:17:06 +02:00
2020-12-10 20:39:09 +01:00
static bool _derive_emmc_keys ( key_derivation_ctx_t * keys , titlekey_buffer_t * titlekey_buffer ) {
// Set BIS keys.
// PRODINFO/PRODINFOF
se_aes_key_set ( 0 , keys - > bis_key [ 0 ] + 0x00 , AES_128_KEY_SIZE ) ;
se_aes_key_set ( 1 , keys - > bis_key [ 0 ] + 0x10 , AES_128_KEY_SIZE ) ;
// SAFE
se_aes_key_set ( 2 , keys - > bis_key [ 1 ] + 0x00 , AES_128_KEY_SIZE ) ;
se_aes_key_set ( 3 , keys - > bis_key [ 1 ] + 0x10 , AES_128_KEY_SIZE ) ;
// SYSTEM/USER
se_aes_key_set ( 4 , keys - > bis_key [ 2 ] + 0x00 , AES_128_KEY_SIZE ) ;
se_aes_key_set ( 5 , keys - > bis_key [ 2 ] + 0x10 , AES_128_KEY_SIZE ) ;
2021-05-12 23:38:34 +02:00
if ( ! emummc_storage_set_mmc_partition ( EMMC_GPP ) ) {
2020-12-10 20:39:09 +01:00
EPRINTF ( " Unable to set partition. " ) ;
return false ;
}
// Parse eMMC GPT.
LIST_INIT ( gpt ) ;
nx_emmc_gpt_parse ( & gpt , & emmc_storage ) ;
emmc_part_t * system_part = nx_emmc_part_find ( & gpt , " SYSTEM " ) ;
if ( ! system_part ) {
EPRINTF ( " Unable to locate System partition. " ) ;
nx_emmc_gpt_free ( & gpt ) ;
return false ;
}
nx_emmc_bis_init ( system_part ) ;
if ( f_mount ( & emmc_fs , " bis: " , 1 ) ) {
EPRINTF ( " Unable to mount system partition. " ) ;
nx_emmc_gpt_free ( & gpt ) ;
return false ;
}
2021-08-25 01:44:25 +02:00
if ( ! sd_mount ( ) ) {
EPRINTF ( " Unable to mount SD. " ) ;
} else if ( ! _derive_sd_seed ( keys ) ) {
2020-12-10 20:39:09 +01:00
EPRINTF ( " Unable to get SD seed. " ) ;
}
bool res = _derive_titlekeys ( keys , titlekey_buffer ) ;
if ( ! res ) {
EPRINTF ( " Unable to derive titlekeys. " ) ;
}
2020-06-26 22:17:06 +02:00
f_mount ( NULL , " bis: " , 1 ) ;
2019-04-18 17:02:15 +02:00
nx_emmc_gpt_free ( & gpt ) ;
2020-12-10 20:39:09 +01:00
return res ;
}
2020-12-11 02:05:36 +01:00
// The security engine supports partial key override for locked keyslots
// This allows for a manageable brute force on a PC
2021-08-22 00:02:19 +02:00
// Then the Mariko AES class keys, KEK, BEK, unique SBK and SSK can be recovered
static void _save_mariko_partial_keys ( u32 start , u32 count , bool append ) {
if ( start + count > SE_AES_KEYSLOT_COUNT ) {
return ;
}
2020-12-11 02:05:36 +01:00
u32 pos = 0 ;
u32 zeros [ 4 ] = { 0 } ;
u8 * data = malloc ( 4 * AES_128_KEY_SIZE ) ;
2021-08-22 00:02:19 +02:00
char * text_buffer = calloc ( 1 , 0x100 * count ) ;
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 ] ) ;
if ( _key_exists ( data ) ) {
continue ;
}
}
// Encrypt zeros with complete key
2020-12-11 02:05:36 +01:00
se_aes_crypt_block_ecb ( ks , 1 , & 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 ) ;
}
2021-08-22 00:02:19 +02:00
// Skip saving key if two results are the same indicating unsuccessful overwrite or empty slot
if ( memcmp ( & data [ 0 ] , & data [ SE_KEY_128_SIZE ] , AES_128_KEY_SIZE ) = = 0 ) {
continue ;
}
pos + = s_printf ( & text_buffer [ pos ] , " %d \n " , ks ) ;
2020-12-11 02:05:36 +01:00
for ( u32 i = 0 ; i < 4 ; i + + ) {
for ( u32 j = 0 ; j < AES_128_KEY_SIZE ; j + + )
2021-05-12 23:38:34 +02:00
pos + = s_printf ( & text_buffer [ pos ] , " %02x " , data [ i * AES_128_KEY_SIZE + j ] ) ;
2021-08-22 00:02:19 +02:00
pos + = s_printf ( & text_buffer [ pos ] , " " ) ;
2020-12-11 02:05:36 +01:00
}
2021-08-22 00:02:19 +02:00
pos + = s_printf ( & text_buffer [ pos ] , " \n " ) ;
2020-12-11 02:05:36 +01:00
}
free ( data ) ;
2021-08-22 00:02:19 +02:00
if ( strlen ( text_buffer ) = = 0 ) {
EPRINTF ( " Failed to dump partial keys. " ) ;
return ;
}
FIL fp ;
u32 res = 0 ;
BYTE mode = FA_WRITE ;
if ( append ) {
mode | = FA_OPEN_APPEND ;
} else {
mode | = FA_CREATE_ALWAYS ;
}
res = f_open ( & fp , " sd:/switch/partialaes.keys " , mode ) ;
if ( res ) {
EPRINTF ( " Unable to write partial keys to SD. " ) ;
return ;
}
f_write ( & fp , text_buffer , strlen ( text_buffer ) , NULL ) ;
f_close ( & fp ) ;
2021-01-05 23:24:54 +01:00
gfx_printf ( " %kWrote partials to sd:/switch/partialaes.keys \n " , colors [ ( color_idx + + ) % 6 ] ) ;
2021-08-22 00:02:19 +02:00
free ( text_buffer ) ;
2020-12-11 02:05:36 +01:00
}
2021-08-28 20:35:26 +02:00
static void _save_keys_to_sd ( key_derivation_ctx_t * keys , titlekey_buffer_t * titlekey_buffer , bool is_dev ) {
2019-10-25 19:57:59 +02:00
char * text_buffer = NULL ;
if ( ! sd_mount ( ) ) {
EPRINTF ( " Unable to mount SD. " ) ;
2020-12-10 20:39:09 +01:00
return ;
2019-10-25 19:57:59 +02:00
}
2020-12-04 02:16:55 +01:00
u32 text_buffer_size = MAX ( _titlekey_count * sizeof ( titlekey_text_buffer_t ) + 1 , 0x4000 ) ;
2019-10-25 19:57:59 +02:00
text_buffer = ( char * ) calloc ( 1 , text_buffer_size ) ;
2019-03-05 00:05:42 +01:00
2020-12-04 02:16:55 +01:00
SAVE_KEY ( aes_kek_generation_source ) ;
SAVE_KEY ( aes_key_generation_source ) ;
SAVE_KEY ( bis_kek_source ) ;
2020-12-10 20:39:09 +01:00
SAVE_KEY_FAMILY_VAR ( bis_key , keys - > bis_key , 0 ) ;
2021-08-25 01:44:25 +02:00
SAVE_KEY_FAMILY ( bis_key_sources , 0 ) ;
2020-12-10 20:39:09 +01:00
SAVE_KEY_VAR ( device_key , keys - > device_key ) ;
SAVE_KEY_VAR ( device_key_4x , keys - > device_key_4x ) ;
SAVE_KEY_VAR ( eticket_rsa_kek , keys - > eticket_rsa_kek ) ;
SAVE_KEY_VAR ( eticket_rsa_kek_personalized , keys - > eticket_rsa_kek_personalized ) ;
2021-08-28 20:35:26 +02:00
if ( is_dev ) {
SAVE_KEY_VAR ( eticket_rsa_kek_source , eticket_rsa_kek_source_dev ) ;
} else {
SAVE_KEY ( eticket_rsa_kek_source ) ;
}
2020-12-04 02:16:55 +01:00
SAVE_KEY ( eticket_rsa_kekek_source ) ;
SAVE_KEY ( header_kek_source ) ;
2020-12-10 20:39:09 +01:00
SAVE_KEY_VAR ( header_key , keys - > header_key ) ;
2020-12-04 02:16:55 +01:00
SAVE_KEY ( header_key_source ) ;
2020-12-10 20:39:09 +01:00
SAVE_KEY_FAMILY_VAR ( key_area_key_application , keys - > key_area_key [ 0 ] , 0 ) ;
2020-12-04 02:16:55 +01:00
SAVE_KEY_VAR ( key_area_key_application_source , key_area_key_sources [ 0 ] ) ;
2020-12-10 20:39:09 +01:00
SAVE_KEY_FAMILY_VAR ( key_area_key_ocean , keys - > key_area_key [ 1 ] , 0 ) ;
2020-12-04 02:16:55 +01:00
SAVE_KEY_VAR ( key_area_key_ocean_source , key_area_key_sources [ 1 ] ) ;
2020-12-10 20:39:09 +01:00
SAVE_KEY_FAMILY_VAR ( key_area_key_system , keys - > key_area_key [ 2 ] , 0 ) ;
2020-12-04 02:16:55 +01:00
SAVE_KEY_VAR ( key_area_key_system_source , key_area_key_sources [ 2 ] ) ;
2020-12-10 20:39:09 +01:00
SAVE_KEY_FAMILY_VAR ( keyblob , keys - > keyblob , 0 ) ;
SAVE_KEY_FAMILY_VAR ( keyblob_key , keys - > keyblob_key , 0 ) ;
2021-08-28 20:35:26 +02:00
SAVE_KEY_FAMILY_VAR ( keyblob_key_source , keyblob_key_sources , 0 ) ;
2020-12-10 20:39:09 +01:00
SAVE_KEY_FAMILY_VAR ( keyblob_mac_key , keys - > keyblob_mac_key , 0 ) ;
2020-12-04 02:16:55 +01:00
SAVE_KEY ( keyblob_mac_key_source ) ;
2021-08-28 20:35:26 +02:00
if ( is_dev ) {
SAVE_KEY_FAMILY_VAR ( mariko_master_kek_source , mariko_master_kek_sources_dev , 5 ) ;
} else {
SAVE_KEY_FAMILY_VAR ( mariko_master_kek_source , mariko_master_kek_sources , 5 ) ;
}
2020-12-10 20:39:09 +01:00
SAVE_KEY_FAMILY_VAR ( master_kek , keys - > master_kek , 0 ) ;
2020-12-04 02:16:55 +01:00
SAVE_KEY_FAMILY_VAR ( master_kek_source , master_kek_sources , KB_FIRMWARE_VERSION_620 ) ;
2020-12-10 20:39:09 +01:00
SAVE_KEY_FAMILY_VAR ( master_key , keys - > master_key , 0 ) ;
2020-12-04 02:16:55 +01:00
SAVE_KEY ( master_key_source ) ;
2020-12-10 20:39:09 +01:00
SAVE_KEY_FAMILY_VAR ( package1_key , keys - > package1_key , 0 ) ;
SAVE_KEY_FAMILY_VAR ( package2_key , keys - > package2_key , 0 ) ;
2020-12-04 02:16:55 +01:00
SAVE_KEY ( package2_key_source ) ;
SAVE_KEY ( per_console_key_source ) ;
SAVE_KEY ( retail_specific_aes_key_source ) ;
2020-12-04 21:07:46 +01:00
for ( u32 i = 0 ; i < AES_128_KEY_SIZE ; i + + )
2020-12-10 20:39:09 +01:00
keys - > temp_key [ i ] = aes_kek_generation_source [ i ] ^ aes_kek_seed_03 [ i ] ;
SAVE_KEY_VAR ( rsa_oaep_kek_generation_source , keys - > temp_key ) ;
2020-12-04 21:07:46 +01:00
for ( u32 i = 0 ; i < AES_128_KEY_SIZE ; i + + )
2020-12-10 20:39:09 +01:00
keys - > temp_key [ i ] = aes_kek_generation_source [ i ] ^ aes_kek_seed_01 [ i ] ;
SAVE_KEY_VAR ( rsa_private_kek_generation_source , keys - > temp_key ) ;
2020-12-04 02:16:55 +01:00
SAVE_KEY ( save_mac_kek_source ) ;
2020-12-10 20:39:09 +01:00
SAVE_KEY_VAR ( save_mac_key , keys - > save_mac_key ) ;
2020-12-04 02:16:55 +01:00
SAVE_KEY ( save_mac_key_source ) ;
SAVE_KEY ( save_mac_sd_card_kek_source ) ;
SAVE_KEY ( save_mac_sd_card_key_source ) ;
SAVE_KEY ( sd_card_custom_storage_key_source ) ;
SAVE_KEY ( sd_card_kek_source ) ;
SAVE_KEY ( sd_card_nca_key_source ) ;
SAVE_KEY ( sd_card_save_key_source ) ;
2020-12-10 20:39:09 +01:00
SAVE_KEY_VAR ( sd_seed , keys - > sd_seed ) ;
SAVE_KEY_VAR ( secure_boot_key , keys - > sbk ) ;
SAVE_KEY_VAR ( ssl_rsa_kek , keys - > ssl_rsa_kek ) ;
2020-12-04 02:16:55 +01:00
SAVE_KEY ( ssl_rsa_kek_source_x ) ;
SAVE_KEY ( ssl_rsa_kek_source_y ) ;
2020-12-10 20:39:09 +01:00
SAVE_KEY_FAMILY_VAR ( titlekek , keys - > titlekek , 0 ) ;
2020-12-04 02:16:55 +01:00
SAVE_KEY ( titlekek_source ) ;
2021-08-25 01:44:25 +02:00
SAVE_KEY_VAR ( tsec_key , keys - > tsec_key ) ;
const u32 root_key_ver = 2 ;
char root_key_name [ 21 ] = " tsec_root_key_00 " ;
s_printf ( root_key_name + 14 , " %02x " , root_key_ver ) ;
_save_key ( root_key_name , keys - > tsec_root_key , AES_128_KEY_SIZE , text_buffer ) ;
2021-08-28 20:35:26 +02:00
gfx_printf ( " \n %k Found %d %s keys. \n \n " , colors [ ( color_idx + + ) % 6 ] , _key_count , is_dev ? " dev " : " prod " ) ;
2021-08-25 01:44:25 +02:00
gfx_printf ( " %kFound through master_key_%02x. \n \n " , colors [ ( color_idx + + ) % 6 ] , KB_FIRMWARE_VERSION_MAX ) ;
2019-03-05 00:05:42 +01:00
2019-10-21 19:06:39 +02:00
f_mkdir ( " sd:/switch " ) ;
2020-12-10 20:39:09 +01:00
char keyfile_path [ 30 ] = " sd:/switch/prod.keys " ;
2021-08-28 20:35:26 +02:00
if ( is_dev ) {
2021-05-12 23:38:34 +02:00
s_printf ( & keyfile_path [ 11 ] , " dev.keys " ) ;
2021-08-28 20:35:26 +02:00
}
2020-12-10 20:39:09 +01:00
FILINFO fno ;
2019-10-25 19:57:59 +02:00
if ( ! sd_save_to_file ( text_buffer , strlen ( text_buffer ) , keyfile_path ) & & ! f_stat ( keyfile_path , & fno ) ) {
2019-09-17 06:18:41 +02:00
gfx_printf ( " %kWrote %d bytes to %s \n " , colors [ ( color_idx + + ) % 6 ] , ( u32 ) fno . fsize , keyfile_path ) ;
2019-05-12 20:05:58 +02:00
} else
2019-09-25 20:18:08 +02:00
EPRINTF ( " Unable to save keys to SD. " ) ;
2021-01-05 23:24:54 +01:00
if ( h_cfg . t210b01 ) {
2021-08-22 00:02:19 +02:00
_save_mariko_partial_keys ( 12 , 4 , true ) ;
2021-01-05 23:24:54 +01:00
}
2021-08-28 20:35:26 +02:00
if ( _titlekey_count = = 0 | | ! titlekey_buffer ) {
2020-12-10 20:39:09 +01:00
free ( text_buffer ) ;
return ;
}
2019-10-07 21:18:14 +02:00
memset ( text_buffer , 0 , text_buffer_size ) ;
2020-12-04 02:16:55 +01:00
titlekey_text_buffer_t * titlekey_text = ( titlekey_text_buffer_t * ) text_buffer ;
2019-09-25 20:18:08 +02:00
for ( u32 i = 0 ; i < _titlekey_count ; i + + ) {
2020-12-04 21:07:46 +01:00
for ( u32 j = 0 ; j < AES_128_KEY_SIZE ; j + + )
2021-05-12 23:38:34 +02:00
s_printf ( & titlekey_text [ i ] . rights_id [ j * 2 ] , " %02x " , titlekey_buffer - > rights_ids [ i ] [ j ] ) ;
s_printf ( titlekey_text [ i ] . equals , " = " ) ;
2020-12-04 21:07:46 +01:00
for ( u32 j = 0 ; j < AES_128_KEY_SIZE ; j + + )
2021-05-12 23:38:34 +02:00
s_printf ( & titlekey_text [ i ] . titlekey [ j * 2 ] , " %02x " , titlekey_buffer - > titlekeys [ i ] [ j ] ) ;
s_printf ( titlekey_text [ i ] . newline , " \n " ) ;
2019-09-25 20:18:08 +02:00
}
2021-05-12 23:38:34 +02:00
s_printf ( & keyfile_path [ 11 ] , " title.keys " ) ;
2019-10-25 19:57:59 +02:00
if ( ! sd_save_to_file ( text_buffer , strlen ( text_buffer ) , keyfile_path ) & & ! f_stat ( keyfile_path , & fno ) ) {
2019-09-25 20:18:08 +02:00
gfx_printf ( " %kWrote %d bytes to %s \n " , colors [ ( color_idx + + ) % 6 ] , ( u32 ) fno . fsize , keyfile_path ) ;
} else
EPRINTF ( " Unable to save titlekeys to SD. " ) ;
2019-10-07 21:18:14 +02:00
2019-09-25 20:18:08 +02:00
free ( text_buffer ) ;
2020-12-10 20:39:09 +01:00
}
2021-07-11 23:23:43 +02:00
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 ) ;
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 ;
}
2020-12-10 20:39:09 +01:00
static void _derive_keys ( ) {
2021-08-22 00:02:19 +02:00
if ( ! f_stat ( " sd:/switch/partialaes.keys " , NULL ) ) {
f_unlink ( " sd:/switch/partialaes.keys " ) ;
}
if ( h_cfg . t210b01 ) {
_save_mariko_partial_keys ( 0 , 12 , false ) ;
}
2021-07-11 23:23:43 +02:00
if ( ! _check_keyslot_access ( ) ) {
2021-08-22 00:02:19 +02:00
EPRINTF ( " Unable to set crypto keyslots! \n Try launching payload differently \n or flash Spacecraft-NX if using a modchip. " ) ;
2021-07-11 23:23:43 +02:00
return ;
}
2020-12-10 20:39:09 +01:00
u32 start_whole_operation_time = get_tmr_us ( ) ;
const pkg1_id_t * pkg1_id ;
2021-05-12 23:38:34 +02:00
u8 * pkg1 = _read_pkg1 ( & pkg1_id ) ;
2020-12-10 20:39:09 +01:00
if ( ! pkg1 ) {
return ;
}
2021-08-25 01:44:25 +02:00
free ( pkg1 ) ;
2020-12-10 20:39:09 +01:00
2021-08-28 20:35:26 +02:00
bool is_dev = fuse_read_hw_state ( ) = = FUSE_NX_HW_STATE_DEV ;
key_derivation_ctx_t __attribute__ ( ( aligned ( 4 ) ) ) prod_keys = { 0 } , dev_keys = { 0 } ;
key_derivation_ctx_t * keys = is_dev ? & dev_keys : & prod_keys ;
2020-12-10 20:39:09 +01:00
// Master key derivation
if ( h_cfg . t210b01 ) {
2021-08-28 20:35:26 +02:00
_derive_master_key_mariko ( keys , is_dev ) ;
_derive_master_keys_from_latest_key ( keys , is_dev ) ;
2020-12-10 20:39:09 +01:00
} else {
2021-08-28 20:35:26 +02:00
int res = _run_ams_keygen ( keys ) ;
2021-08-25 01:44:25 +02:00
if ( res ) {
EPRINTF ( " Unable to run keygen. " ) ;
return ;
}
u8 * aes_keys = ( u8 * ) calloc ( 0x1000 , 1 ) ;
se_get_aes_keys ( aes_keys + 0x800 , aes_keys , AES_128_KEY_SIZE ) ;
2021-08-28 20:35:26 +02:00
memcpy ( & dev_keys . tsec_root_key , aes_keys + 11 * AES_128_KEY_SIZE , AES_128_KEY_SIZE ) ;
memcpy ( keys - > tsec_key , aes_keys + 12 * AES_128_KEY_SIZE , AES_128_KEY_SIZE ) ;
memcpy ( & prod_keys . tsec_root_key , aes_keys + 13 * AES_128_KEY_SIZE , AES_128_KEY_SIZE ) ;
2021-08-25 01:44:25 +02:00
free ( aes_keys ) ;
2021-08-28 20:35:26 +02:00
_derive_master_keys_from_latest_key ( & prod_keys , false ) ;
_derive_master_keys_from_latest_key ( & dev_keys , true ) ;
_derive_keyblob_keys ( keys ) ;
2020-12-10 20:39:09 +01:00
}
TPRINTFARGS ( " %kMaster keys... " , colors [ ( color_idx + + ) % 6 ] ) ;
2021-08-28 20:35:26 +02:00
_derive_bis_keys ( keys ) ;
2020-12-10 20:39:09 +01:00
TPRINTFARGS ( " %kBIS keys... " , colors [ ( color_idx + + ) % 6 ] ) ;
2021-08-28 20:35:26 +02:00
_derive_misc_keys ( keys , is_dev ) ;
_derive_non_unique_keys ( & prod_keys , is_dev ) ;
_derive_non_unique_keys ( & dev_keys , is_dev ) ;
_derive_master_key_per_generation_keys ( & prod_keys ) ;
_derive_master_key_per_generation_keys ( & dev_keys ) ;
2020-12-10 20:39:09 +01:00
titlekey_buffer_t * titlekey_buffer = ( titlekey_buffer_t * ) TITLEKEY_BUF_ADR ;
// BIS key for SYSTEM partition
2021-08-28 20:35:26 +02:00
if ( _key_exists ( keys - > bis_key [ 2 ] ) ) {
_derive_emmc_keys ( keys , titlekey_buffer ) ;
2020-12-10 20:39:09 +01:00
} else {
EPRINTF ( " Missing needed BIS keys. \n Skipping SD seed and titlekeys. " ) ;
}
2021-08-28 20:35:26 +02:00
end_time = get_tmr_us ( ) ;
gfx_printf ( " %kLockpick totally done in %d us \n " , colors [ ( color_idx + + ) % 6 ] , end_time - start_whole_operation_time ) ;
_save_keys_to_sd ( & prod_keys , titlekey_buffer , false ) ;
_key_count = 0 ;
_save_keys_to_sd ( & dev_keys , NULL , true ) ;
2020-12-10 20:39:09 +01:00
}
void dump_keys ( ) {
display_backlight_brightness ( h_cfg . backlight , 1000 ) ;
gfx_clear_grey ( 0x1B ) ;
gfx_con_setpos ( 0 , 0 ) ;
gfx_printf ( " [%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k] \n \n " ,
colors [ 0 ] , colors [ 1 ] , colors [ 2 ] , colors [ 3 ] , colors [ 4 ] , colors [ 5 ] , 0xFFFF00FF , LP_VER_MJ , LP_VER_MN , LP_VER_BF , 0xFFCCCCCC ) ;
_key_count = 0 ;
_titlekey_count = 0 ;
color_idx = 0 ;
start_time = get_tmr_us ( ) ;
_derive_keys ( ) ;
2019-03-05 00:05:42 +01:00
2020-06-26 22:17:06 +02:00
emummc_load_cfg ( ) ;
// Ignore whether emummc is enabled.
h_cfg . emummc_force_disable = emu_cfg . sector = = 0 & & ! emu_cfg . path ;
2020-07-02 17:42:49 +02:00
emu_cfg . enabled = ! h_cfg . emummc_force_disable ;
2020-06-26 22:17:06 +02:00
emummc_storage_end ( & emmc_storage ) ;
2020-07-02 17:42:49 +02:00
gfx_printf ( " \n %kPress a button to return to the menu. " , colors [ ( color_idx ) % 6 ] , colors [ ( color_idx + 1 ) % 6 ] , colors [ ( color_idx + 2 ) % 6 ] ) ;
2019-09-17 17:51:30 +02:00
btn_wait ( ) ;
2020-07-02 17:42:49 +02:00
gfx_clear_grey ( 0x1B ) ;
2019-03-05 00:05:42 +01:00
}
2019-09-25 20:18:08 +02:00
static void _save_key ( const char * name , const void * data , u32 len , char * outbuf ) {
2019-03-05 00:05:42 +01:00
if ( ! _key_exists ( data ) )
return ;
2019-05-12 20:05:58 +02:00
u32 pos = strlen ( outbuf ) ;
2021-05-12 23:38:34 +02:00
pos + = s_printf ( & outbuf [ pos ] , " %s = " , name ) ;
2019-04-18 17:02:15 +02:00
for ( u32 i = 0 ; i < len ; i + + )
2021-05-12 23:38:34 +02:00
pos + = s_printf ( & outbuf [ pos ] , " %02x " , * ( u8 * ) ( data + i ) ) ;
s_printf ( & outbuf [ pos ] , " \n " ) ;
2019-03-05 00:05:42 +01:00
_key_count + + ;
}
2019-09-25 20:18:08 +02:00
static void _save_key_family ( const char * name , const void * data , u32 start_key , u32 num_keys , u32 len , char * outbuf ) {
2020-12-11 02:05:36 +01:00
char * temp_name = calloc ( 1 , 0x40 ) ;
2019-10-28 16:54:01 +01:00
for ( u32 i = 0 ; i < num_keys ; i + + ) {
2021-05-12 23:38:34 +02:00
s_printf ( temp_name , " %s_%02x " , name , i + start_key ) ;
2019-05-12 20:05:58 +02:00
_save_key ( temp_name , data + i * len , len , outbuf ) ;
2019-03-05 00:05:42 +01:00
}
2020-12-11 02:05:36 +01:00
free ( temp_name ) ;
2019-03-05 00:05:42 +01:00
}
static void _generate_kek ( u32 ks , const void * key_source , void * master_key , const void * kek_seed , const void * key_seed ) {
if ( ! _key_exists ( key_source ) | | ! _key_exists ( master_key ) | | ! _key_exists ( kek_seed ) )
return ;
2020-12-04 21:07:46 +01:00
se_aes_key_set ( ks , master_key , AES_128_KEY_SIZE ) ;
2019-03-05 00:05:42 +01:00
se_aes_unwrap_key ( ks , ks , kek_seed ) ;
se_aes_unwrap_key ( ks , ks , key_source ) ;
if ( key_seed & & _key_exists ( key_seed ) )
se_aes_unwrap_key ( ks , ks , key_seed ) ;
}
2021-08-28 20:35:26 +02:00
static void _get_secure_data ( key_derivation_ctx_t * keys , void * dst ) {
se_aes_key_set ( 6 , keys - > device_key , AES_128_KEY_SIZE ) ;
u8 * d = ( u8 * ) dst ;
se_aes_crypt_ctr ( 6 , d + 0x00 , AES_128_KEY_SIZE , secure_data_source , AES_128_KEY_SIZE , secure_data_counters [ 0 ] ) ;
se_aes_crypt_ctr ( 6 , d + 0x10 , AES_128_KEY_SIZE , secure_data_source , AES_128_KEY_SIZE , secure_data_counters [ 0 ] ) ;
// Apply tweak
for ( u32 i = 0 ; i < AES_128_KEY_SIZE ; i + + ) {
d [ AES_128_KEY_SIZE + i ] ^ = secure_data_tweaks [ 0 ] [ i ] ;
}
}
static void _generate_specific_aes_key ( u32 ks , key_derivation_ctx_t * keys , void * out_key , const void * key_source , u32 key_generation ) {
if ( fuse_read_bootrom_rev ( ) > = 0x7F ) {
_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)
} 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 ) {
2020-12-10 03:08:24 +01:00
if ( revision = = KB_FIRMWARE_VERSION_100_200 & & ! h_cfg . t210b01 ) {
2021-08-28 20:35:26 +02:00
memcpy ( out_device_key , keys - > device_key , AES_128_KEY_SIZE ) ;
2020-12-08 03:11:33 +01:00
return ;
}
2019-12-30 17:18:02 +01:00
2020-12-10 03:08:24 +01:00
if ( revision > = KB_FIRMWARE_VERSION_400 ) {
revision - = KB_FIRMWARE_VERSION_400 ;
} else {
revision = 0 ;
}
2020-12-08 03:11:33 +01:00
u32 temp_key [ AES_128_KEY_SIZE / 4 ] = { 0 } ;
2021-08-28 20:35:26 +02:00
se_aes_key_set ( ks , keys - > device_key_4x , AES_128_KEY_SIZE ) ;
2021-07-11 23:23:43 +02:00
se_aes_crypt_block_ecb ( ks , 0 , temp_key , device_master_key_source_sources [ revision ] ) ;
2021-08-28 20:35:26 +02:00
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 ) ;
2021-07-11 23:23:43 +02:00
se_aes_crypt_block_ecb ( ks , 0 , out_device_key , temp_key ) ;
2019-03-05 00:05:42 +01:00
}
2020-12-04 02:16:55 +01:00
static bool _test_key_pair ( const void * public_exponent , const void * private_exponent , const void * modulus ) {
2020-12-08 03:11:33 +01:00
u8 plaintext [ RSA_2048_KEY_SIZE ] __attribute__ ( ( aligned ( 4 ) ) ) = { 0 } ,
ciphertext [ RSA_2048_KEY_SIZE ] __attribute__ ( ( aligned ( 4 ) ) ) = { 0 } ,
work [ RSA_2048_KEY_SIZE ] __attribute__ ( ( aligned ( 4 ) ) ) = { 0 } ;
2019-09-25 20:18:08 +02:00
// 0xCAFEBABE
2020-12-04 02:16:55 +01:00
plaintext [ 0xfc ] = 0xca ; plaintext [ 0xfd ] = 0xfe ; plaintext [ 0xfe ] = 0xba ; plaintext [ 0xff ] = 0xbe ;
2019-09-25 20:18:08 +02:00
2020-12-04 21:07:46 +01:00
se_rsa_key_set ( 0 , modulus , RSA_2048_KEY_SIZE , private_exponent , RSA_2048_KEY_SIZE ) ;
se_rsa_exp_mod ( 0 , ciphertext , RSA_2048_KEY_SIZE , plaintext , RSA_2048_KEY_SIZE ) ;
2019-09-25 20:18:08 +02:00
2020-12-04 21:07:46 +01:00
se_rsa_key_set ( 0 , modulus , RSA_2048_KEY_SIZE , public_exponent , 4 ) ;
se_rsa_exp_mod ( 0 , work , RSA_2048_KEY_SIZE , ciphertext , RSA_2048_KEY_SIZE ) ;
2019-09-25 20:18:08 +02:00
2020-12-04 21:07:46 +01:00
return ! memcmp ( plaintext , work , RSA_2048_KEY_SIZE ) ;
2019-09-25 20:18:08 +02:00
}