mirror of
https://github.com/s1204IT/Lockpick_RCM.git
synced 2024-11-08 11:31:43 +00:00
Add Amiibo key dump support
This commit is contained in:
parent
5f35c8396d
commit
065ba8bc11
4 changed files with 182 additions and 25 deletions
|
@ -209,6 +209,8 @@ static const u8 device_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMW
|
||||||
// from SPL
|
// from SPL
|
||||||
static const u8 aes_key_generation_source[0x10] __attribute__((aligned(4))) = {
|
static const u8 aes_key_generation_source[0x10] __attribute__((aligned(4))) = {
|
||||||
0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8};
|
0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8};
|
||||||
|
static const u8 aes_key_decryption_source[0x10] __attribute__((aligned(4))) = {
|
||||||
|
0x11, 0x70, 0x24, 0x2B, 0x48, 0x69, 0x11, 0xF1, 0x11, 0xB0, 0x0C, 0x47, 0x7C, 0xC3, 0xEF, 0x7E};
|
||||||
|
|
||||||
// from FS
|
// from FS
|
||||||
static const u8 bis_kek_source[0x10] __attribute__((aligned(4))) = {
|
static const u8 bis_kek_source[0x10] __attribute__((aligned(4))) = {
|
||||||
|
@ -250,3 +252,31 @@ static const u8 sd_card_nca_key_source[0x20] __attribute__((aligned(4))) = {
|
||||||
static const u8 sd_card_save_key_source[0x20] __attribute__((aligned(4))) = {
|
static const u8 sd_card_save_key_source[0x20] __attribute__((aligned(4))) = {
|
||||||
0X24, 0X49, 0XB7, 0X22, 0X72, 0X67, 0X03, 0XA8, 0X19, 0X65, 0XE6, 0XE3, 0XEA, 0X58, 0X2F, 0XDD,
|
0X24, 0X49, 0XB7, 0X22, 0X72, 0X67, 0X03, 0XA8, 0X19, 0X65, 0XE6, 0XE3, 0XEA, 0X58, 0X2F, 0XDD,
|
||||||
0X9A, 0X95, 0X15, 0X17, 0XB1, 0X6E, 0X8F, 0X7F, 0X1F, 0X68, 0X26, 0X31, 0X52, 0XEA, 0X29, 0X6A};
|
0X9A, 0X95, 0X15, 0X17, 0XB1, 0X6E, 0X8F, 0X7F, 0X1F, 0X68, 0X26, 0X31, 0X52, 0XEA, 0X29, 0X6A};
|
||||||
|
|
||||||
|
// from NFC
|
||||||
|
static const u8 nfc_key_source[0x10] __attribute__((aligned(4))) = {
|
||||||
|
0x83, 0xF6, 0xEF, 0xD8, 0x13, 0x26, 0x49, 0xAB, 0x97, 0x5F, 0xEA, 0xBA, 0x65, 0x71, 0xCA, 0xCA};
|
||||||
|
static const u8 encrypted_nfc_keys[0x80] __attribute__((aligned(4))) = {
|
||||||
|
0x76, 0x50, 0x87, 0x02, 0x40, 0xA6, 0x5A, 0x98, 0xCE, 0x39, 0x2F, 0xC8, 0x83, 0xAF, 0x54, 0x76,
|
||||||
|
0x28, 0xFF, 0x50, 0xFC, 0xC1, 0xFB, 0x26, 0x14, 0xA2, 0x4A, 0xA6, 0x74, 0x90, 0xA4, 0x37, 0x06,
|
||||||
|
0x03, 0x63, 0xC2, 0xB1, 0xAF, 0x9F, 0xF7, 0x07, 0xFC, 0x8A, 0xB9, 0xCA, 0x28, 0x68, 0x6E, 0xF7,
|
||||||
|
0x42, 0xCD, 0x68, 0x13, 0xCD, 0x7B, 0x3A, 0x60, 0x3E, 0x8B, 0xAB, 0x3A, 0xCC, 0xED, 0xE0, 0xDD,
|
||||||
|
0x71, 0x1F, 0xA5, 0xDE, 0xB8, 0xB1, 0xF5, 0x1D, 0x14, 0x73, 0xBE, 0x27, 0xCC, 0xA1, 0x9B, 0x23,
|
||||||
|
0x06, 0x91, 0x89, 0x05, 0xED, 0xD6, 0x92, 0x76, 0x3F, 0x42, 0xFB, 0xD1, 0x8F, 0x2D, 0x6D, 0x72,
|
||||||
|
0xC8, 0x9E, 0x48, 0xE8, 0x03, 0x64, 0xF0, 0x3C, 0x0E, 0x2A, 0xF1, 0x26, 0x83, 0x02, 0x4F, 0xE2,
|
||||||
|
0x41, 0xAA, 0xC8, 0x33, 0x68, 0x84, 0x3A, 0xFB, 0x87, 0x18, 0xEA, 0xF7, 0x36, 0xA2, 0x4E, 0xA9};
|
||||||
|
static const u8 encrypted_nfc_keys_dev[0x80] __attribute__((aligned(4))) = {
|
||||||
|
0x13, 0xB0, 0xFB, 0xC2, 0x91, 0x6D, 0x6E, 0x5A, 0x10, 0x31, 0x40, 0xB7, 0xDF, 0xCF, 0x69, 0x69,
|
||||||
|
0xB0, 0xFA, 0xAE, 0x7F, 0xB2, 0x4D, 0x27, 0xC9, 0xE9, 0x3F, 0x5B, 0x38, 0x39, 0x24, 0x98, 0xCE,
|
||||||
|
0xED, 0xD2, 0xA9, 0x6C, 0x6F, 0xA7, 0x72, 0xD7, 0x11, 0x31, 0x17, 0x93, 0x12, 0x49, 0x32, 0x85,
|
||||||
|
0x21, 0xE5, 0xE1, 0x88, 0x0F, 0x08, 0xF2, 0x30, 0x5C, 0xC3, 0xAA, 0xFF, 0xC0, 0xAB, 0x21, 0x96,
|
||||||
|
0x74, 0x39, 0xED, 0xE0, 0x5A, 0xB6, 0x75, 0xC2, 0x3B, 0x08, 0x61, 0xE4, 0xA7, 0xD6, 0xED, 0x8C,
|
||||||
|
0xA9, 0x02, 0x12, 0xA6, 0xCC, 0x27, 0x4C, 0x1C, 0x41, 0x9C, 0xD8, 0x4C, 0x00, 0xC7, 0x5B, 0x5D,
|
||||||
|
0xED, 0xC2, 0x3D, 0x5E, 0x00, 0xF5, 0x49, 0xFA, 0x6C, 0x75, 0x67, 0xCF, 0x1F, 0x73, 0x1A, 0xE8,
|
||||||
|
0x47, 0xD4, 0x3D, 0x9B, 0x83, 0x5B, 0x18, 0x2F, 0x95, 0xA9, 0x04, 0xBC, 0x2E, 0xBB, 0x64, 0x4A};
|
||||||
|
static const u8 nfc_blob_hash[0x20] __attribute__((aligned(4))) = {
|
||||||
|
0x7F, 0x92, 0x83, 0x65, 0x4E, 0xC1, 0x09, 0x7F, 0xBD, 0xFF, 0x31, 0xDE, 0x94, 0x66, 0x51, 0xAE,
|
||||||
|
0x60, 0xC2, 0x85, 0x4A, 0xFB, 0x54, 0x4A, 0xBE, 0x89, 0x63, 0xD3, 0x89, 0x63, 0x9C, 0x71, 0x0E};
|
||||||
|
static const u8 nfc_blob_hash_dev[0x20] __attribute__((aligned(4))) = {
|
||||||
|
0x4E, 0x36, 0x59, 0x1C, 0x75, 0x80, 0x23, 0x03, 0x98, 0x2D, 0x45, 0xD9, 0x85, 0xB8, 0x60, 0x18,
|
||||||
|
0x7C, 0x85, 0x37, 0x9B, 0xCB, 0xBA, 0xF3, 0xDC, 0x25, 0x38, 0x73, 0xDB, 0x2F, 0xFA, 0xAE, 0x26};
|
||||||
|
|
|
@ -74,6 +74,7 @@ static int _key_exists(const void *data) { return memcmp(data, "\x00\x00\x00\x0
|
||||||
static void _save_key(const char *name, const void *data, u32 len, char *outbuf);
|
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 _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, const void *master_key, const void *kek_seed, const void *key_seed);
|
static void _generate_kek(u32 ks, const void *key_source, const void *master_key, const void *kek_seed, const void *key_seed);
|
||||||
|
static void _decrypt_aes_key(u32 ks, void *dst, const void *key_source, const void *master_key);
|
||||||
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 _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);
|
static void _get_device_key(u32 ks, key_derivation_ctx_t *keys, void *out_device_key, u32 revision);
|
||||||
// titlekey functions
|
// titlekey functions
|
||||||
|
@ -584,6 +585,11 @@ static bool _derive_emmc_keys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit
|
||||||
// This allows for a manageable brute force on a PC
|
// This allows for a manageable brute force on a PC
|
||||||
// Then the Mariko AES class keys, KEK, BEK, unique SBK and SSK can be recovered
|
// Then the Mariko AES class keys, KEK, BEK, unique SBK and SSK can be recovered
|
||||||
int save_mariko_partial_keys(u32 start, u32 count, bool append) {
|
int save_mariko_partial_keys(u32 start, u32 count, bool append) {
|
||||||
|
const char *keyfile_path = "sd:/switch/partialaes.keys";
|
||||||
|
if (!f_stat(keyfile_path, NULL)) {
|
||||||
|
f_unlink(keyfile_path);
|
||||||
|
}
|
||||||
|
|
||||||
if (start + count > SE_AES_KEYSLOT_COUNT) {
|
if (start + count > SE_AES_KEYSLOT_COUNT) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -592,6 +598,8 @@ int save_mariko_partial_keys(u32 start, u32 count, bool append) {
|
||||||
gfx_clear_partial_grey(0x1B, 32, 1224);
|
gfx_clear_partial_grey(0x1B, 32, 1224);
|
||||||
gfx_con_setpos(0, 32);
|
gfx_con_setpos(0, 32);
|
||||||
|
|
||||||
|
color_idx = 0;
|
||||||
|
|
||||||
u32 pos = 0;
|
u32 pos = 0;
|
||||||
u32 zeros[AES_128_KEY_SIZE / 4] = {0};
|
u32 zeros[AES_128_KEY_SIZE / 4] = {0};
|
||||||
u8 *data = malloc(4 * AES_128_KEY_SIZE);
|
u8 *data = malloc(4 * AES_128_KEY_SIZE);
|
||||||
|
@ -655,7 +663,7 @@ int save_mariko_partial_keys(u32 start, u32 count, bool append) {
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f_open(&fp, "sd:/switch/partialaes.keys", mode)) {
|
if (f_open(&fp, keyfile_path, mode)) {
|
||||||
EPRINTF("Unable to write partial keys to SD.");
|
EPRINTF("Unable to write partial keys to SD.");
|
||||||
free(text_buffer);
|
free(text_buffer);
|
||||||
return 3;
|
return 3;
|
||||||
|
@ -664,7 +672,7 @@ int save_mariko_partial_keys(u32 start, u32 count, bool append) {
|
||||||
f_write(&fp, text_buffer, strlen(text_buffer), NULL);
|
f_write(&fp, text_buffer, strlen(text_buffer), NULL);
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
|
|
||||||
gfx_printf("%kWrote partials to sd:/switch/partialaes.keys\n", colors[(color_idx++) % 6]);
|
gfx_printf("%kWrote partials to %s\n", colors[(color_idx++) % 6], keyfile_path);
|
||||||
|
|
||||||
free(text_buffer);
|
free(text_buffer);
|
||||||
|
|
||||||
|
@ -757,16 +765,15 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl
|
||||||
gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], KB_FIRMWARE_VERSION_MAX);
|
gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], KB_FIRMWARE_VERSION_MAX);
|
||||||
|
|
||||||
f_mkdir("sd:/switch");
|
f_mkdir("sd:/switch");
|
||||||
char keyfile_path[30] = "sd:/switch/prod.keys";
|
|
||||||
if (is_dev) {
|
const char *keyfile_path = is_dev ? "sd:/switch/dev.keys" : "sd:/switch/prod.keys";
|
||||||
s_printf(&keyfile_path[11], "dev.keys");
|
|
||||||
}
|
|
||||||
|
|
||||||
FILINFO fno;
|
FILINFO fno;
|
||||||
if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) {
|
if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) {
|
||||||
gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path);
|
gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path);
|
||||||
} else
|
} else {
|
||||||
EPRINTF("Unable to save keys to SD.");
|
EPRINTF("Unable to save keys to SD.");
|
||||||
|
}
|
||||||
|
|
||||||
if (_titlekey_count == 0 || !titlekey_buffer) {
|
if (_titlekey_count == 0 || !titlekey_buffer) {
|
||||||
free(text_buffer);
|
free(text_buffer);
|
||||||
|
@ -784,11 +791,13 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl
|
||||||
s_printf(&titlekey_text[i].titlekey[j * 2], "%02x", titlekey_buffer->titlekeys[i][j]);
|
s_printf(&titlekey_text[i].titlekey[j * 2], "%02x", titlekey_buffer->titlekeys[i][j]);
|
||||||
s_printf(titlekey_text[i].newline, "\n");
|
s_printf(titlekey_text[i].newline, "\n");
|
||||||
}
|
}
|
||||||
s_printf(&keyfile_path[11], "title.keys");
|
|
||||||
|
keyfile_path = "sd:/switch/title.keys";
|
||||||
if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) {
|
if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) {
|
||||||
gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path);
|
gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path);
|
||||||
} else
|
} else {
|
||||||
EPRINTF("Unable to save titlekeys to SD.");
|
EPRINTF("Unable to save titlekeys to SD.");
|
||||||
|
}
|
||||||
|
|
||||||
free(text_buffer);
|
free(text_buffer);
|
||||||
}
|
}
|
||||||
|
@ -831,10 +840,6 @@ static void _derive_master_keys(key_derivation_ctx_t *prod_keys, key_derivation_
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _derive_keys() {
|
static void _derive_keys() {
|
||||||
if (!f_stat("sd:/switch/partialaes.keys", NULL)) {
|
|
||||||
f_unlink("sd:/switch/partialaes.keys");
|
|
||||||
}
|
|
||||||
|
|
||||||
minerva_periodic_training();
|
minerva_periodic_training();
|
||||||
|
|
||||||
if (!_check_keyslot_access()) {
|
if (!_check_keyslot_access()) {
|
||||||
|
@ -875,10 +880,13 @@ static void _derive_keys() {
|
||||||
|
|
||||||
minerva_periodic_training();
|
minerva_periodic_training();
|
||||||
_derive_non_unique_keys(&prod_keys, is_dev);
|
_derive_non_unique_keys(&prod_keys, is_dev);
|
||||||
|
|
||||||
minerva_periodic_training();
|
minerva_periodic_training();
|
||||||
_derive_non_unique_keys(&dev_keys, is_dev);
|
_derive_non_unique_keys(&dev_keys, is_dev);
|
||||||
|
|
||||||
minerva_periodic_training();
|
minerva_periodic_training();
|
||||||
_derive_per_generation_keys(&prod_keys);
|
_derive_per_generation_keys(&prod_keys);
|
||||||
|
|
||||||
minerva_periodic_training();
|
minerva_periodic_training();
|
||||||
_derive_per_generation_keys(&dev_keys);
|
_derive_per_generation_keys(&dev_keys);
|
||||||
|
|
||||||
|
@ -907,6 +915,89 @@ static void _derive_keys() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void derive_amiibo_keys() {
|
||||||
|
minerva_change_freq(FREQ_1600);
|
||||||
|
|
||||||
|
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;
|
||||||
|
const u8 *encrypted_keys = is_dev ? encrypted_nfc_keys_dev : encrypted_nfc_keys;
|
||||||
|
|
||||||
|
_derive_master_keys(&prod_keys, &dev_keys, is_dev);
|
||||||
|
|
||||||
|
minerva_periodic_training();
|
||||||
|
|
||||||
|
display_backlight_brightness(h_cfg.backlight, 1000);
|
||||||
|
gfx_clear_partial_grey(0x1B, 32, 1224);
|
||||||
|
gfx_con_setpos(0, 32);
|
||||||
|
|
||||||
|
color_idx = 0;
|
||||||
|
|
||||||
|
minerva_periodic_training();
|
||||||
|
|
||||||
|
if (!_key_exists(keys->master_key[0])) {
|
||||||
|
EPRINTF("Unable to derive master keys for NFC.");
|
||||||
|
minerva_change_freq(FREQ_800);
|
||||||
|
btn_wait();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_decrypt_aes_key(8, keys->temp_key, nfc_key_source, keys->master_key[0]);
|
||||||
|
|
||||||
|
nfc_keyblob_t __attribute__((aligned(4))) nfc_keyblob;
|
||||||
|
static const u8 nfc_iv[AES_128_KEY_SIZE] = {
|
||||||
|
0xB9, 0x1D, 0xC1, 0xCF, 0x33, 0x5F, 0xA6, 0x13, 0x2A, 0xEF, 0x90, 0x99, 0xAA, 0xCA, 0x93, 0xC8};
|
||||||
|
se_aes_key_set(6, keys->temp_key, AES_128_KEY_SIZE);
|
||||||
|
se_aes_crypt_ctr(6, &nfc_keyblob, sizeof(nfc_keyblob), encrypted_keys, sizeof(nfc_keyblob), &nfc_iv);
|
||||||
|
|
||||||
|
minerva_periodic_training();
|
||||||
|
|
||||||
|
u8 xor_pad[0x20] __attribute__((aligned(4))) = {0};
|
||||||
|
se_aes_key_set(6, nfc_keyblob.ctr_key, AES_128_KEY_SIZE);
|
||||||
|
se_aes_crypt_ctr(6, xor_pad, sizeof(xor_pad), xor_pad, sizeof(xor_pad), nfc_keyblob.ctr_iv);
|
||||||
|
|
||||||
|
minerva_periodic_training();
|
||||||
|
|
||||||
|
nfc_save_key_t __attribute__((aligned(4))) nfc_save_keys[2] = {0};
|
||||||
|
memcpy(nfc_save_keys[0].hmac_key, nfc_keyblob.hmac_key, sizeof(nfc_keyblob.hmac_key));
|
||||||
|
memcpy(nfc_save_keys[0].phrase, nfc_keyblob.phrase, sizeof(nfc_keyblob.phrase));
|
||||||
|
nfc_save_keys[0].seed_size = sizeof(nfc_keyblob.seed);
|
||||||
|
memcpy(nfc_save_keys[0].seed, nfc_keyblob.seed, sizeof(nfc_keyblob.seed));
|
||||||
|
memcpy(nfc_save_keys[0].xor_pad, xor_pad, sizeof(xor_pad));
|
||||||
|
|
||||||
|
memcpy(nfc_save_keys[1].hmac_key, nfc_keyblob.hmac_key_for_verif, sizeof(nfc_keyblob.hmac_key_for_verif));
|
||||||
|
memcpy(nfc_save_keys[1].phrase, nfc_keyblob.phrase_for_verif, sizeof(nfc_keyblob.phrase_for_verif));
|
||||||
|
nfc_save_keys[1].seed_size = sizeof(nfc_keyblob.seed_for_verif);
|
||||||
|
memcpy(nfc_save_keys[1].seed, nfc_keyblob.seed_for_verif, sizeof(nfc_keyblob.seed_for_verif));
|
||||||
|
memcpy(nfc_save_keys[1].xor_pad, xor_pad, sizeof(xor_pad));
|
||||||
|
|
||||||
|
minerva_periodic_training();
|
||||||
|
|
||||||
|
u8 hash[0x20] = {0};
|
||||||
|
se_calc_sha256_oneshot(hash, &nfc_save_keys[0], sizeof(nfc_save_keys));
|
||||||
|
|
||||||
|
if (memcmp(hash, is_dev ? nfc_blob_hash_dev : nfc_blob_hash, sizeof(hash)) != 0) {
|
||||||
|
EPRINTF("Amiibo hash mismatch. Skipping save.");
|
||||||
|
minerva_change_freq(FREQ_800);
|
||||||
|
btn_wait();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *keyfile_path = is_dev ? "sd:/switch/key_dev.bin" : "sd:/switch/key_retail.bin";
|
||||||
|
|
||||||
|
if (!sd_save_to_file(&nfc_save_keys[0], sizeof(nfc_save_keys), keyfile_path)) {
|
||||||
|
gfx_printf("%kWrote Amiibo keys to\n %s\n", colors[(color_idx++) % 6], keyfile_path);
|
||||||
|
} else {
|
||||||
|
EPRINTF("Unable to save Amiibo keys to SD.");
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx_printf("\n%kPress a button to return to the menu.", colors[(color_idx++) % 6]);
|
||||||
|
minerva_change_freq(FREQ_800);
|
||||||
|
btn_wait();
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
}
|
||||||
|
|
||||||
void dump_keys() {
|
void dump_keys() {
|
||||||
minerva_change_freq(FREQ_1600);
|
minerva_change_freq(FREQ_1600);
|
||||||
|
|
||||||
|
@ -969,6 +1060,8 @@ static void _save_key_family(const char *name, const void *data, u32 start_key,
|
||||||
free(temp_name);
|
free(temp_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Equivalent to spl::GenerateAesKek. When key_seed is set, the result is as if spl::GenerateAesKey was called immediately after.
|
||||||
|
// The generation and option args are dictated by master_key and kek_seed.
|
||||||
static void _generate_kek(u32 ks, const void *key_source, const void *master_key, const void *kek_seed, const void *key_seed) {
|
static void _generate_kek(u32 ks, const void *key_source, const void *master_key, const void *kek_seed, const void *key_seed) {
|
||||||
if (!_key_exists(key_source) || !_key_exists(master_key) || !_key_exists(kek_seed))
|
if (!_key_exists(key_source) || !_key_exists(master_key) || !_key_exists(kek_seed))
|
||||||
return;
|
return;
|
||||||
|
@ -980,6 +1073,12 @@ static void _generate_kek(u32 ks, const void *key_source, const void *master_key
|
||||||
se_aes_unwrap_key(ks, ks, key_seed);
|
se_aes_unwrap_key(ks, ks, key_seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Equivalent to spl::DecryptAesKey.
|
||||||
|
static void _decrypt_aes_key(u32 ks, void *dst, const void *key_source, const void *master_key) {
|
||||||
|
_generate_kek(ks, aes_key_decryption_source, master_key, aes_kek_generation_source, aes_key_generation_source);
|
||||||
|
se_aes_crypt_block_ecb(ks, 0, dst, key_source);
|
||||||
|
}
|
||||||
|
|
||||||
static void _get_secure_data(key_derivation_ctx_t *keys, void *dst) {
|
static void _get_secure_data(key_derivation_ctx_t *keys, void *dst) {
|
||||||
se_aes_key_set(6, keys->device_key, AES_128_KEY_SIZE);
|
se_aes_key_set(6, keys->device_key, AES_128_KEY_SIZE);
|
||||||
u8 *d = (u8 *)dst;
|
u8 *d = (u8 *)dst;
|
||||||
|
|
|
@ -83,6 +83,27 @@ typedef struct {
|
||||||
u8 unused[0x150];
|
u8 unused[0x150];
|
||||||
} encrypted_keyblob_t;
|
} encrypted_keyblob_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char phrase[0xE];
|
||||||
|
u8 seed[0xE];
|
||||||
|
u8 hmac_key[0x10];
|
||||||
|
char phrase_for_verif[0xE];
|
||||||
|
u8 seed_for_verif[0x10];
|
||||||
|
u8 hmac_key_for_verif[0x10];
|
||||||
|
u8 ctr_key[0x10];
|
||||||
|
u8 ctr_iv[0x10];
|
||||||
|
u8 pad[6];
|
||||||
|
} nfc_keyblob_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u8 hmac_key[0x10];
|
||||||
|
char phrase[0xE];
|
||||||
|
u8 rsvd;
|
||||||
|
u8 seed_size;
|
||||||
|
u8 seed[0x10];
|
||||||
|
u8 xor_pad[0x20];
|
||||||
|
} nfc_save_key_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u8 temp_key[AES_128_KEY_SIZE],
|
u8 temp_key[AES_128_KEY_SIZE],
|
||||||
bis_key[4][AES_128_KEY_SIZE * 2],
|
bis_key[4][AES_128_KEY_SIZE * 2],
|
||||||
|
@ -142,5 +163,6 @@ typedef struct {
|
||||||
|
|
||||||
void dump_keys();
|
void dump_keys();
|
||||||
int save_mariko_partial_keys(u32 start, u32 count, bool append);
|
int save_mariko_partial_keys(u32 start, u32 count, bool append);
|
||||||
|
void derive_amiibo_keys();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -304,6 +304,11 @@ void dump_emunand()
|
||||||
dump_keys();
|
dump_keys();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dump_amiibo_keys()
|
||||||
|
{
|
||||||
|
derive_amiibo_keys();
|
||||||
|
}
|
||||||
|
|
||||||
void dump_mariko_partial_keys();
|
void dump_mariko_partial_keys();
|
||||||
|
|
||||||
ment_t ment_partials[] = {
|
ment_t ment_partials[] = {
|
||||||
|
@ -340,14 +345,15 @@ ment_t ment_top[] = {
|
||||||
MDEF_HANDLER("Dump from SysNAND", dump_sysnand, colors[0]),
|
MDEF_HANDLER("Dump from SysNAND", dump_sysnand, colors[0]),
|
||||||
MDEF_HANDLER("Dump from EmuNAND", dump_emunand, colors[1]),
|
MDEF_HANDLER("Dump from EmuNAND", dump_emunand, colors[1]),
|
||||||
MDEF_CAPTION("---------------", colors[2]),
|
MDEF_CAPTION("---------------", colors[2]),
|
||||||
MDEF_MENU("Dump Mariko Partials (requires reboot)", &menu_partials, colors[3]),
|
MDEF_HANDLER("Dump Amiibo Keys", dump_amiibo_keys, colors[3]),
|
||||||
MDEF_CAPTION("---------------", colors[4]),
|
MDEF_MENU("Dump Mariko Partials (requires reboot)", &menu_partials, colors[4]),
|
||||||
MDEF_HANDLER("Payloads...", launch_tools, colors[5]),
|
MDEF_CAPTION("---------------", colors[5]),
|
||||||
MDEF_HANDLER("Reboot to hekate", launch_hekate, colors[0]),
|
MDEF_HANDLER("Payloads...", launch_tools, colors[0]),
|
||||||
MDEF_CAPTION("---------------", colors[1]),
|
MDEF_HANDLER("Reboot to hekate", launch_hekate, colors[1]),
|
||||||
MDEF_HANDLER_EX("Reboot (OFW)", &STATE_REBOOT_BYPASS_FUSES, power_set_state_ex, colors[2]),
|
MDEF_CAPTION("---------------", colors[2]),
|
||||||
MDEF_HANDLER_EX("Reboot (RCM)", &STATE_REBOOT_RCM, power_set_state_ex, colors[3]),
|
MDEF_HANDLER_EX("Reboot (OFW)", &STATE_REBOOT_BYPASS_FUSES, power_set_state_ex, colors[3]),
|
||||||
MDEF_HANDLER_EX("Power off", &STATE_POWER_OFF, power_set_state_ex, colors[4]),
|
MDEF_HANDLER_EX("Reboot (RCM)", &STATE_REBOOT_RCM, power_set_state_ex, colors[4]),
|
||||||
|
MDEF_HANDLER_EX("Power off", &STATE_POWER_OFF, power_set_state_ex, colors[5]),
|
||||||
MDEF_END()
|
MDEF_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -369,7 +375,7 @@ void dump_mariko_partial_keys()
|
||||||
// Grey out dumping menu items as the keyslots have been invalidated.
|
// Grey out dumping menu items as the keyslots have been invalidated.
|
||||||
grey_out_menu_item(&ment_top[0]);
|
grey_out_menu_item(&ment_top[0]);
|
||||||
grey_out_menu_item(&ment_top[1]);
|
grey_out_menu_item(&ment_top[1]);
|
||||||
grey_out_menu_item(&ment_top[3]);
|
grey_out_menu_item(&ment_top[4]);
|
||||||
grey_out_menu_item(&ment_partials[18]);
|
grey_out_menu_item(&ment_partials[18]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,18 +439,18 @@ void ipl_main()
|
||||||
// Grey out reboot to RCM option if on Mariko or patched console.
|
// Grey out reboot to RCM option if on Mariko or patched console.
|
||||||
if (h_cfg.t210b01 || h_cfg.rcm_patched)
|
if (h_cfg.t210b01 || h_cfg.rcm_patched)
|
||||||
{
|
{
|
||||||
grey_out_menu_item(&ment_top[9]);
|
grey_out_menu_item(&ment_top[10]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grey out Mariko partial dump option on Erista.
|
// Grey out Mariko partial dump option on Erista.
|
||||||
if (!h_cfg.t210b01) {
|
if (!h_cfg.t210b01) {
|
||||||
grey_out_menu_item(&ment_top[3]);
|
grey_out_menu_item(&ment_top[4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grey out reboot to hekate option if no update.bin found.
|
// Grey out reboot to hekate option if no update.bin found.
|
||||||
if (f_stat("bootloader/update.bin", NULL))
|
if (f_stat("bootloader/update.bin", NULL))
|
||||||
{
|
{
|
||||||
grey_out_menu_item(&ment_top[6]);
|
grey_out_menu_item(&ment_top[7]);
|
||||||
}
|
}
|
||||||
|
|
||||||
minerva_change_freq(FREQ_800);
|
minerva_change_freq(FREQ_800);
|
||||||
|
|
Loading…
Reference in a new issue