mirror of
https://github.com/Decscots/Lockpick_RCM.git
synced 2024-11-25 13:56:54 +01:00
Validate mariko keyslot contents; dump class keys
This commit is contained in:
parent
fe17b12ea7
commit
d84ab5796a
23
README.md
23
README.md
@ -11,6 +11,29 @@ Usage
|
|||||||
* Upon completion, keys will be saved to `/switch/prod.keys` and titlekeys to `/switch/title.keys` on SD
|
* Upon completion, keys will be saved to `/switch/prod.keys` and titlekeys to `/switch/title.keys` on SD
|
||||||
* If the console has Firmware 7.x or higher, the `/sept/` folder from [Atmosphère](https://github.com/Atmosphere-NX/Atmosphere/releases) or [Kosmos](https://github.com/AtlasNX/Kosmos/releases) release zip must be present on SD or else only keyblob master key derivation is possible (ie. up to `master_key_05` only)
|
* If the console has Firmware 7.x or higher, the `/sept/` folder from [Atmosphère](https://github.com/Atmosphere-NX/Atmosphere/releases) or [Kosmos](https://github.com/AtlasNX/Kosmos/releases) release zip must be present on SD or else only keyblob master key derivation is possible (ie. up to `master_key_05` only)
|
||||||
|
|
||||||
|
Mariko-Specific Keys
|
||||||
|
=
|
||||||
|
Mariko consoles have several unique keys and protected keyslots. To get your SBK or the Mariko specific keys, you will need to use the `/switch/partialaes.keys` file along with a brute forcing tool such as <https://files.sshnuke.net/PartialAesKeyCrack.zip>. The contents of this file are the keyslot number followed by the result of that keyslot encrypting 16 null bytes. With the tool linked above, enter them in sequence for a given keyslot you want the contents of, for example: `PartialAesKeyCrack.exe <num1> <num2> <num3> <num4>` with the `--numthreads=N` where N is the number of threads you can dedicate to the brute force.
|
||||||
|
|
||||||
|
The keyslots are as follows, with names recognized by `hactool`:
|
||||||
|
* 0-11 - `mariko_aes_class_key_xx` (this is not used by the Switch but is set by the bootrom; hactoolnet recognizes it but it serves no purpose)
|
||||||
|
* 12 - `mariko_kek` (not unique - this is used for master key derivation)
|
||||||
|
* 13 - `mariko_bek` (not unique - this is used for BCT and package1 decryption)
|
||||||
|
* 14 - `secure_boot_key` (console unique - this isn't needed for further key derivation than what Lockpick_RCM does but might be nice to have for your records)
|
||||||
|
* 15 - Secure storage key (console unique - this is not used on retail or dev consoles and not recognized by any tools)
|
||||||
|
|
||||||
|
So if you want to brute force the `mariko_kek`, open your `partialaes.keys` and observe the numbers beneath keyslot 12. Here's an example with fake numbers:
|
||||||
|
```
|
||||||
|
12
|
||||||
|
11111111111111111111111111111111 22222222222222222222222222222222 33333333333333333333333333333333 44444444444444444444444444444444
|
||||||
|
```
|
||||||
|
Then take those numbers and open a command prompt window at the location of the exe linked above and type:
|
||||||
|
`PartialAesKeyCrack.exe 11111111111111111111111111111111 22222222222222222222222222222222 33333333333333333333333333333333 44444444444444444444444444444444` and if you're on a powerful enough multicore system, add ` --numthreads=[whatever number of threads]`, ideally not your system's maximum if it's, for example, an older laptop with a low-end dual core CPU. On a Ryzen 3900x with 24 threads this generates a lot of heat but finishes in about 45 seconds.
|
||||||
|
|
||||||
|
These keys never change so a brute force need only be conducted once.
|
||||||
|
|
||||||
|
This works due to the security engine immediately flushing writes to keyslots which can be written one 32-bit chunk at a time. See: <https://switchbrew.org/wiki/Switch_System_Flaws#Hardware>
|
||||||
|
|
||||||
Building
|
Building
|
||||||
=
|
=
|
||||||
Install [devkitARM](https://devkitpro.org/) and run `make`.
|
Install [devkitARM](https://devkitpro.org/) and run `make`.
|
||||||
|
@ -52,6 +52,23 @@ static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attribut
|
|||||||
{0xC1, 0x8D, 0x16, 0xBB, 0x2A, 0xE4, 0x1D, 0xD4, 0xC2, 0xC1, 0xB6, 0x40, 0x94, 0x35, 0x63, 0x98}, /* Master key 0A encrypted with Master key 0B. */
|
{0xC1, 0x8D, 0x16, 0xBB, 0x2A, 0xE4, 0x1D, 0xD4, 0xC2, 0xC1, 0xB6, 0x40, 0x94, 0x35, 0x63, 0x98}, /* Master key 0A encrypted with Master key 0B. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const u8 mariko_key_vectors[][0x10] __attribute__((aligned(4))) = {
|
||||||
|
{0x20, 0x9E, 0x97, 0xAE, 0xAF, 0x7E, 0x6A, 0xF6, 0x9E, 0xF5, 0xA7, 0x17, 0x2F, 0xF4, 0x49, 0xA6}, /* Zeroes encrypted with AES Class Key 00. */
|
||||||
|
{0x83, 0x1C, 0xC7, 0x7F, 0xB8, 0xB2, 0x66, 0x16, 0xFC, 0x6B, 0x81, 0xBB, 0xF6, 0x05, 0x07, 0x49}, /* Zeroes encrypted with AES Class Key 01. */
|
||||||
|
{0x61, 0x19, 0xBA, 0x39, 0x6D, 0xFA, 0xF4, 0x63, 0x27, 0x8E, 0x9E, 0xB1, 0xEA, 0xD4, 0x65, 0xCC}, /* Zeroes encrypted with AES Class Key 02. */
|
||||||
|
{0x6C, 0xDB, 0x10, 0xD4, 0x14, 0x3A, 0xBD, 0x22, 0xC9, 0xCC, 0xEF, 0xE4, 0xA0, 0x94, 0x85, 0x87}, /* Zeroes encrypted with AES Class Key 03. */
|
||||||
|
{0xD3, 0x40, 0xC7, 0x86, 0xDC, 0x77, 0x50, 0x7C, 0x01, 0x56, 0x11, 0xDE, 0x18, 0xDF, 0x30, 0xCA}, /* Zeroes encrypted with AES Class Key 04. */
|
||||||
|
{0xC4, 0x8B, 0xD7, 0x5A, 0x22, 0x6C, 0xF7, 0x85, 0xE4, 0xC0, 0x68, 0xFC, 0xB4, 0xD8, 0x76, 0x6C}, /* Zeroes encrypted with AES Class Key 05. */
|
||||||
|
{0x83, 0x86, 0xEF, 0xE6, 0x6B, 0x38, 0x24, 0xD3, 0xC9, 0xB0, 0xE7, 0x03, 0x59, 0xC8, 0x54, 0xB9}, /* Zeroes encrypted with AES Class Key 06. */
|
||||||
|
{0xDA, 0xC0, 0xD3, 0x27, 0x1D, 0x35, 0xAB, 0x4B, 0x01, 0x63, 0x90, 0xED, 0x1B, 0x5D, 0xA7, 0x6C}, /* Zeroes encrypted with AES Class Key 07. */
|
||||||
|
{0x96, 0x75, 0x0E, 0x4F, 0xF5, 0x1A, 0xAF, 0xD4, 0x30, 0x73, 0x8C, 0x61, 0x03, 0xE5, 0xF7, 0x80}, /* Zeroes encrypted with AES Class Key 08. */
|
||||||
|
{0x74, 0xF2, 0x1D, 0xA1, 0x4C, 0x48, 0x91, 0xE6, 0xE0, 0xD5, 0x19, 0x42, 0x2A, 0x2B, 0x5D, 0xF8}, /* Zeroes encrypted with AES Class Key 09. */
|
||||||
|
{0x7D, 0xA6, 0xFE, 0xDA, 0xF9, 0xEF, 0x83, 0xD8, 0x29, 0x40, 0x24, 0x6D, 0x70, 0x8D, 0x99, 0x93}, /* Zeroes encrypted with AES Class Key 0A. */
|
||||||
|
{0xF6, 0x71, 0xAD, 0xC3, 0xCD, 0xD4, 0x2F, 0x37, 0xAB, 0x50, 0x1C, 0x9B, 0xAF, 0x3B, 0xE6, 0xC3}, /* Zeroes encrypted with AES Class Key 0B. */
|
||||||
|
{0x01, 0x96, 0x59, 0x07, 0x62, 0xF4, 0xF4, 0x2D, 0x13, 0x60, 0xD8, 0x03, 0xFB, 0xF0, 0xAE, 0xC8}, /* Zeroes encrypted with Mariko KEK. */
|
||||||
|
{0x95, 0x48, 0xC1, 0x59, 0x0F, 0x84, 0x19, 0xC4, 0xAB, 0x69, 0x05, 0x88, 0x01, 0x31, 0x52, 0x59}, /* Zeroes encrypted with Mariko BEK. */
|
||||||
|
};
|
||||||
|
|
||||||
//======================================Keys======================================//
|
//======================================Keys======================================//
|
||||||
// from Package1 -> Secure_Monitor
|
// from Package1 -> Secure_Monitor
|
||||||
static const u8 aes_kek_generation_source[0x10] __attribute__((aligned(4))) = {
|
static const u8 aes_kek_generation_source[0x10] __attribute__((aligned(4))) = {
|
||||||
|
@ -682,15 +682,28 @@ static bool _derive_emmc_keys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit
|
|||||||
|
|
||||||
// The security engine supports partial key override for locked keyslots
|
// The security engine supports partial key override for locked keyslots
|
||||||
// This allows for a manageable brute force on a PC
|
// This allows for a manageable brute force on a PC
|
||||||
// Then we can recover the Mariko KEK, BEK, unique SBK and SSK
|
// Then the Mariko AES class keys, KEK, BEK, unique SBK and SSK can be recovered
|
||||||
static void _save_mariko_partial_keys(char *text_buffer) {
|
static void _save_mariko_partial_keys(u32 start, u32 count, bool append) {
|
||||||
|
if (start + count > SE_AES_KEYSLOT_COUNT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
u32 pos = 0;
|
u32 pos = 0;
|
||||||
u32 zeros[4] = {0};
|
u32 zeros[4] = {0};
|
||||||
u8 *data = malloc(4 * AES_128_KEY_SIZE);
|
u8 *data = malloc(4 * AES_128_KEY_SIZE);
|
||||||
for (u32 ks = 12; ks < 16; ks++) {
|
char *text_buffer = calloc(1, 0x100 * count);
|
||||||
// First, encrypt zeros with complete key
|
|
||||||
|
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
|
||||||
se_aes_crypt_block_ecb(ks, 1, &data[3 * AES_128_KEY_SIZE], zeros);
|
se_aes_crypt_block_ecb(ks, 1, &data[3 * AES_128_KEY_SIZE], zeros);
|
||||||
pos += s_printf(&text_buffer[pos], "%d\n", ks);
|
|
||||||
|
|
||||||
// We only need to overwrite 3 of the dwords of the key
|
// We only need to overwrite 3 of the dwords of the key
|
||||||
for (u32 i = 0; i < 3; i++) {
|
for (u32 i = 0; i < 3; i++) {
|
||||||
@ -699,15 +712,49 @@ static void _save_mariko_partial_keys(char *text_buffer) {
|
|||||||
// Encrypt zeros with more of the key zeroed out
|
// 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, 1, &data[(2 - i) * AES_128_KEY_SIZE], zeros);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
for (u32 i = 0; i < 4; i++) {
|
for (u32 i = 0; i < 4; i++) {
|
||||||
for (u32 j = 0; j < AES_128_KEY_SIZE; j++)
|
for (u32 j = 0; j < AES_128_KEY_SIZE; j++)
|
||||||
pos += s_printf(&text_buffer[pos], "%02x", data[i * AES_128_KEY_SIZE + j]);
|
pos += s_printf(&text_buffer[pos], "%02x", data[i * AES_128_KEY_SIZE + j]);
|
||||||
pos += s_printf(&text_buffer[pos], "\n");
|
pos += s_printf(&text_buffer[pos], " ");
|
||||||
}
|
}
|
||||||
|
pos += s_printf(&text_buffer[pos], "\n");
|
||||||
}
|
}
|
||||||
free(data);
|
free(data);
|
||||||
sd_save_to_file(text_buffer, strlen(text_buffer), "sd:/switch/partialaes.keys");
|
|
||||||
|
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);
|
||||||
|
|
||||||
gfx_printf("%kWrote partials to sd:/switch/partialaes.keys\n", colors[(color_idx++) % 6]);
|
gfx_printf("%kWrote partials to sd:/switch/partialaes.keys\n", colors[(color_idx++) % 6]);
|
||||||
|
|
||||||
|
free(text_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, const pkg1_id_t *pkg1_id, u32 start_whole_operation_time, u32 derivable_key_count) {
|
static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, const pkg1_id_t *pkg1_id, u32 start_whole_operation_time, u32 derivable_key_count) {
|
||||||
@ -797,8 +844,7 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl
|
|||||||
EPRINTF("Unable to save keys to SD.");
|
EPRINTF("Unable to save keys to SD.");
|
||||||
|
|
||||||
if (h_cfg.t210b01) {
|
if (h_cfg.t210b01) {
|
||||||
memset(text_buffer, 0, text_buffer_size);
|
_save_mariko_partial_keys(12, 4, true);
|
||||||
_save_mariko_partial_keys(text_buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_titlekey_count == 0) {
|
if (_titlekey_count == 0) {
|
||||||
@ -836,8 +882,16 @@ static bool _check_keyslot_access() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void _derive_keys() {
|
static void _derive_keys() {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
if (!_check_keyslot_access()) {
|
if (!_check_keyslot_access()) {
|
||||||
EPRINTF("Unable to set crypto keyslots!\nTry launching payload differently\n or flash Spacecraft-NX if using a modchip!");
|
EPRINTF("Unable to set crypto keyslots!\nTry launching payload differently\n or flash Spacecraft-NX if using a modchip.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user