diff --git a/source/gfx/gfx.h b/source/gfx/gfx.h index 94cb0ed..a5c9fd6 100644 --- a/source/gfx/gfx.h +++ b/source/gfx/gfx.h @@ -47,6 +47,7 @@ void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); +void gfx_box(int x0, int y0, int x1, int y1, u32 color); // Global gfx console and context. gfx_ctxt_t gfx_ctxt; diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl deleted file mode 100644 index 5b0f6b7..0000000 --- a/source/keys/key_sources.inl +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2019 shchmue - * - * 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 . - */ - -static const u8 zeros[0x10] = {0}; - -static const u8 keyblob_key_source[][0x10] = { - {0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3}, //1.0.0 - {0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC}, //3.0.0 - {0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B}, //3.0.1 - {0x2D, 0x1F, 0x48, 0x80, 0xED, 0xEC, 0xED, 0x3E, 0x3C, 0xF2, 0x48, 0xB5, 0x65, 0x7D, 0xF7, 0xBE}, //4.0.0 - {0xBB, 0x5A, 0x01, 0xF9, 0x88, 0xAF, 0xF5, 0xFC, 0x6C, 0xFF, 0x07, 0x9E, 0x13, 0x3C, 0x39, 0x80}, //5.0.0 - {0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0} //6.0.0 -}; - -static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600][0x10] = { - {0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, //6.2.0 - {0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, //7.0.0 - {0xDE, 0xDC, 0xE3, 0x39, 0x30, 0x88, 0x16, 0xF8, 0xAE, 0x97, 0xAD, 0xEC, 0x64, 0x2D, 0x41, 0x41}, //8.1.0 - {0x1A, 0xEC, 0x11, 0x82, 0x2B, 0x32, 0x38, 0x7A, 0x2B, 0xED, 0xBA, 0x01, 0x47, 0x7E, 0x3B, 0x67}, //9.0.0 - {0x30, 0x3F, 0x02, 0x7E, 0xD8, 0x38, 0xEC, 0xD7, 0x93, 0x25, 0x34, 0xB5, 0x30, 0xEB, 0xCA, 0x7A}, //9.1.0 -}; - -static const u8 mkey_vectors[KB_FIRMWARE_VERSION_MAX+1][0x10] = -{ - {0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D}, /* Zeroes encrypted with Master Key 00. */ - {0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD}, /* Master key 00 encrypted with Master key 01. */ - {0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72}, /* Master key 01 encrypted with Master key 02. */ - {0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07}, /* Master key 02 encrypted with Master key 03. */ - {0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9}, /* Master key 03 encrypted with Master key 04. */ - {0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */ - {0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */ - {0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */ - {0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */ - {0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80}, /* Master key 08 encrypted with Master key 09. */ - {0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A}, /* Master key 09 encrypted with Master key 0A. */ -}; - -//======================================Keys======================================// -// from Package1 -> Secure_Monitor -static const u8 aes_kek_generation_source[0x10] = { - 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9}; -static const u8 aes_kek_seed_01[0x10] = { - 0xA2, 0xAB, 0xBF, 0x9C, 0x92, 0x2F, 0xBB, 0xE3, 0x78, 0x79, 0x9B, 0xC0, 0xCC, 0xEA, 0xA5, 0x74}; -static const u8 aes_kek_seed_03[0x10] = { - 0xE5, 0x4D, 0x9A, 0x02, 0xF0, 0x4F, 0x5F, 0xA8, 0xAD, 0x76, 0x0A, 0xF6, 0x32, 0x95, 0x59, 0xBB}; -static const u8 package2_key_source[0x10] = { - 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7}; -static const u8 titlekek_source[0x10] = { - 0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B}; -static const u8 retail_specific_aes_key_source[0x10] = { - 0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95}; - -// from Package1ldr (or Secure_Monitor on 6.2.0) -static const u8 keyblob_mac_key_source[0x10] = { - 0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5}; -static const u8 master_key_source[0x10] = { - 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C}; -static const u8 per_console_key_source[0x10] = { - 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78}; -static const u8 per_console_key_source_4x[0x10] = { - 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28}; - -static const u8 new_device_key_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = { - {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.x New Device Key Source. */ - {0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.x New Device Key Source. */ - {0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.x New Device Key Source. */ - {0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 New Device Key Source. */ - {0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 New Device Key Source. */ - {0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 New Device Key Source. */ - {0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 New Device Key Source. */ - {0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 New Device Key Source. */ -}; - -static const u8 new_device_keygen_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = { - {0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.x New Device Keygen Source. */ - {0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.x New Device Keygen Source. */ - {0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.x New Device Keygen Source. */ - {0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 New Device Keygen Source. */ - {0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */ - {0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 New Device Keygen Source. */ - {0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 New Device Keygen Source. */ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.1.0 New Device Keygen Source to be added on next change-of-keys. */ -}; - -// from SPL -static const u8 aes_key_generation_source[0x10] = { - 0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8}; - -// from FS -static const u8 bis_kek_source[0x10] = { - 0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F}; -static const u8 bis_key_source[3][0x20] = { - { - 0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48, - 0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06}, - { - 0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F, - 0x44, 0x42, 0x4E, 0xDA, 0xB4, 0x9D, 0xFC, 0xD9, 0x87, 0x77, 0x24, 0x9A, 0xDC, 0x9F, 0x7C, 0xA4}, - { - 0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C, - 0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4} -}; - -static const u8 fs_hashes_sha256[13][0x20] = { - { // header_kek_source - 0x18, 0x88, 0xca, 0xed, 0x55, 0x51, 0xb3, 0xed, 0xe0, 0x14, 0x99, 0xe8, 0x7c, 0xe0, 0xd8, 0x68, - 0x27, 0xf8, 0x08, 0x20, 0xef, 0xb2, 0x75, 0x92, 0x10, 0x55, 0xaa, 0x4e, 0x2a, 0xbd, 0xff, 0xc2}, - { // header_key_source - 0x8f, 0x78, 0x3e, 0x46, 0x85, 0x2d, 0xf6, 0xbe, 0x0b, 0xa4, 0xe1, 0x92, 0x73, 0xc4, 0xad, 0xba, - 0xee, 0x16, 0x38, 0x00, 0x43, 0xe1, 0xb8, 0xc4, 0x18, 0xc4, 0x08, 0x9a, 0x8b, 0xd6, 0x4a, 0xa6}, - { // key_area_key_application_source - 0x04, 0xad, 0x66, 0x14, 0x3c, 0x72, 0x6b, 0x2a, 0x13, 0x9f, 0xb6, 0xb2, 0x11, 0x28, 0xb4, 0x6f, - 0x56, 0xc5, 0x53, 0xb2, 0xb3, 0x88, 0x71, 0x10, 0x30, 0x42, 0x98, 0xd8, 0xd0, 0x09, 0x2d, 0x9e}, - { // key_area_key_ocean_source - 0xfd, 0x43, 0x40, 0x00, 0xc8, 0xff, 0x2b, 0x26, 0xf8, 0xe9, 0xa9, 0xd2, 0xd2, 0xc1, 0x2f, 0x6b, - 0xe5, 0x77, 0x3c, 0xbb, 0x9d, 0xc8, 0x63, 0x00, 0xe1, 0xbd, 0x99, 0xf8, 0xea, 0x33, 0xa4, 0x17}, - { // key_area_key_system_source - 0x1f, 0x17, 0xb1, 0xfd, 0x51, 0xad, 0x1c, 0x23, 0x79, 0xb5, 0x8f, 0x15, 0x2c, 0xa4, 0x91, 0x2e, - 0xc2, 0x10, 0x64, 0x41, 0xe5, 0x17, 0x22, 0xf3, 0x87, 0x00, 0xd5, 0x93, 0x7a, 0x11, 0x62, 0xf7}, - { // save_mac_kek_source - 0x3D, 0xCB, 0xA1, 0x00, 0xAD, 0x4D, 0xF1, 0x54, 0x7F, 0xE3, 0xC4, 0x79, 0x5C, 0x4B, 0x22, 0x8A, - 0xA9, 0x80, 0x38, 0xF0, 0x7A, 0x36, 0xF1, 0xBC, 0x14, 0x8E, 0xEA, 0xF3, 0xDC, 0xD7, 0x50, 0xF4}, - { // save_mac_key_source - 0xB4, 0x7B, 0x60, 0x0B, 0x1A, 0xD3, 0x14, 0xF9, 0x41, 0x14, 0x7D, 0x8B, 0x39, 0x1D, 0x4B, 0x19, - 0x87, 0xCC, 0x8C, 0x88, 0x4A, 0xC8, 0x9F, 0xFC, 0x91, 0xCA, 0xE2, 0x21, 0xC5, 0x24, 0x51, 0xF7}, - { // save_mac_sd_card_kek_source - 0x60, 0x1a, 0x60, 0xbe, 0x13, 0xf6, 0x3e, 0xda, 0xec, 0xcc, 0x96, 0x7f, 0x27, 0xa3, 0xa3, 0x64, - 0x65, 0xcb, 0xe8, 0xf0, 0x29, 0xf0, 0xc4, 0x14, 0xb2, 0x36, 0x6a, 0x8b, 0x8a, 0x0f, 0x13, 0x00}, - { // save_mac_sd_card_key_source - 0xc2, 0x22, 0x0a, 0x38, 0xb6, 0x87, 0x2b, 0x63, 0xee, 0x77, 0xac, 0x8c, 0x28, 0x24, 0x7a, 0x44, - 0x02, 0xe6, 0xdd, 0x85, 0x24, 0x8b, 0x41, 0x9a, 0x6f, 0x9b, 0x17, 0x93, 0xc0, 0x50, 0x3f, 0x21}, - { // sd_card_custom_storage_key_source - 0x6b, 0x8f, 0xd2, 0x6c, 0x76, 0x5b, 0x7c, 0x67, 0x70, 0x0c, 0x68, 0x54, 0x90, 0x8e, 0xbe, 0x88, - 0x45, 0xb0, 0x55, 0xa6, 0xbb, 0xbb, 0xea, 0x0c, 0x06, 0x3a, 0x85, 0x04, 0x12, 0xd4, 0xca, 0x53}, - { // sd_card_kek_source - 0x6B, 0x2E, 0xD8, 0x77, 0xC2, 0xC5, 0x23, 0x34, 0xAC, 0x51, 0xE5, 0x9A, 0xBF, 0xA7, 0xEC, 0x45, - 0x7F, 0x4A, 0x7D, 0x01, 0xE4, 0x62, 0x91, 0xE9, 0xF2, 0xEA, 0xA4, 0x5F, 0x01, 0x1D, 0x24, 0xB7}, - { // sd_card_nca_key_source - 0x2E, 0x75, 0x1C, 0xEC, 0xF7, 0xD9, 0x3A, 0x2B, 0x95, 0x7B, 0xD5, 0xFF, 0xCB, 0x08, 0x2F, 0xD0, - 0x38, 0xCC, 0x28, 0x53, 0x21, 0x9D, 0xD3, 0x09, 0x2C, 0x6D, 0xAB, 0x98, 0x38, 0xF5, 0xA7, 0xCC}, - { // sd_card_save_key_source - 0xD4, 0x82, 0x74, 0x35, 0x63, 0xD3, 0xEA, 0x5D, 0xCD, 0xC3, 0xB7, 0x4E, 0x97, 0xC9, 0xAC, 0x8A, - 0x34, 0x21, 0x64, 0xFA, 0x04, 0x1A, 0x1D, 0xC8, 0x0F, 0x17, 0xF6, 0xD3, 0x1E, 0x4B, 0xC0, 0x1C} -}; - -static const u8 es_hashes_sha256[3][0x20] = { - { // eticket_rsa_kek - 0xB7, 0x1D, 0xB2, 0x71, 0xDC, 0x33, 0x8D, 0xF3, 0x80, 0xAA, 0x2C, 0x43, 0x35, 0xEF, 0x88, 0x73, - 0xB1, 0xAF, 0xD4, 0x08, 0xE8, 0x0B, 0x35, 0x82, 0xD8, 0x71, 0x9F, 0xC8, 0x1C, 0x5E, 0x51, 0x1C}, - { // eticket_rsa_kekek - 0xE8, 0x96, 0x5A, 0x18, 0x7D, 0x30, 0xE5, 0x78, 0x69, 0xF5, 0x62, 0xD0, 0x43, 0x83, 0xC9, 0x96, - 0xDE, 0x48, 0x7B, 0xBA, 0x57, 0x61, 0x36, 0x3D, 0x2D, 0x4D, 0x32, 0x39, 0x18, 0x66, 0xA8, 0x5C}, - { // ssl_rsa_kek_source_x - 0x69, 0xA0, 0x8E, 0x62, 0xE0, 0xAE, 0x50, 0x7B, 0xB5, 0xDA, 0x0E, 0x65, 0x17, 0x9A, 0xE3, 0xBE, - 0x05, 0x1F, 0xED, 0x3C, 0x49, 0x94, 0x1D, 0xF4, 0xEF, 0x29, 0x56, 0xD3, 0x6D, 0x30, 0x11, 0x0C} -}; - -static const u8 ssl_hashes_sha256[2][0x20] = { - { // ssl_rsa_kek_source_x - 0x69, 0xA0, 0x8E, 0x62, 0xE0, 0xAE, 0x50, 0x7B, 0xB5, 0xDA, 0x0E, 0x65, 0x17, 0x9A, 0xE3, 0xBE, - 0x05, 0x1F, 0xED, 0x3C, 0x49, 0x94, 0x1D, 0xF4, 0xEF, 0x29, 0x56, 0xD3, 0x6D, 0x30, 0x11, 0x0C}, - { // ssl_rsa_kek_source_y - 0x1C, 0x86, 0xF3, 0x63, 0x26, 0x54, 0x17, 0xD4, 0x99, 0x22, 0x9E, 0xB1, 0xC4, 0xAD, 0xC7, 0x47, - 0x9B, 0x2A, 0x15, 0xF9, 0x31, 0x26, 0x1F, 0x31, 0xEE, 0x67, 0x76, 0xAE, 0xB4, 0xC7, 0x65, 0x42} -}; \ No newline at end of file diff --git a/source/keys/keys.c b/source/keys/keys.c deleted file mode 100644 index 975e2b7..0000000 --- a/source/keys/keys.c +++ /dev/null @@ -1,1163 +0,0 @@ -/* - * Copyright (c) 2019 shchmue - * - * 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 . - */ - -#include "keys.h" - -#include "../config/config.h" -#include "../gfx/di.h" -#include "../gfx/gfx.h" -#include "../gfx/tui.h" -#include "../hos/pkg1.h" -#include "../hos/pkg2.h" -#include "../hos/sept.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../mem/mc.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 "../soc/smmu.h" -#include "../soc/t210.h" -#include "../storage/emummc.h" -#include "../storage/nx_emmc.h" -#include "../storage/sdmmc.h" -#include "../utils/btn.h" -#include "../utils/list.h" -#include "../utils/sprintf.h" -#include "../utils/util.h" - -#include "key_sources.inl" -#include "save.h" - -#include - -extern bool sd_mount(); -extern void sd_unmount(); -extern int sd_save_to_file(void *buf, u32 size, const char *filename); - -extern hekate_config h_cfg; - -extern bool clear_sector_cache; - -u32 _key_count = 0, _titlekey_count = 0; -u32 color_idx = 0; -sdmmc_storage_t storage; -emmc_part_t *system_part; -u32 start_time, end_time; - -#define TPRINTF(text) \ - end_time = get_tmr_us(); \ - gfx_printf(text" done in %d us\n", end_time - start_time); \ - start_time = get_tmr_us(); \ - minerva_periodic_training() - -#define TPRINTFARGS(text, args...) \ - end_time = get_tmr_us(); \ - gfx_printf(text" done in %d us\n", args, end_time - start_time); \ - start_time = get_tmr_us(); \ - minerva_periodic_training() - -#define SAVE_KEY(name, src, len) _save_key(name, src, len, text_buffer) -#define SAVE_KEY_FAMILY(name, src, start, count, len) _save_key_family(name, src, start, count, len, text_buffer) - -// key functions -static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); }; -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); -// nca functions -static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len, const u8 key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10]); -static u32 _nca_fread_ctr(u32 ks, FIL *fp, void *buffer, u32 offset, u32 len, u8 *ctr); -static void _update_ctr(u8 *ctr, u32 ofs); -// titlekey functions -static bool _test_key_pair(const void *E, const void *D, const void *N); -static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size); - -void dump_keys() { - u8 temp_key[0x10], - bis_key[4][0x20] = {0}, - device_key[0x10] = {0}, - new_device_key[0x10] = {0}, - sd_seed[0x10] = {0}, - // FS-related keys - fs_keys[13][0x20] = {0}, - header_key[0x20] = {0}, - save_mac_key[0x10] = {0}, - // other sysmodule sources - es_keys[3][0x10] = {0}, - eticket_rsa_kek[0x10] = {0}, - ssl_keys[0x10] = {0}, - ssl_rsa_kek[0x10] = {0}, - // keyblob-derived families - keyblob[KB_FIRMWARE_VERSION_600+1][0x90] = {0}, - keyblob_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0}, - keyblob_mac_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0}, - package1_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0}, - // master key-derived families - key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, - master_kek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, - master_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, - package2_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, - titlekek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}; - - sd_mount(); - - display_backlight_brightness(h_cfg.backlight, 1000); - gfx_clear_partial_grey(0x1B, 0, 1256); - 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); - - tui_sbar(true); - - _key_count = 0; - _titlekey_count = 0; - color_idx = 0; - - start_time = get_tmr_us(); - u32 begin_time = get_tmr_us(); - u32 retries = 0; - - tsec_ctxt_t tsec_ctxt; - sdmmc_t sdmmc; - - if (!emummc_storage_init_mmc(&storage, &sdmmc)) { - EPRINTF("Unable to init MMC."); - goto out_wait; - } - TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]); - - // Read package1. - u8 *pkg1 = (u8 *)malloc(0x40000); - emummc_storage_set_mmc_partition(&storage, 1); - emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); - const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); - 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."); - goto out_wait; - } - - bool found_tsec_fw = false; - for (const u32 *pos = (const u32 *)pkg1; (u8 *)pos < pkg1 + 0x40000; pos += 0x100 / sizeof(u32)) { - if (*pos == 0xCF42004D) { - tsec_ctxt.fw = (u8 *)pos; - found_tsec_fw = true; - break; - } - } - if (!found_tsec_fw) { - EPRINTF("Unable to locate TSEC firmware."); - goto out_wait; - } - - minerva_periodic_training(); - - tsec_key_data_t *key_data = (tsec_key_data_t *)(tsec_ctxt.fw + TSEC_KEY_DATA_ADDR); - tsec_ctxt.pkg1 = pkg1; - tsec_ctxt.size = 0x100 + key_data->blob0_size + key_data->blob1_size + key_data->blob2_size + key_data->blob3_size + key_data->blob4_size; - - u32 MAX_KEY = 6; - if (pkg1_id->kb >= KB_FIRMWARE_VERSION_620) { - MAX_KEY = pkg1_id->kb + 1; - } - - if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700) { - sd_mount(); - if (!f_stat("sd:/sept/payload.bak", NULL)) { - if (f_unlink("sd:/sept/payload.bin")) - gfx_printf("%kNote: no payload.bin already in /sept\n", colors[(color_idx++) % 6]); - f_rename("sd:/sept/payload.bak", "sd:/sept/payload.bin"); - } - - if (!h_cfg.sept_run) { - // bundle lp0 fw for sept instead of loading it from SD as hekate does - sdram_lp0_save_params(sdram_get_params_patched()); - FIL fp; - if (f_stat("sd:/sept", NULL)) { - EPRINTF("On firmware 7.x+ but Sept missing.\nSkipping new key derivation..."); - goto get_tsec; - } - // backup post-reboot payload - if (!f_stat("sd:/sept/payload.bin", NULL)) { - if (f_rename("sd:/sept/payload.bin", "sd:/sept/payload.bak")) { - EPRINTF("Unable to backup payload.bin."); - goto out_wait; - } - } - // write self to payload.bin to run again when sept finishes - u32 payload_size = *(u32 *)(IPL_LOAD_ADDR + 0x84) - IPL_LOAD_ADDR; - if (f_open(&fp, "sd:/sept/payload.bin", FA_CREATE_NEW | FA_WRITE)) { - EPRINTF("Unable to open /sept/payload.bin to write."); - goto out_wait; - } - if (f_write(&fp, (u8 *)IPL_LOAD_ADDR, payload_size, NULL)) { - EPRINTF("Unable to write self to /sept/payload.bin."); - f_close(&fp); - goto out_wait; - } - f_close(&fp); - gfx_printf("%k\nFirmware 7.x or higher detected.\n\n", colors[(color_idx++) % 6]); - gfx_printf("%kRenamed /sept/payload.bin", colors[(color_idx++) % 6]); - gfx_printf("\n to /sept/payload.bak\n\n"); - gfx_printf("%kCopied self to /sept/payload.bin\n", colors[(color_idx++) % 6]); - sdmmc_storage_end(&storage); - if (!reboot_to_sept((u8 *)tsec_ctxt.fw, tsec_ctxt.size, pkg1_id->kb)) - goto out_wait; - } else { - se_aes_key_read(12, master_key[KB_FIRMWARE_VERSION_MAX], 0x10); - } - } - -get_tsec: ; - u8 tsec_keys[0x10 * 2] = {0}; - - if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) { - u8 *tsec_paged = (u8 *)page_alloc(3); - memcpy(tsec_paged, (void *)tsec_ctxt.fw, tsec_ctxt.size); - tsec_ctxt.fw = tsec_paged; - } - - int res = 0; - - mc_disable_ahb_redirect(); - - while (tsec_query(tsec_keys, pkg1_id->kb, &tsec_ctxt) < 0) { - memset(tsec_keys, 0x00, 0x20); - retries++; - if (retries > 15) { - res = -1; - break; - } - } - free(pkg1); - - mc_enable_ahb_redirect(); - - if (res < 0) { - EPRINTFARGS("ERROR %x dumping TSEC.\n", res); - goto out_wait; - } - - TPRINTFARGS("%kTSEC key(s)... ", colors[(color_idx++) % 6]); - - // Master key derivation - if (pkg1_id->kb == KB_FIRMWARE_VERSION_620 && _key_exists(tsec_keys + 0x10)) { - se_aes_key_set(8, tsec_keys + 0x10, 0x10); // mkek6 = unwrap(mkeks6, tsecroot) - se_aes_crypt_block_ecb(8, 0, master_kek[6], master_kek_sources[0]); - se_aes_key_set(8, master_kek[6], 0x10); // mkey = unwrap(mkek, mks) - se_aes_crypt_block_ecb(8, 0, master_key[6], master_key_source); - } - - if (pkg1_id->kb >= KB_FIRMWARE_VERSION_620) { - // derive all lower master keys in case keyblobs are bad - if (_key_exists(master_key[pkg1_id->kb])) { - for (u32 i = pkg1_id->kb; i > 0; i--) { - se_aes_key_set(8, master_key[i], 0x10); - se_aes_crypt_block_ecb(8, 0, master_key[i-1], mkey_vectors[i]); - } - se_aes_key_set(8, master_key[0], 0x10); - se_aes_crypt_block_ecb(8, 0, temp_key, mkey_vectors[0]); - if (_key_exists(temp_key)) { - EPRINTFARGS("Unable to derive master key. kb = %d.\n Put current sept files on SD and retry.", pkg1_id->kb); - memset(master_key, 0, sizeof(master_key)); - } - } else if (_key_exists(master_key[KB_FIRMWARE_VERSION_MAX])) { - // handle sept version differences - for (u32 kb = KB_FIRMWARE_VERSION_MAX; kb >= KB_FIRMWARE_VERSION_620; kb--) { - for (u32 i = kb; i > 0; i--) { - se_aes_key_set(8, master_key[i], 0x10); - se_aes_crypt_block_ecb(8, 0, master_key[i-1], mkey_vectors[i]); - } - se_aes_key_set(8, master_key[0], 0x10); - se_aes_crypt_block_ecb(8, 0, temp_key, mkey_vectors[0]); - if (!_key_exists(temp_key)) { - break; - } - memcpy(master_key[kb-1], master_key[kb], 0x10); - memcpy(master_key[kb], zeros, 0x10); - } - if (_key_exists(temp_key)) { - EPRINTF("Unable to derive master key."); - memset(master_key, 0, sizeof(master_key)); - } - } - } - - u8 *keyblob_block = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1); - u8 keyblob_mac[0x10] = {0}; - u32 sbk[4] = {FUSE(FUSE_PRIVATE_KEY0), FUSE(FUSE_PRIVATE_KEY1), - FUSE(FUSE_PRIVATE_KEY2), FUSE(FUSE_PRIVATE_KEY3)}; - se_aes_key_set(8, tsec_keys, 0x10); - se_aes_key_set(9, sbk, 0x10); - for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++) { - minerva_periodic_training(); - se_aes_crypt_block_ecb(8, 0, keyblob_key[i], keyblob_key_source[i]); // temp = unwrap(kbks, tsec) - se_aes_crypt_block_ecb(9, 0, keyblob_key[i], keyblob_key[i]); // kbk = unwrap(temp, sbk) - se_aes_key_set(7, keyblob_key[i], 0x10); - se_aes_crypt_block_ecb(7, 0, keyblob_mac_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk) - if (i == 0) { - se_aes_crypt_block_ecb(7, 0, device_key, per_console_key_source); // devkey = unwrap(pcks, kbk0) - se_aes_crypt_block_ecb(7, 0, new_device_key, per_console_key_source_4x); - } - - // verify keyblob is not corrupt - emummc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + i, 1, keyblob_block); - se_aes_key_set(3, keyblob_mac_key[i], 0x10); - se_aes_cmac(3, keyblob_mac, 0x10, keyblob_block + 0x10, 0xa0); - if (memcmp(keyblob_block, keyblob_mac, 0x10)) { - EPRINTFARGS("Keyblob %x corrupt.", i); - gfx_hexdump(i, keyblob_block, 0x10); - gfx_hexdump(i, keyblob_mac, 0x10); - continue; - } - - // decrypt keyblobs - se_aes_key_set(2, keyblob_key[i], 0x10); - se_aes_crypt_ctr(2, keyblob[i], 0x90, keyblob_block + 0x20, 0x90, keyblob_block + 0x10); - - memcpy(package1_key[i], keyblob[i] + 0x80, 0x10); - memcpy(master_kek[i], keyblob[i], 0x10); - se_aes_key_set(7, master_kek[i], 0x10); - se_aes_crypt_block_ecb(7, 0, master_key[i], master_key_source); - } - free(keyblob_block); - - TPRINTFARGS("%kMaster keys... ", colors[(color_idx++) % 6]); - - /* 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 = 0; - if (pkg1_id->kb >= KB_FIRMWARE_VERSION_500) { - if ((fuse_read_odm(4) & 0x800) && fuse_read_odm(0) == 0x8E61ECAE && fuse_read_odm(1) == 0xF2BA3BB2) { - key_generation = fuse_read_odm(2) & 0x1F; - } - } - if (_key_exists(device_key)) { - if (key_generation) { - se_aes_key_set(8, new_device_key, 0x10); - se_aes_crypt_block_ecb(8, 0, temp_key, new_device_key_sources[pkg1_id->kb - KB_FIRMWARE_VERSION_400]); - se_aes_key_set(8, master_key[0], 0x10); - se_aes_unwrap_key(8, 8, new_device_keygen_sources[pkg1_id->kb - KB_FIRMWARE_VERSION_400]); - se_aes_crypt_block_ecb(8, 0, temp_key, temp_key); - } else - memcpy(temp_key, device_key, 0x10); - se_aes_key_set(8, temp_key, 0x10); - se_aes_unwrap_key(8, 8, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey) - se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x00, bis_key_source[0] + 0x00); // bkey = unwrap(bkeys, kek) - se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x10, bis_key_source[0] + 0x10); - // kek = generate_kek(bkeks, devkey, aeskek, aeskey) - _generate_kek(8, bis_kek_source, temp_key, aes_kek_generation_source, aes_key_generation_source); - se_aes_crypt_block_ecb(8, 0, bis_key[1] + 0x00, bis_key_source[1] + 0x00); // bkey = unwrap(bkeys, kek) - se_aes_crypt_block_ecb(8, 0, bis_key[1] + 0x10, bis_key_source[1] + 0x10); - se_aes_crypt_block_ecb(8, 0, bis_key[2] + 0x00, bis_key_source[2] + 0x00); - se_aes_crypt_block_ecb(8, 0, bis_key[2] + 0x10, bis_key_source[2] + 0x10); - memcpy(bis_key[3], bis_key[2], 0x20); - } - - // Dump package2. - u8 *pkg2 = NULL; - pkg2_kip1_info_t *ki = NULL; - - emummc_storage_set_mmc_partition(&storage, 0); - // Parse eMMC GPT. - LIST_INIT(gpt); - nx_emmc_gpt_parse(&gpt, &storage); - - // Find package2 partition. - emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main"); - if (!pkg2_part) { - EPRINTF("Unable to locate Package2."); - goto pkg2_done; - } - - // Read in package2 header and get package2 real size. - u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE); - nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, 1, tmp); - u32 *hdr_pkg2_raw = (u32 *)(tmp + 0x100); - u32 pkg2_size = hdr_pkg2_raw[0] ^ hdr_pkg2_raw[2] ^ hdr_pkg2_raw[3]; - free(tmp); - - if (pkg2_size > 0x7FC000) { - EPRINTF("Invalid Package2 header."); - goto pkg2_done; - } - // Read in package2. - u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE); - pkg2 = malloc(pkg2_size_aligned); - nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2); - - // Decrypt package2 and parse KIP1 blobs in INI1 section. Try all available key generations in case of pkg1/pkg2 mismatch. - minerva_periodic_training(); - pkg2_hdr_t *pkg2_hdr; - pkg2_hdr_t hdr; - u32 pkg2_kb; - for (pkg2_kb = 0; pkg2_kb < MAX_KEY; pkg2_kb++) { - se_aes_key_set(8, master_key[pkg2_kb], 0x10); - se_aes_unwrap_key(8, 8, package2_key_source); - memcpy(&hdr, pkg2 + 0x100, sizeof(pkg2_hdr_t)); - se_aes_crypt_ctr(8, &hdr, sizeof(pkg2_hdr_t), &hdr, sizeof(pkg2_hdr_t), &hdr); - if (hdr.magic == PKG2_MAGIC) - break; - } - if (pkg2_kb == MAX_KEY) { - EPRINTF("Unable to derive Package2 key."); - goto pkg2_done; - } else if (pkg2_kb != pkg1_id->kb) - EPRINTFARGS("Warning! Package1-Package2 mismatch: %d, %d", pkg1_id->kb, pkg2_kb); - - pkg2_hdr = pkg2_decrypt(pkg2); - if (!pkg2_hdr) { - EPRINTF("Unable to decrypt Package2."); - goto pkg2_done; - } - - TPRINTFARGS("%kDecrypt pkg2... ", colors[(color_idx++) % 6]); - - LIST_INIT(kip1_info); - bool new_pkg2; - pkg2_parse_kips(&kip1_info, pkg2_hdr, &new_pkg2); - LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki_tmp, &kip1_info, link) { - if(ki_tmp->kip1->tid == 0x0100000000000000ULL) { - ki = malloc(sizeof(pkg2_kip1_info_t)); - memcpy(ki, ki_tmp, sizeof(pkg2_kip1_info_t)); - break; - } - } - LIST_FOREACH_SAFE(iter, &kip1_info) - free(CONTAINER_OF(iter, pkg2_kip1_info_t, link)); - - if (!ki) { - EPRINTF("Unable to parse INI1."); - goto pkg2_done; - } - - pkg2_decompress_kip(ki, 2 | 4); // we only need .rodata and .data - TPRINTFARGS("%kDecompress FS...", colors[(color_idx++) % 6]); - - u8 hash_index = 0; - const u8 key_lengths[13] = {0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x20, 0x20}; - - if (!memcmp(pkg1_id->id, "2016", 4)) { - // 1.0.0 doesn't have SD keys at all and the first key isn't aligned with the rest - memcpy(fs_keys[2], ki->kip1->data + ki->kip1->sections[0].size_comp + 0x1ae0e, 0x10); - hash_index = 1; - } - - u8 temp_hash[0x20]; - for (u32 i = ki->kip1->sections[0].size_comp + pkg1_id->key_info.start_offset; i < ki->size - 0x20; ) { - minerva_periodic_training(); - se_calc_sha256(temp_hash, ki->kip1->data + i, key_lengths[pkg1_id->key_info.hash_order[hash_index]]); - if (!memcmp(temp_hash, fs_hashes_sha256[pkg1_id->key_info.hash_order[hash_index]], 0x20)) { - memcpy(fs_keys[pkg1_id->key_info.hash_order[hash_index]], ki->kip1->data + i, key_lengths[pkg1_id->key_info.hash_order[hash_index]]); - i += key_lengths[pkg1_id->key_info.hash_order[hash_index]]; - if (hash_index == pkg1_id->key_info.hash_max - 1) { - if (pkg1_id->key_info.hks_offset_is_from_end) - i = ki->size - pkg1_id->key_info.hks_offset; - else - i = ki->size - (ki->kip1->sections[2].size_decomp - pkg1_id->key_info.hks_offset); - } else if (hash_index == pkg1_id->key_info.hash_max) { - break; - } - hash_index++; - } else { - i += pkg1_id->key_info.alignment; - } - } -pkg2_done: - if (ki) { - free(ki); - } - free(pkg2); - - u8 *rights_ids = NULL, *titlekeys = NULL; - - TPRINTFARGS("%kFS keys... ", colors[(color_idx++) % 6]); - - if (_key_exists(fs_keys[0]) && _key_exists(fs_keys[1]) && _key_exists(master_key[0])) { - _generate_kek(8, fs_keys[0], master_key[0], aes_kek_generation_source, aes_key_generation_source); - se_aes_crypt_block_ecb(8, 0, header_key + 0x00, fs_keys[1] + 0x00); - se_aes_crypt_block_ecb(8, 0, header_key + 0x10, fs_keys[1] + 0x10); - } - - if (_key_exists(fs_keys[5]) && _key_exists(fs_keys[6]) && _key_exists(device_key)) { - _generate_kek(8, fs_keys[5], device_key, aes_kek_generation_source, NULL); - se_aes_crypt_block_ecb(8, 0, save_mac_key, fs_keys[6]); - } - - if (_key_exists(master_key[MAX_KEY])) { - MAX_KEY = KB_FIRMWARE_VERSION_MAX + 1; - } - for (u32 i = 0; i < MAX_KEY; i++) { - if (!_key_exists(master_key[i])) - continue; - if (_key_exists(fs_keys[2]) && _key_exists(fs_keys[3]) && _key_exists(fs_keys[4])) { - for (u32 j = 0; j < 3; j++) { - _generate_kek(8, fs_keys[2 + j], master_key[i], aes_kek_generation_source, NULL); - se_aes_crypt_block_ecb(8, 0, key_area_key[j][i], aes_key_generation_source); - } - } - se_aes_key_set(8, master_key[i], 0x10); - se_aes_crypt_block_ecb(8, 0, package2_key[i], package2_key_source); - se_aes_crypt_block_ecb(8, 0, titlekek[i], titlekek_source); - } - - if (!_key_exists(header_key) || !_key_exists(bis_key[2])) - { - EPRINTF("Missing FS keys. Skipping ES/SSL keys."); - goto key_output; - } - - se_aes_key_set(4, header_key + 0x00, 0x10); - se_aes_key_set(5, header_key + 0x10, 0x10); - se_aes_key_set(8, bis_key[2] + 0x00, 0x10); - se_aes_key_set(9, bis_key[2] + 0x10, 0x10); - - system_part = nx_emmc_part_find(&gpt, "SYSTEM"); - if (!system_part) { - EPRINTF("Unable to locate System partition."); - goto key_output; - } - __attribute__ ((aligned (16))) FATFS emmc_fs; - if (f_mount(&emmc_fs, "emmc:", 1)) { - EPRINTF("Unable to mount system partition."); - goto key_output; - } - - DIR dir; - FILINFO fno; - FIL fp; - save_ctx_t *save_ctx = NULL; - - // sysmodule NCAs only ever have one section (exefs) so 0x600 is sufficient - u8 *dec_header = (u8*)malloc(0x600); - char path[100] = "emmc:/Contents/registered"; - u32 titles_found = 0, title_limit = 2, read_bytes = 0; - if (!memcmp(pkg1_id->id, "2016", 4)) - title_limit = 1; - u8 *temp_file = NULL; - - if (f_opendir(&dir, path)) { - EPRINTF("Unable to open System:/Contents/registered."); - goto dismount; - } - - // prepopulate /Contents/registered in decrypted sector cache - while (!f_readdir(&dir, &fno) && fno.fname[0]) {} - f_closedir(&dir); - - if (f_opendir(&dir, path)) { - EPRINTF("Unable to open System:/Contents/registered."); - goto dismount; - } - - path[25] = '/'; - while (!f_readdir(&dir, &fno) && fno.fname[0] && titles_found < title_limit) { - minerva_periodic_training(); - memcpy(path + 26, fno.fname, 36); - path[62] = 0; - if (fno.fattrib & AM_DIR) - memcpy(path + 62, "/00", 4); - if (f_open(&fp, path, FA_READ | FA_OPEN_EXISTING)) continue; - if (f_lseek(&fp, 0x200) || f_read(&fp, dec_header, 32, &read_bytes) || read_bytes != 32) { - f_close(&fp); - continue; - } - se_aes_xts_crypt(5, 4, 0, 1, dec_header + 0x200, dec_header, 32, 1); - // es doesn't contain es key sources on 1.0.0 - if (memcmp(pkg1_id->id, "2016", 4) && *(u32*)(dec_header + 0x210) == 0x33 && dec_header[0x205] == 0) { - u8 hash_order[3] = {0, 1, 2}; - if (pkg1_id->kb >= KB_FIRMWARE_VERSION_500) { - hash_order[0] = 1; - hash_order[1] = 0; - } - hash_index = 0; - // decrypt only what is needed to locate needed keys - temp_file = (u8*)_nca_process(5, 4, &fp, pkg1_id->key_info.es_offset, 0xc0, key_area_key); - for (u32 i = 0; i <= 0xb0; ) { - se_calc_sha256(temp_hash, temp_file + i, 0x10); - if (!memcmp(temp_hash, es_hashes_sha256[hash_order[hash_index]], 0x10)) { - memcpy(es_keys[hash_order[hash_index]], temp_file + i, 0x10); - hash_index++; - if (hash_index == 3) - break; - i += 0x10; - } else { - i++; - } - } - free(temp_file); - temp_file = NULL; - titles_found++; - } else if (*(u32*)(dec_header + 0x210) == 0x24 && dec_header[0x205] == 0) { - temp_file = (u8*)_nca_process(5, 4, &fp, pkg1_id->key_info.ssl_offset, 0x70, key_area_key); - for (u32 i = 0; i <= 0x60; i++) { - se_calc_sha256(temp_hash, temp_file + i, 0x10); - if (!memcmp(temp_hash, ssl_hashes_sha256[1], 0x10)) { - memcpy(ssl_keys, temp_file + i, 0x10); - // only get ssl_rsa_kek_source_x from SSL on 1.0.0 - // we get it from ES on every other firmware - // and it's located oddly distant from ssl_rsa_kek_source_y on >= 6.0.0 - if (!memcmp(pkg1_id->id, "2016", 4)) { - se_calc_sha256(temp_hash, temp_file + i + 0x10, 0x10); - if (!memcmp(temp_hash, ssl_hashes_sha256[0], 0x10)) - memcpy(es_keys[2], temp_file + i + 0x10, 0x10); - } - break; - } - } - free(temp_file); - temp_file = NULL; - titles_found++; - } - f_close(&fp); - } - f_closedir(&dir); - free(dec_header); - - // derive eticket_rsa_kek and ssl_rsa_kek - if (_key_exists(es_keys[0]) && _key_exists(es_keys[1]) && _key_exists(master_key[0])) { - for (u32 i = 0; i < 0x10; i++) - temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; - _generate_kek(7, es_keys[1], master_key[0], temp_key, NULL); - se_aes_crypt_block_ecb(7, 0, eticket_rsa_kek, es_keys[0]); - } - if (_key_exists(ssl_keys) && _key_exists(es_keys[2]) && _key_exists(master_key[0])) { - for (u32 i = 0; i < 0x10; i++) - temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; - _generate_kek(7, es_keys[2], master_key[0], temp_key, NULL); - se_aes_crypt_block_ecb(7, 0, ssl_rsa_kek, ssl_keys); - } - - if (memcmp(pkg1_id->id, "2016", 4)) { - TPRINTFARGS("%kES & SSL keys...", colors[(color_idx++) % 6]); - } else { - TPRINTFARGS("%kSSL keys... ", colors[(color_idx++) % 6]); - } - - char private_path[200] = "sd:/"; - 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"); - if (f_open(&fp, private_path, FA_READ | FA_OPEN_EXISTING)) { - EPRINTF("Unable to open SD seed vector. Skipping."); - goto get_titlekeys; - } - // get sd seed verification vector - if (f_read(&fp, temp_key, 0x10, &read_bytes) || read_bytes != 0x10) { - EPRINTF("Unable to read SD seed vector. Skipping."); - f_close(&fp); - goto get_titlekeys; - } - f_close(&fp); - - // this file is so small that parsing the savedata properly would take longer - if (f_open(&fp, "emmc:/save/8000000000000043", FA_READ | FA_OPEN_EXISTING)) { - EPRINTF("Unable to open ns_appman save.\nSkipping SD seed."); - goto get_titlekeys; - } - - u8 read_buf[0x20] = {0}; - for (u32 i = 0x8000; i < f_size(&fp); i += 0x4000) { - if (f_lseek(&fp, i) || f_read(&fp, read_buf, 0x20, &read_bytes) || read_bytes != 0x20) - break; - if (!memcmp(temp_key, read_buf, 0x10)) { - memcpy(sd_seed, read_buf + 0x10, 0x10); - break; - } - } - f_close(&fp); - - TPRINTFARGS("%kSD Seed... ", colors[(color_idx++) % 6]); - -get_titlekeys: - if (!_key_exists(eticket_rsa_kek)) - goto dismount; - - gfx_printf("%kTitlekeys... ", colors[(color_idx++) % 6]); - u32 save_x = gfx_con.x, save_y = gfx_con.y; - gfx_printf("\n%kCommon... ", colors[color_idx % 6]); - - u8 null_hash[0x20] = { - 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, - 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55}; - - se_aes_key_set(8, bis_key[0] + 0x00, 0x10); - se_aes_key_set(9, bis_key[0] + 0x10, 0x10); - - u32 buf_size = 0x4000; - u8 *buffer = (u8 *)malloc(buf_size); - - u8 keypair[0x230] = {0}; - - emummc_storage_read(&storage, 0x4400 / NX_EMMC_BLOCKSIZE, 0x4000 / NX_EMMC_BLOCKSIZE, buffer); - - se_aes_xts_crypt(9, 8, 0, 0, buffer, buffer, 0x4000, 1); - - se_aes_key_set(8, bis_key[2] + 0x00, 0x10); - se_aes_key_set(9, bis_key[2] + 0x10, 0x10); - - if (*(u32 *)buffer != 0x304C4143) { - EPRINTF("CAL0 magic not found. Check BIS key 0."); - free(buffer); - goto dismount; - } - - se_aes_key_set(2, eticket_rsa_kek, 0x10); - se_aes_crypt_ctr(2, keypair, 0x230, buffer + 0x38a0, 0x230, buffer + 0x3890); - - u8 *D = keypair, *N = keypair + 0x100, *E = keypair + 0x200; - - // Check public exponent is 0x10001 big endian - if (E[0] != 0 || E[1] != 1 || E[2] != 0 || E[3] != 1) { - EPRINTF("Invalid public exponent."); - free(buffer); - goto dismount; - } - - if (!_test_key_pair(E, D, N)) { - EPRINTF("Invalid keypair. Check eticket_rsa_kek."); - free(buffer); - goto dismount; - } - - se_rsa_key_set(0, N, 0x100, D, 0x100); - - u32 br = buf_size; - u32 file_tkey_count = 0; - u64 total_br = 0; - rights_ids = (u8 *)malloc(0x40000); - titlekeys = (u8 *)malloc(0x40000); - save_ctx = calloc(1, sizeof(save_ctx_t)); - u8 M[0x100]; - if (f_open(&fp, "emmc:/save/80000000000000E1", FA_READ | FA_OPEN_EXISTING)) { - EPRINTF("Unable to open ES save 1. Skipping."); - free(buffer); - goto dismount; - } - - u32 pct = 0, last_pct = 0; - tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500); - - save_ctx->file = &fp; - save_ctx->tool_ctx.action = 0; - memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); - save_process(save_ctx); - - char ticket_bin_path[SAVE_FS_LIST_MAX_NAME_LENGTH] = "/ticket.bin"; - char ticket_list_bin_path[SAVE_FS_LIST_MAX_NAME_LENGTH] = "/ticket_list.bin"; - allocation_table_storage_ctx_t fat_storage; - save_fs_list_entry_t entry = {0, "", {0}, 0}; - if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_list_bin_path, &entry)) { - EPRINTF("Unable to locate ticket_list.bin in e1."); - goto dismount; - } - save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); - while (br == buf_size && total_br < entry.value.save_file_info.length) { - br = save_allocation_table_storage_read(&fat_storage, buffer, total_br, buf_size); - if (buffer[0] == 0) break; - total_br += br; - minerva_periodic_training(); - for (u32 j = 0; j < buf_size; j += 0x20) { - if (buffer[j] == 0xff && buffer[j+1] == 0xff && buffer[j+2] == 0xff && buffer[j+3] == 0xff) break; - file_tkey_count++; - } - } - if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_bin_path, &entry)) { - EPRINTF("Unable to locate ticket.bin in e1."); - goto dismount; - } - save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); - total_br = 0; - while (br == buf_size && total_br < entry.value.save_file_info.length) { - br = save_allocation_table_storage_read(&fat_storage, buffer, total_br, buf_size); - if (buffer[0] == 0) break; - total_br += br; - for (u32 j = 0; j < buf_size; j += 0x400) { - pct = _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); - } - minerva_periodic_training(); - if (buffer[j] == 4 && buffer[j+1] == 0 && buffer[j+2] == 1 && buffer[j+3] == 0) { - memcpy(rights_ids + 0x10 * _titlekey_count, buffer + j + 0x2a0, 0x10); - memcpy(titlekeys + 0x10 * _titlekey_count, buffer + j + 0x180, 0x10); - _titlekey_count++; - } else { - break; - } - } - } - tui_pbar(save_x, save_y, 100, COLOR_GREEN, 0xFF155500); - f_close(&fp); - save_free_contexts(save_ctx); - memset(save_ctx, 0, sizeof(save_ctx_t)); - memset(&fat_storage, 0, sizeof(allocation_table_storage_ctx_t)); - - gfx_con_setpos(0, save_y); - TPRINTFARGS("\n%kCommon... ", colors[(color_idx++) % 6]); - save_x = gfx_con.x + 16 * 17; - save_y = gfx_con.y; - gfx_printf("\n%kPersonalized... ", colors[color_idx % 6]); - - u32 common_titlekey_count = _titlekey_count; - if (f_open(&fp, "emmc:/save/80000000000000E2", FA_READ | FA_OPEN_EXISTING)) { - EPRINTF("Unable to open ES save 2. Skipping."); - free(buffer); - goto dismount; - } - - save_ctx->file = &fp; - save_ctx->tool_ctx.action = 0; - memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); - save_process(save_ctx); - - if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_list_bin_path, &entry)) { - EPRINTF("Unable to locate ticket_list.bin in e2."); - goto dismount; - } - save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); - - total_br = 0; - file_tkey_count = 0; - while (br == buf_size && total_br < entry.value.save_file_info.length) { - br = save_allocation_table_storage_read(&fat_storage, buffer, total_br, buf_size); - if (buffer[0] == 0) break; - total_br += br; - minerva_periodic_training(); - for (u32 j = 0; j < buf_size; j += 0x20) { - if (buffer[j] == 0xff && buffer[j+1] == 0xff && buffer[j+2] == 0xff && buffer[j+3] == 0xff) break; - file_tkey_count++; - } - } - if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_bin_path, &entry)) { - EPRINTF("Unable to locate ticket.bin in e2."); - goto dismount; - } - - save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); - - total_br = 0; - pct = 0; - last_pct = 0; - while (br == buf_size && total_br < entry.value.save_file_info.length) { - br = save_allocation_table_storage_read(&fat_storage, buffer, total_br, buf_size); - if (buffer[0] == 0) break; - total_br += br; - for (u32 j = 0; j < buf_size; j += 0x400) { - pct = (_titlekey_count - common_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); - } - minerva_periodic_training(); - if (buffer[j] == 4 && buffer[j+1] == 0 && buffer[j+2] == 1 && buffer[j+3] == 0) { - memcpy(rights_ids + 0x10 * _titlekey_count, buffer + j + 0x2a0, 0x10); - - u8 *titlekey_block = buffer + j + 0x180; - se_rsa_exp_mod(0, M, 0x100, titlekey_block, 0x100); - u8 *salt = M + 1; - u8 *db = M + 0x21; - _mgf1_xor(salt, 0x20, db, 0xdf); - _mgf1_xor(db, 0xdf, salt, 0x20); - if (memcmp(db, null_hash, 0x20)) - continue; - memcpy(titlekeys + 0x10 * _titlekey_count, db + 0xcf, 0x10); - _titlekey_count++; - } else { - break; - } - } - } - tui_pbar(save_x, save_y, 100, COLOR_GREEN, 0xFF155500); - free(buffer); - f_close(&fp); - - gfx_con_setpos(0, save_y); - TPRINTFARGS("\n%kPersonalized... ", colors[(color_idx++) % 6]); - gfx_printf("\n%k Found %d titlekeys.\n", colors[(color_idx++) % 6], _titlekey_count); - -dismount:; - if (save_ctx) { - save_free_contexts(save_ctx); - free(save_ctx); - } - f_mount(NULL, "emmc:", 1); - clear_sector_cache = true; - nx_emmc_gpt_free(&gpt); - -key_output: ; - char *text_buffer = NULL; - if (!sd_mount()) { - EPRINTF("Unable to mount SD."); - goto free_buffers; - } - u32 text_buffer_size = _titlekey_count * 68 < 0x3000 ? 0x3000 : _titlekey_count * 68 + 1; - text_buffer = (char *)calloc(1, text_buffer_size); - - SAVE_KEY("aes_kek_generation_source", aes_kek_generation_source, 0x10); - SAVE_KEY("aes_key_generation_source", aes_key_generation_source, 0x10); - SAVE_KEY("bis_kek_source", bis_kek_source, 0x10); - SAVE_KEY_FAMILY("bis_key", bis_key, 0, 4, 0x20); - SAVE_KEY_FAMILY("bis_key_source", bis_key_source, 0, 3, 0x20); - SAVE_KEY("device_key", device_key, 0x10); - SAVE_KEY("eticket_rsa_kek", eticket_rsa_kek, 0x10); - SAVE_KEY("eticket_rsa_kek_source", es_keys[0], 0x10); - SAVE_KEY("eticket_rsa_kekek_source", es_keys[1], 0x10); - SAVE_KEY("header_kek_source", fs_keys[0], 0x10); - SAVE_KEY("header_key", header_key, 0x20); - SAVE_KEY("header_key_source", fs_keys[1], 0x20); - SAVE_KEY_FAMILY("key_area_key_application", key_area_key[0], 0, MAX_KEY, 0x10); - SAVE_KEY("key_area_key_application_source", fs_keys[2], 0x10); - SAVE_KEY_FAMILY("key_area_key_ocean", key_area_key[1], 0, MAX_KEY, 0x10); - SAVE_KEY("key_area_key_ocean_source", fs_keys[3], 0x10); - SAVE_KEY_FAMILY("key_area_key_system", key_area_key[2], 0, MAX_KEY, 0x10); - SAVE_KEY("key_area_key_system_source", fs_keys[4], 0x10); - SAVE_KEY_FAMILY("keyblob", keyblob, 0, 6, 0x90); - SAVE_KEY_FAMILY("keyblob_key", keyblob_key, 0, 6, 0x10); - SAVE_KEY_FAMILY("keyblob_key_source", keyblob_key_source, 0, 6, 0x10); - SAVE_KEY_FAMILY("keyblob_mac_key", keyblob_mac_key, 0, 6, 0x10); - SAVE_KEY("keyblob_mac_key_source", keyblob_mac_key_source, 0x10); - SAVE_KEY_FAMILY("master_kek", master_kek, 0, MAX_KEY, 0x10); - SAVE_KEY_FAMILY("master_kek_source", master_kek_sources, KB_FIRMWARE_VERSION_620, sizeof(master_kek_sources) / 0x10, 0x10); - SAVE_KEY_FAMILY("master_key", master_key, 0, MAX_KEY, 0x10); - SAVE_KEY("master_key_source", master_key_source, 0x10); - SAVE_KEY_FAMILY("package1_key", package1_key, 0, 6, 0x10); - SAVE_KEY_FAMILY("package2_key", package2_key, 0, MAX_KEY, 0x10); - SAVE_KEY("package2_key_source", package2_key_source, 0x10); - SAVE_KEY("per_console_key_source", per_console_key_source, 0x10); - SAVE_KEY("retail_specific_aes_key_source", retail_specific_aes_key_source, 0x10); - for (u32 i = 0; i < 0x10; i++) - temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; - SAVE_KEY("rsa_oaep_kek_generation_source", temp_key, 0x10); - for (u32 i = 0; i < 0x10; i++) - temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; - SAVE_KEY("rsa_private_kek_generation_source", temp_key, 0x10); - SAVE_KEY("save_mac_kek_source", fs_keys[5], 0x10); - SAVE_KEY("save_mac_key", save_mac_key, 0x10); - SAVE_KEY("save_mac_key_source", fs_keys[6], 0x10); - SAVE_KEY("save_mac_sd_card_kek_source", fs_keys[7], 0x10); - SAVE_KEY("save_mac_sd_card_key_source", fs_keys[8], 0x10); - SAVE_KEY("sd_card_custom_storage_key_source", fs_keys[9], 0x20); - SAVE_KEY("sd_card_kek_source", fs_keys[10], 0x10); - SAVE_KEY("sd_card_nca_key_source", fs_keys[11], 0x20); - SAVE_KEY("sd_card_save_key_source", fs_keys[12], 0x20); - SAVE_KEY("sd_seed", sd_seed, 0x10); - SAVE_KEY("secure_boot_key", sbk, 0x10); - SAVE_KEY("ssl_rsa_kek", ssl_rsa_kek, 0x10); - SAVE_KEY("ssl_rsa_kek_source_x", es_keys[2], 0x10); - SAVE_KEY("ssl_rsa_kek_source_y", ssl_keys, 0x10); - SAVE_KEY_FAMILY("titlekek", titlekek, 0, MAX_KEY, 0x10); - SAVE_KEY("titlekek_source", titlekek_source, 0x10); - SAVE_KEY("tsec_key", tsec_keys, 0x10); - if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) - SAVE_KEY("tsec_root_key", tsec_keys + 0x10, 0x10); - - //gfx_con.fntsz = 8; gfx_puts(text_buffer); gfx_con.fntsz = 16; - - end_time = get_tmr_us(); - gfx_printf("\n%k Found %d keys.\n\n", colors[(color_idx++) % 6], _key_count); - gfx_printf("%kLockpick totally done in %d us\n\n", colors[(color_idx++) % 6], end_time - begin_time); - gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], MAX_KEY - 1); - - f_mkdir("sd:/switch"); - char keyfile_path[30] = "sd:/switch/"; - if (!(fuse_read_odm(4) & 3)) - sprintf(&keyfile_path[11], "prod.keys"); - else - sprintf(&keyfile_path[11], "dev.keys"); - 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); - } else - EPRINTF("Unable to save keys to SD."); - - if (_titlekey_count == 0) - goto free_buffers; - memset(text_buffer, 0, text_buffer_size); - for (u32 i = 0; i < _titlekey_count; i++) { - for (u32 j = 0; j < 0x10; j++) - sprintf(&text_buffer[i * 68 + j * 2], "%02x", rights_ids[i * 0x10 + j]); - sprintf(&text_buffer[i * 68 + 0x20], " = "); - for (u32 j = 0; j < 0x10; j++) - sprintf(&text_buffer[i * 68 + 0x23 + j * 2], "%02x", titlekeys[i * 0x10 + j]); - sprintf(&text_buffer[i * 68 + 0x43], "\n"); - } - sprintf(&keyfile_path[11], "title.keys"); - 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); - } else - EPRINTF("Unable to save titlekeys to SD."); - -free_buffers: - free(rights_ids); - free(titlekeys); - free(text_buffer); - -out_wait: - h_cfg.emummc_force_disable = emummc_load_cfg(); - emummc_storage_end(&storage); - gfx_printf("\n%kPress any key to return to the main menu.", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]); - btn_wait(); -} - -static void _save_key(const char *name, const void *data, u32 len, char *outbuf) { - if (!_key_exists(data)) - return; - u32 pos = strlen(outbuf); - pos += sprintf(&outbuf[pos], "%s = ", name); - for (u32 i = 0; i < len; i++) - pos += sprintf(&outbuf[pos], "%02x", *(u8*)(data + i)); - sprintf(&outbuf[pos], "\n"); - _key_count++; -} - -static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf) { - char temp_name[0x40] = {0}; - for (u32 i = 0; i < num_keys; i++) { - sprintf(temp_name, "%s_%02x", name, i + start_key); - _save_key(temp_name, data + i * len, len, outbuf); - } -} - -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; - - se_aes_key_set(ks, master_key, 0x10); - 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); -} - -static inline u32 _read_le_u32(const void *buffer, u32 offset) { - return (*(u8*)(buffer + offset + 0) ) | - (*(u8*)(buffer + offset + 1) << 0x08) | - (*(u8*)(buffer + offset + 2) << 0x10) | - (*(u8*)(buffer + offset + 3) << 0x18); -} - -static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len, const u8 key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10]) { - u32 read_bytes = 0, crypt_offset, read_size, num_files, string_table_size, rodata_offset; - - u8 *temp_file = (u8*)malloc(0x400), - ctr[0x10] = {0}; - if (f_lseek(fp, 0x200) || f_read(fp, temp_file, 0x400, &read_bytes) || read_bytes != 0x400) { - free(temp_file); - return NULL; - } - se_aes_xts_crypt(hk_ks1, hk_ks2, 0, 1, temp_file, temp_file, 0x200, 2); - // both 1.x and 2.x use master_key_00 - temp_file[0x20] -= temp_file[0x20] ? 1 : 0; - // decrypt key area and load decrypted key area key - se_aes_key_set(7, key_area_key[temp_file[7]][temp_file[0x20]], 0x10); - se_aes_crypt_block_ecb(7, 0, temp_file + 0x120, temp_file + 0x120); - se_aes_key_set(2, temp_file + 0x120, 0x10); - for (u32 i = 0; i < 8; i++) - ctr[i] = temp_file[0x347 - i]; - crypt_offset = _read_le_u32(temp_file, 0x40) * 0x200 + _read_le_u32(temp_file, 0x240); - read_size = 0x10; - _nca_fread_ctr(2, fp, temp_file, crypt_offset, read_size, ctr); - num_files = _read_le_u32(temp_file, 4); - string_table_size = _read_le_u32(temp_file, 8); - if (!memcmp(temp_file + 0x10 + num_files * 0x18, "main.npdm", 9)) - crypt_offset += _read_le_u32(temp_file, 0x18); - crypt_offset += 0x10 + num_files * 0x18 + string_table_size; - read_size = 0x40; - _nca_fread_ctr(2, fp, temp_file, crypt_offset, read_size, ctr); - rodata_offset = _read_le_u32(temp_file, 0x20); - - void *buf = malloc(len); - _nca_fread_ctr(2, fp, buf, crypt_offset + rodata_offset + key_offset, len, ctr); - free(temp_file); - - return buf; -} - -static u32 _nca_fread_ctr(u32 ks, FIL *fp, void *buffer, u32 offset, u32 len, u8 *ctr) { - u32 br; - if (f_lseek(fp, offset) || f_read(fp, buffer, len, &br) || br != len) - return 0; - _update_ctr(ctr, offset); - - if (offset % 0x10) { - u8 *temp = (u8*)malloc(ALIGN(br + offset % 0x10, 0x10)); - memcpy(temp + offset % 0x10, buffer, br); - se_aes_crypt_ctr(ks, temp, ALIGN(br + offset % 0x10, 0x10), temp, ALIGN(br + offset % 0x10, 0x10), ctr); - memcpy(buffer, temp + offset % 0x10, br); - free(temp); - return br; - } - se_aes_crypt_ctr(ks, buffer, br, buffer, br, ctr); - return br; -} - -static void _update_ctr(u8 *ctr, u32 ofs) { - ofs >>= 4; - for (u32 i = 0; i < 4; i++, ofs >>= 8) - ctr[0x10-i-1] = (u8)(ofs & 0xff); -} - -static bool _test_key_pair(const void *E, const void *D, const void *N) { - u8 X[0x100] = {0}, Y[0x100] = {0}, Z[0x100] = {0}; - - // 0xCAFEBABE - X[0xfc] = 0xca; X[0xfd] = 0xfe; X[0xfe] = 0xba; X[0xff] = 0xbe; - se_rsa_key_set(0, N, 0x100, D, 0x100); - se_rsa_exp_mod(0, Y, 0x100, X, 0x100); - se_rsa_key_set(0, N, 0x100, E, 4); - se_rsa_exp_mod(0, Z, 0x100, Y, 0x100); - - return !memcmp(X, Z, 0x100); -} - -// _mgf1_xor() was derived from Atmosphère's calculate_mgf1_and_xor -static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size) { - u8 cur_hash[0x20]; - u8 hash_buf[0xe4]; - - u32 hash_buf_size = seed_size + 4; - memcpy(hash_buf, seed, seed_size); - u32 round_num = 0; - - u8 *p_out = (u8 *)masked; - - while (masked_size) { - u32 cur_size = masked_size > 0x20 ? 0x20 : masked_size; - - for (u32 i = 0; i < 4; i++) - hash_buf[seed_size + 3 - i] = (round_num >> (8 * i)) & 0xff; - round_num++; - - se_calc_sha256(cur_hash, hash_buf, hash_buf_size); - - for (unsigned int i = 0; i < cur_size; i++) { - *p_out ^= cur_hash[i]; - p_out++; - } - - masked_size -= cur_size; - } -} diff --git a/source/keys/keys.h b/source/keys/keys.h deleted file mode 100644 index 9be86dd..0000000 --- a/source/keys/keys.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2019 shchmue - * - * 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 . - */ - -#ifndef _KEYS_H_ -#define _KEYS_H_ - -void dump_keys(); - -#endif diff --git a/source/keys/save.c b/source/keys/save.c deleted file mode 100644 index bcac3b4..0000000 --- a/source/keys/save.c +++ /dev/null @@ -1,821 +0,0 @@ -#include -#include "save.h" - -#include "../gfx/gfx.h" -#include "../mem/heap.h" -#include "../sec/se.h" -#include "../utils/types.h" -#include "../utils/util.h" - -#define REMAP_ENTRY_LENGTH 0x20 - -static inline void save_bitmap_set_bit(void *buffer, size_t bit_offset) { - *((uint8_t *)buffer + (bit_offset >> 3)) |= 1 << (bit_offset & 7); -} - -static inline void save_bitmap_clear_bit(void *buffer, size_t bit_offset) { - *((uint8_t *)buffer + (bit_offset >> 3)) &= ~(uint8_t)(1 << (bit_offset & 7)); -} - -static inline uint8_t save_bitmap_check_bit(const void *buffer, size_t bit_offset) { - return *((uint8_t *)buffer + (bit_offset >> 3)) & (1 << (bit_offset & 7)); -} - -void save_duplex_storage_init(duplex_storage_ctx_t *ctx, duplex_fs_layer_info_t *layer, void *bitmap, uint64_t bitmap_size) { - ctx->data_a = layer->data_a; - ctx->data_b = layer->data_b; - ctx->bitmap_storage = (uint8_t *)bitmap; - ctx->block_size = 1 << layer->info.block_size_power; - - ctx->bitmap.data = ctx->bitmap_storage; - ctx->bitmap.bitmap = malloc(bitmap_size >> 3); - - uint32_t bits_remaining = bitmap_size; - uint32_t bitmap_pos = 0; - uint32_t *buffer_pos = (uint32_t *)bitmap; - while (bits_remaining) { - uint32_t bits_to_read = bits_remaining < 32 ? bits_remaining : 32; - uint32_t val = *buffer_pos; - for (uint32_t i = 0; i < bits_to_read; i++) { - if (val & 0x80000000) - save_bitmap_set_bit(ctx->bitmap.bitmap, bitmap_pos); - else - save_bitmap_clear_bit(ctx->bitmap.bitmap, bitmap_pos); - bitmap_pos++; - bits_remaining--; - val <<= 1; - } - buffer_pos++; - } -} - -uint32_t save_duplex_storage_read(duplex_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count) { - uint64_t in_pos = offset; - uint32_t out_pos = 0; - uint32_t remaining = count; - - while (remaining) { - uint32_t block_num = (uint32_t)(in_pos / ctx->block_size); - uint32_t block_pos = (uint32_t)(in_pos % ctx->block_size); - uint32_t bytes_to_read = ctx->block_size - block_pos < remaining ? ctx->block_size - block_pos : remaining; - - uint8_t *data = save_bitmap_check_bit(ctx->bitmap.bitmap, block_num) ? ctx->data_b : ctx->data_a; - memcpy((uint8_t *)buffer + out_pos, data + in_pos, bytes_to_read); - - out_pos += bytes_to_read; - in_pos += bytes_to_read; - remaining -= bytes_to_read; - } - return out_pos; -} - -remap_segment_ctx_t *save_remap_init_segments(remap_header_t *header, remap_entry_ctx_t *map_entries, uint32_t num_map_entries) { - remap_segment_ctx_t *segments = malloc(sizeof(remap_segment_ctx_t) * header->map_segment_count); - unsigned int entry_idx = 0; - - for (unsigned int i = 0; i < header->map_segment_count; i++) { - remap_segment_ctx_t *seg = &segments[i]; - seg->entries = malloc(sizeof(remap_entry_ctx_t)); - memcpy(seg->entries, &map_entries[entry_idx], sizeof(remap_entry_ctx_t)); - seg->offset = map_entries[entry_idx].virtual_offset; - map_entries[entry_idx].segment = seg; - seg->entry_count = 1; - entry_idx++; - - while (entry_idx < num_map_entries && map_entries[entry_idx - 1].virtual_offset_end == map_entries[entry_idx].virtual_offset) { - map_entries[entry_idx].segment = seg; - map_entries[entry_idx - 1].next = &map_entries[entry_idx]; - seg->entries = malloc(sizeof(remap_entry_ctx_t)); - memcpy(seg->entries, &map_entries[entry_idx], sizeof(remap_entry_ctx_t)); - seg->entry_count++; - entry_idx++; - } - seg->length = seg->entries[seg->entry_count - 1].virtual_offset_end - seg->entries[0].virtual_offset; - } - return segments; -} - -remap_entry_ctx_t *save_remap_get_map_entry(remap_storage_ctx_t *ctx, uint64_t offset) { - uint32_t segment_idx = (uint32_t)(offset >> (64 - ctx->header->segment_bits)); - if (segment_idx < ctx->header->map_segment_count) { - for (unsigned int i = 0; i < ctx->segments[segment_idx].entry_count; i++) - if (ctx->segments[segment_idx].entries[i].virtual_offset_end > offset) - return &ctx->segments[segment_idx].entries[i]; - } - return NULL; -} - -uint32_t save_remap_read(remap_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count) { - remap_entry_ctx_t *entry = save_remap_get_map_entry(ctx, offset); - uint64_t in_pos = offset; - uint32_t out_pos = 0; - uint32_t remaining = count; - - while (remaining) { - uint64_t entry_pos = in_pos - entry->virtual_offset; - uint32_t bytes_to_read = entry->virtual_offset_end - in_pos < remaining ? (uint32_t)(entry->virtual_offset_end - in_pos) : remaining; - - switch (ctx->type) { - case STORAGE_BYTES: - f_lseek(ctx->file, ctx->base_storage_offset + entry->physical_offset + entry_pos); - f_read(ctx->file, (uint8_t *)buffer + out_pos, bytes_to_read, NULL); - break; - case STORAGE_DUPLEX: - save_duplex_storage_read(ctx->duplex, (uint8_t *)buffer + out_pos, ctx->base_storage_offset + entry->physical_offset + entry_pos, bytes_to_read); - break; - default: - break; - } - - out_pos += bytes_to_read; - in_pos += bytes_to_read; - remaining -= bytes_to_read; - - if (in_pos >= entry->virtual_offset_end) - entry = entry->next; - } - return out_pos; -} - -uint32_t save_journal_storage_read(journal_storage_ctx_t *ctx, remap_storage_ctx_t *remap, void *buffer, uint64_t offset, size_t count) { - uint64_t in_pos = offset; - uint32_t out_pos = 0; - uint32_t remaining = count; - - while (remaining) { - uint32_t block_num = (uint32_t)(in_pos / ctx->block_size); - uint32_t block_pos = (uint32_t)(in_pos % ctx->block_size); - uint64_t physical_offset = ctx->map.entries[block_num].physical_index * ctx->block_size + block_pos; - uint32_t bytes_to_read = ctx->block_size - block_pos < remaining ? ctx->block_size - block_pos : remaining; - - save_remap_read(remap, (uint8_t *)buffer + out_pos, ctx->journal_data_offset + physical_offset, bytes_to_read); - - out_pos += bytes_to_read; - in_pos += bytes_to_read; - remaining -= bytes_to_read; - } - return out_pos; -} - -void save_ivfc_storage_init(hierarchical_integrity_verification_storage_ctx_t *ctx, uint64_t master_hash_offset, ivfc_save_hdr_t *ivfc) { - ivfc_level_save_ctx_t *levels = ctx->levels; - levels[0].type = STORAGE_BYTES; - levels[0].hash_offset = master_hash_offset; - for (unsigned int i = 1; i < 4; i++) { - ivfc_level_hdr_t *level = &ivfc->level_headers[i - 1]; - levels[i].type = STORAGE_REMAP; - levels[i].data_offset = level->logical_offset; - levels[i].data_size = level->hash_data_size; - } - if (ivfc->num_levels == 5) { - ivfc_level_hdr_t *data_level = &ivfc->level_headers[ivfc->num_levels - 2]; - levels[ivfc->num_levels - 1].type = STORAGE_JOURNAL; - levels[ivfc->num_levels - 1].data_offset = data_level->logical_offset; - levels[ivfc->num_levels - 1].data_size = data_level->hash_data_size; - } - - struct salt_source_t { - char string[50]; - uint32_t length; - }; - - static struct salt_source_t salt_sources[6] = { - {"HierarchicalIntegrityVerificationStorage::Master", 48}, - {"HierarchicalIntegrityVerificationStorage::L1", 44}, - {"HierarchicalIntegrityVerificationStorage::L2", 44}, - {"HierarchicalIntegrityVerificationStorage::L3", 44}, - {"HierarchicalIntegrityVerificationStorage::L4", 44}, - {"HierarchicalIntegrityVerificationStorage::L5", 44} - }; - integrity_verification_info_ctx_t init_info[ivfc->num_levels]; - - init_info[0].data = &levels[0]; - init_info[0].block_size = 0; - for (unsigned int i = 1; i < ivfc->num_levels; i++) { - init_info[i].data = &levels[i]; - init_info[i].block_size = 1 << ivfc->level_headers[i - 1].block_size; - se_calc_hmac_sha256(init_info[i].salt, ivfc->salt_source, 0x20, salt_sources[i - 1].string, salt_sources[i - 1].length); - } - - ctx->integrity_storages[0].next_level = NULL; - ctx->level_validities = malloc(sizeof(validity_t *) * (ivfc->num_levels - 1)); - for (unsigned int i = 1; i < ivfc->num_levels; i++) { - integrity_verification_storage_ctx_t *level_data = &ctx->integrity_storages[i - 1]; - level_data->hash_storage = &levels[i - 1]; - level_data->base_storage = &levels[i]; - level_data->sector_size = init_info[i].block_size; - level_data->_length = init_info[i].data->data_size; - level_data->sector_count = (level_data->_length + level_data->sector_size - 1) / level_data->sector_size; - memcpy(level_data->salt, init_info[i].salt, 0x20); - level_data->block_validities = calloc(1, sizeof(validity_t) * level_data->sector_count); - ctx->level_validities[i - 1] = level_data->block_validities; - if (i > 1) { - level_data->next_level = &ctx->integrity_storages[i - 2]; - } - } - ctx->data_level = &levels[ivfc->num_levels - 1]; - ctx->_length = ctx->integrity_storages[ivfc->num_levels - 2]._length; -} - -size_t save_ivfc_level_fread(ivfc_level_save_ctx_t *ctx, void *buffer, uint64_t offset, size_t count) { - switch (ctx->type) { - case STORAGE_BYTES: - f_lseek(ctx->save_ctx->file, ctx->hash_offset + offset); - UINT br = 0; - f_read(ctx->save_ctx->file, buffer, count, &br); - return br; - case STORAGE_REMAP: - save_remap_read(&ctx->save_ctx->meta_remap_storage, buffer, ctx->data_offset + offset, count); - return count; - case STORAGE_JOURNAL: - save_journal_storage_read(&ctx->save_ctx->journal_storage, &ctx->save_ctx->data_remap_storage, buffer, ctx->data_offset + offset, count); - return count; - default: - return 0; - } -} - -void save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count, uint32_t verify) { - if (count > ctx->sector_size) { - EPRINTF("IVFC read exceeds sector size!\n"); - } - - uint64_t block_index = offset / ctx->sector_size; - - if (ctx->block_validities[block_index] == VALIDITY_INVALID && verify) { - EPRINTFARGS("Hash error from previous check\n found at offset %x count %x!\n", (u32)offset, count); - } - - uint8_t hash_buffer[0x20] = {0}; - uint8_t zeroes[0x20] = {0}; - uint64_t hash_pos = block_index * 0x20; - if (ctx->next_level) { - save_ivfc_storage_read(ctx->next_level, hash_buffer, hash_pos, 0x20, verify); - } else { - save_ivfc_level_fread(ctx->hash_storage, hash_buffer, hash_pos, 0x20); - } - - if (!memcmp(hash_buffer, zeroes, 0x20)) { - memset(buffer, 0, count); - ctx->block_validities[block_index] = VALIDITY_VALID; - return; - } - - save_ivfc_level_fread(ctx->base_storage, buffer, offset, count); - - if (!(verify && ctx->block_validities[block_index] == VALIDITY_UNCHECKED)) { - return; - } - - uint8_t hash[0x20] = {0}; - uint8_t *data_buffer = calloc(1, ctx->sector_size + 0x20); - memcpy(data_buffer, ctx->salt, 0x20); - memcpy(data_buffer + 0x20, buffer, count); - - se_calc_sha256(hash, data_buffer, ctx->sector_size + 0x20); - hash[0x1F] |= 0x80; - - free(data_buffer); - if (memcmp(hash_buffer, hash, 0x20)) { - ctx->block_validities[block_index] = VALIDITY_INVALID; - } else { - ctx->block_validities[block_index] = VALIDITY_VALID; - } - - if (ctx->block_validities[block_index] == VALIDITY_INVALID && verify) { - EPRINTFARGS("Hash error from current check\n found at offset %x count %x!\n", (u32)offset, count); - } -} - -uint32_t save_allocation_table_read_entry_with_length(allocation_table_ctx_t *ctx, allocation_table_entry_t *entry) { - uint32_t length = 1; - uint32_t entry_index = allocation_table_block_to_entry_index(entry->next); - - allocation_table_entry_t *entries = (allocation_table_entry_t *)((uint8_t *)(ctx->base_storage) + entry_index * SAVE_FAT_ENTRY_SIZE); - if ((entries[0].next & 0x80000000) == 0) { - if (entries[0].prev & 0x80000000 && entries[0].prev != 0x80000000) { - EPRINTF("Invalid range entry in allocation table!\n"); - } - } else { - length = entries[1].next - entry_index + 1; - } - - if (allocation_table_is_list_end(&entries[0])) { - entry->next = 0xFFFFFFFF; - } else { - entry->next = allocation_table_entry_index_to_block(allocation_table_get_next(&entries[0])); - } - - if (allocation_table_is_list_start(&entries[0])) { - entry->prev = 0xFFFFFFFF; - } else { - entry->prev = allocation_table_entry_index_to_block(allocation_table_get_prev(&entries[0])); - } - - return length; -} - -uint32_t save_allocation_table_get_list_length(allocation_table_ctx_t *ctx, uint32_t block_index) { - allocation_table_entry_t entry; - entry.next = block_index; - uint32_t total_length = 0; - uint32_t table_size = ctx->header->allocation_table_block_count; - uint32_t nodes_iterated = 0; - - while (entry.next != 0xFFFFFFFF) { - total_length += save_allocation_table_read_entry_with_length(ctx, &entry); - nodes_iterated++; - if (nodes_iterated > table_size) { - EPRINTF("Cycle detected in allocation table!\n"); - return 0; - } - } - return total_length; -} - -uint64_t save_allocation_table_get_free_space_size(save_filesystem_ctx_t *ctx) { - uint32_t free_list_start = save_allocation_table_get_free_list_block_index(&ctx->allocation_table); - - if (free_list_start == 0xFFFFFFFF) return 0; - - return ctx->header->block_size * save_allocation_table_get_list_length(&ctx->allocation_table, free_list_start); -} - -void save_allocation_table_iterator_begin(allocation_table_iterator_ctx_t *ctx, allocation_table_ctx_t *table, uint32_t initial_block) { - ctx->fat = table; - ctx->physical_block = initial_block; - ctx->virtual_block = 0; - - allocation_table_entry_t entry; - entry.next = initial_block; - ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, &entry); - ctx->next_block = entry.next; - ctx->prev_block = entry.prev; - - if (ctx->prev_block != 0xFFFFFFFF) { - EPRINTFARGS("Attempted to start FAT iteration from\n invalid block %x!\n", initial_block); - } -} - -int save_allocation_table_iterator_move_next(allocation_table_iterator_ctx_t *ctx) { - if (ctx->next_block == 0xFFFFFFFF) return 0; - - ctx->virtual_block += ctx->current_segment_size; - ctx->physical_block = ctx->next_block; - - allocation_table_entry_t entry; - entry.next = ctx->next_block; - ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, &entry); - ctx->next_block = entry.next; - ctx->prev_block = entry.prev; - - return 1; -} - -int save_allocation_table_iterator_move_prev(allocation_table_iterator_ctx_t *ctx) { - if (ctx->prev_block == 0xFFFFFFFF) return 0; - - ctx->physical_block = ctx->prev_block; - - allocation_table_entry_t entry; - entry.next = ctx->prev_block; - ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, &entry); - ctx->next_block = entry.next; - ctx->prev_block = entry.prev; - - ctx->virtual_block -= ctx->current_segment_size; - - return 1; -} - -int save_allocation_table_iterator_seek(allocation_table_iterator_ctx_t *ctx, uint32_t block) { - while (1) { - if (block < ctx->virtual_block) { - if (!save_allocation_table_iterator_move_prev(ctx)) return 0; - } else if (block >= ctx->virtual_block + ctx->current_segment_size) { - if (!save_allocation_table_iterator_move_next(ctx)) return 0; - } else { - return 1; - } - - } -} - -uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count) { - allocation_table_iterator_ctx_t iterator; - save_allocation_table_iterator_begin(&iterator, ctx->fat, ctx->initial_block); - uint64_t in_pos = offset; - uint32_t out_pos = 0; - uint32_t remaining = count; - - while (remaining) { - uint32_t block_num = (uint32_t)(in_pos / ctx->block_size); - save_allocation_table_iterator_seek(&iterator, block_num); - - uint32_t segment_pos = (uint32_t)(in_pos - (uint64_t)iterator.virtual_block * ctx->block_size); - uint64_t physical_offset = iterator.physical_block * ctx->block_size + segment_pos; - - uint32_t remaining_in_segment = iterator.current_segment_size * ctx->block_size - segment_pos; - uint32_t bytes_to_read = remaining < remaining_in_segment ? remaining : remaining_in_segment; - - uint32_t sector_size = ctx->base_storage->integrity_storages[3].sector_size; - uint32_t chunk_remaining = bytes_to_read; - for (unsigned int i = 0; i < bytes_to_read; i += sector_size) { - uint32_t bytes_to_request = chunk_remaining < sector_size ? chunk_remaining : sector_size; - save_ivfc_storage_read(&ctx->base_storage->integrity_storages[3], (uint8_t *)buffer + out_pos + i, physical_offset + i, bytes_to_request, ctx->base_storage->data_level->save_ctx->tool_ctx.action & ACTION_VERIFY); - chunk_remaining -= bytes_to_request; - } - - out_pos += bytes_to_read; - in_pos += bytes_to_read; - remaining -= bytes_to_read; - } - return out_pos; -} - -uint32_t save_fs_list_get_capacity(save_filesystem_list_ctx_t *ctx) { - if (!ctx->capacity) - save_allocation_table_storage_read(&ctx->storage, &ctx->capacity, 4, 4); - return ctx->capacity; -} - -uint32_t save_fs_list_read_entry(save_filesystem_list_ctx_t *ctx, uint32_t index, save_fs_list_entry_t *entry) { - return save_allocation_table_storage_read(&ctx->storage, entry, index * SAVE_FS_LIST_ENTRY_SIZE, SAVE_FS_LIST_ENTRY_SIZE); -} - -int save_fs_list_get_value(save_filesystem_list_ctx_t *ctx, uint32_t index, save_fs_list_entry_t *value) { - if (index >= save_fs_list_get_capacity(ctx)) { - return 0; - } - save_fs_list_read_entry(ctx, index, value); - return 1; -} - -uint32_t save_fs_get_index_from_key(save_filesystem_list_ctx_t *ctx, save_entry_key_t *key, uint32_t *prev_index) { - save_fs_list_entry_t entry; - uint32_t capacity = save_fs_list_get_capacity(ctx); - save_fs_list_read_entry(ctx, ctx->used_list_head_index, &entry); - uint32_t prev; - if (!prev_index) { - prev_index = &prev; - } - *prev_index = ctx->used_list_head_index; - uint32_t index = entry.next; - while (index) { - if (index > capacity) { - EPRINTFARGS("Save entry index %d out of range!", index); - } - save_fs_list_read_entry(ctx, index, &entry); - if (entry.parent == key->parent && !strcmp(entry.name, key->name)) { - return index; - } - *prev_index = index; - index = entry.next; - } - *prev_index = 0xFFFFFFFF; - return 0xFFFFFFFF; -} - -int save_hierarchical_file_table_find_path_recursive(hierarchical_save_file_table_ctx_t *ctx, save_entry_key_t *key, char *path) { - key->parent = 0; - char *pos = strchr(path, '/'); - while (pos) { - memset(key->name, 0, SAVE_FS_LIST_MAX_NAME_LENGTH); - char *tmp = strchr(pos, '/'); - if (!tmp) { - memcpy(key->name, pos, strlen(pos)); - break; - } - memcpy(key->name, pos, tmp - pos); - key->parent = save_fs_get_index_from_key(&ctx->directory_table, key, NULL); - if (key->parent == 0xFFFFFFFF) - return 0; - pos = tmp + 1; - } - return 1; -} - -int save_hierarchical_file_table_find_next_file(hierarchical_save_file_table_ctx_t *ctx, save_find_position_t *position, save_file_info_t *info, char *name) { - if (position->next_file == 0) { - return 0; - } - save_fs_list_entry_t entry; - if(!save_fs_list_get_value(&ctx->file_table, position->next_file, &entry)) { - return 0; - } - position->next_file = entry.value.next_sibling; - memcpy(name, &entry.name, SAVE_FS_LIST_MAX_NAME_LENGTH); - memcpy(info, &entry.value.save_file_info, sizeof(save_file_info_t)); - return 1; -} - -int save_hierarchical_file_table_find_next_directory(hierarchical_save_file_table_ctx_t *ctx, save_find_position_t *position, char *name) { - if (position->next_directory == 0) { - return 0; - } - save_fs_list_entry_t entry; - if(!save_fs_list_get_value(&ctx->directory_table, position->next_directory, &entry)) { - return 0; - } - position->next_directory = entry.value.next_sibling; - memcpy(name, &entry.name, SAVE_FS_LIST_MAX_NAME_LENGTH); - return 1; -} - -int save_hierarchical_file_table_get_file_entry_by_path(hierarchical_save_file_table_ctx_t *ctx, char *path, save_fs_list_entry_t *entry) { - save_entry_key_t key; - if (!save_hierarchical_file_table_find_path_recursive(ctx, &key, path)) { - EPRINTF("Unable to locate file."); - return 0; - } - u32 index = save_fs_get_index_from_key(&ctx->file_table, &key, NULL); - if (index == 0xFFFFFFFF) { - EPRINTF("Unable to get table index for file."); - return 0; - } - if (!save_fs_list_get_value(&ctx->file_table, index, entry)) { - EPRINTF("Unable to get file entry from index."); - return 0; - } - return 1; -} - -void save_open_fat_storage(save_filesystem_ctx_t *ctx, allocation_table_storage_ctx_t *storage_ctx, uint32_t block_index) { - storage_ctx->base_storage = ctx->base_storage; - storage_ctx->fat = &ctx->allocation_table; - storage_ctx->block_size = (uint32_t)ctx->header->block_size; - storage_ctx->initial_block = block_index; - storage_ctx->_length = block_index == 0xFFFFFFFF ? 0 : save_allocation_table_get_list_length(storage_ctx->fat, block_index) * storage_ctx->block_size; -} - -void save_filesystem_init(save_filesystem_ctx_t *ctx, void *fat, save_fs_header_t *save_fs_header, fat_header_t *fat_header) { - ctx->allocation_table.base_storage = fat; - ctx->allocation_table.header = fat_header; - ctx->allocation_table.free_list_entry_index = 0; - ctx->header = save_fs_header; - - save_open_fat_storage(ctx, &ctx->file_table.directory_table.storage, fat_header->directory_table_block); - save_open_fat_storage(ctx, &ctx->file_table.file_table.storage, fat_header->file_table_block); - ctx->file_table.file_table.free_list_head_index = 0; - ctx->file_table.file_table.used_list_head_index = 1; - ctx->file_table.directory_table.free_list_head_index = 0; - ctx->file_table.directory_table.used_list_head_index = 1; -} - -validity_t save_ivfc_validate(hierarchical_integrity_verification_storage_ctx_t *ctx, ivfc_save_hdr_t *ivfc) { - validity_t result = VALIDITY_VALID; - for (unsigned int i = 0; i < ivfc->num_levels - 1 && result != VALIDITY_INVALID; i++) { - integrity_verification_storage_ctx_t *storage = &ctx->integrity_storages[i]; - - uint64_t block_size = storage->sector_size; - uint32_t block_count = (uint32_t)((storage->_length + block_size - 1) / block_size); - - uint8_t *buffer = malloc(block_size); - - for (unsigned int j = 0; j < block_count; j++) { - if (ctx->level_validities[ivfc->num_levels - 2][j] == VALIDITY_UNCHECKED) { - uint32_t to_read = storage->_length - block_size * j < block_size ? storage->_length - block_size * j : block_size; - save_ivfc_storage_read(storage, buffer, block_size * j, to_read, 1); - } - if (ctx->level_validities[ivfc->num_levels - 2][j] == VALIDITY_INVALID) { - result = VALIDITY_INVALID; - break; - } - } - free(buffer); - } - - return result; -} - -void save_ivfc_set_level_validities(hierarchical_integrity_verification_storage_ctx_t *ctx, ivfc_save_hdr_t *ivfc) { - for (unsigned int i = 0; i < ivfc->num_levels - 1; i++) { - validity_t level_validity = VALIDITY_VALID; - for (unsigned int j = 0; j < ctx->integrity_storages[i].sector_count; j++) { - if (ctx->level_validities[i][j] == VALIDITY_INVALID) { - level_validity = VALIDITY_INVALID; - break; - } - if (ctx->level_validities[i][j] == VALIDITY_UNCHECKED && level_validity != VALIDITY_INVALID) { - level_validity = VALIDITY_UNCHECKED; - } - } - ctx->levels[i].hash_validity = level_validity; - } -} - -validity_t save_filesystem_verify(save_ctx_t *ctx) { - validity_t journal_validity = save_ivfc_validate(&ctx->core_data_ivfc_storage, &ctx->header.data_ivfc_header); - save_ivfc_set_level_validities(&ctx->core_data_ivfc_storage, &ctx->header.data_ivfc_header); - - if (!ctx->fat_ivfc_storage.levels[0].save_ctx) return journal_validity; - - validity_t fat_validity = save_ivfc_validate(&ctx->fat_ivfc_storage, &ctx->header.fat_ivfc_header); - save_ivfc_set_level_validities(&ctx->fat_ivfc_storage, &ctx->header.fat_ivfc_header); - - if (journal_validity != VALIDITY_VALID) return journal_validity; - if (fat_validity != VALIDITY_VALID) return fat_validity; - - return journal_validity; -} - -void save_process(save_ctx_t *ctx) { - /* Try to parse Header A. */ - f_lseek(ctx->file, 0); - if (f_read(ctx->file, &ctx->header, sizeof(ctx->header), NULL)) { - EPRINTF("Failed to read save header!\n"); - } - - save_process_header(ctx); - - if (ctx->header_hash_validity == VALIDITY_INVALID) { - /* Try to parse Header B. */ - f_lseek(ctx->file, 0x4000); - if (f_read(ctx->file, &ctx->header, sizeof(ctx->header), NULL)) { - EPRINTF("Failed to read save header!\n"); - } - - save_process_header(ctx); - - if (ctx->header_hash_validity == VALIDITY_INVALID) { - EPRINTF("Error: Save header is invalid!\n"); - } - } - - unsigned char cmac[0x10]; - memset(cmac, 0, 0x10); - se_aes_key_set(3, ctx->save_mac_key, 0x10); - se_aes_cmac(3, cmac, 0x10, &ctx->header.layout, sizeof(ctx->header.layout)); - if (memcmp(cmac, &ctx->header.cmac, 0x10) == 0) { - ctx->header_cmac_validity = VALIDITY_VALID; - } else { - ctx->header_cmac_validity = VALIDITY_INVALID; - } - - /* Initialize remap storages. */ - ctx->data_remap_storage.type = STORAGE_BYTES; - ctx->data_remap_storage.base_storage_offset = ctx->header.layout.file_map_data_offset; - ctx->data_remap_storage.header = &ctx->header.main_remap_header; - ctx->data_remap_storage.map_entries = malloc(sizeof(remap_entry_ctx_t) * ctx->data_remap_storage.header->map_entry_count); - ctx->data_remap_storage.file = ctx->file; - f_lseek(ctx->file, ctx->header.layout.file_map_entry_offset); - for (unsigned int i = 0; i < ctx->data_remap_storage.header->map_entry_count; i++) { - f_read(ctx->file, &ctx->data_remap_storage.map_entries[i], 0x20, NULL); - ctx->data_remap_storage.map_entries[i].physical_offset_end = ctx->data_remap_storage.map_entries[i].physical_offset + ctx->data_remap_storage.map_entries[i].size; - ctx->data_remap_storage.map_entries[i].virtual_offset_end = ctx->data_remap_storage.map_entries[i].virtual_offset + ctx->data_remap_storage.map_entries[i].size; - } - - /* Initialize data remap storage. */ - ctx->data_remap_storage.segments = save_remap_init_segments(ctx->data_remap_storage.header, ctx->data_remap_storage.map_entries, ctx->data_remap_storage.header->map_entry_count); - - /* Initialize duplex storage. */ - ctx->duplex_layers[0].data_a = (uint8_t *)&ctx->header + ctx->header.layout.duplex_master_offset_a; - ctx->duplex_layers[0].data_b = (uint8_t *)&ctx->header + ctx->header.layout.duplex_master_offset_b; - memcpy(&ctx->duplex_layers[0].info, &ctx->header.duplex_header.layers[0], sizeof(duplex_info_t)); - - ctx->duplex_layers[1].data_a = malloc(ctx->header.layout.duplex_l1_size); - save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[1].data_a, ctx->header.layout.duplex_l1_offset_a, ctx->header.layout.duplex_l1_size); - ctx->duplex_layers[1].data_b = malloc(ctx->header.layout.duplex_l1_size); - save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[1].data_b, ctx->header.layout.duplex_l1_offset_b, ctx->header.layout.duplex_l1_size); - memcpy(&ctx->duplex_layers[1].info, &ctx->header.duplex_header.layers[1], sizeof(duplex_info_t)); - - ctx->duplex_layers[2].data_a = malloc(ctx->header.layout.duplex_data_size); - save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[2].data_a, ctx->header.layout.duplex_data_offset_a, ctx->header.layout.duplex_data_size); - ctx->duplex_layers[2].data_b = malloc(ctx->header.layout.duplex_data_size); - save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[2].data_b, ctx->header.layout.duplex_data_offset_b, ctx->header.layout.duplex_data_size); - memcpy(&ctx->duplex_layers[2].info, &ctx->header.duplex_header.layers[2], sizeof(duplex_info_t)); - - /* Initialize hierarchical duplex storage. */ - uint8_t *bitmap = ctx->header.layout.duplex_index == 1 ? ctx->duplex_layers[0].data_b : ctx->duplex_layers[0].data_a; - save_duplex_storage_init(&ctx->duplex_storage.layers[0], &ctx->duplex_layers[1], bitmap, ctx->header.layout.duplex_master_size); - ctx->duplex_storage.layers[0]._length = ctx->header.layout.duplex_l1_size; - - bitmap = malloc(ctx->duplex_storage.layers[0]._length); - save_duplex_storage_read(&ctx->duplex_storage.layers[0], bitmap, 0, ctx->duplex_storage.layers[0]._length); - save_duplex_storage_init(&ctx->duplex_storage.layers[1], &ctx->duplex_layers[2], bitmap, ctx->duplex_storage.layers[0]._length); - ctx->duplex_storage.layers[1]._length = ctx->header.layout.duplex_data_size; - - ctx->duplex_storage.data_layer = ctx->duplex_storage.layers[1]; - - /* Initialize meta remap storage. */ - ctx->meta_remap_storage.type = STORAGE_DUPLEX; - ctx->meta_remap_storage.duplex = &ctx->duplex_storage.data_layer; - ctx->meta_remap_storage.header = &ctx->header.meta_remap_header; - ctx->meta_remap_storage.map_entries = malloc(sizeof(remap_entry_ctx_t) * ctx->meta_remap_storage.header->map_entry_count); - ctx->meta_remap_storage.file = ctx->file; - f_lseek(ctx->file, ctx->header.layout.meta_map_entry_offset); - for (unsigned int i = 0; i < ctx->meta_remap_storage.header->map_entry_count; i++) { - f_read(ctx->file, &ctx->meta_remap_storage.map_entries[i], 0x20, NULL); - ctx->meta_remap_storage.map_entries[i].physical_offset_end = ctx->meta_remap_storage.map_entries[i].physical_offset + ctx->meta_remap_storage.map_entries[i].size; - ctx->meta_remap_storage.map_entries[i].virtual_offset_end = ctx->meta_remap_storage.map_entries[i].virtual_offset + ctx->meta_remap_storage.map_entries[i].size; - } - - ctx->meta_remap_storage.segments = save_remap_init_segments(ctx->meta_remap_storage.header, ctx->meta_remap_storage.map_entries, ctx->meta_remap_storage.header->map_entry_count); - - /* Initialize journal map. */ - ctx->journal_map_info.map_storage = malloc(ctx->header.layout.journal_map_table_size); - save_remap_read(&ctx->meta_remap_storage, ctx->journal_map_info.map_storage, ctx->header.layout.journal_map_table_offset, ctx->header.layout.journal_map_table_size); - - /* Initialize journal storage. */ - ctx->journal_storage.header = &ctx->header.journal_header; - ctx->journal_storage.journal_data_offset = ctx->header.layout.journal_data_offset; - ctx->journal_storage._length = ctx->journal_storage.header->total_size - ctx->journal_storage.header->journal_size; - ctx->journal_storage.file = ctx->file; - ctx->journal_storage.map.header = &ctx->header.map_header; - ctx->journal_storage.map.map_storage = ctx->journal_map_info.map_storage; - ctx->journal_storage.map.entries = malloc(sizeof(journal_map_entry_t) * ctx->journal_storage.map.header->main_data_block_count); - uint32_t *pos = (uint32_t *)ctx->journal_storage.map.map_storage; - for (unsigned int i = 0; i < ctx->journal_storage.map.header->main_data_block_count; i++) { - ctx->journal_storage.map.entries[i].virtual_index = i; - ctx->journal_storage.map.entries[i].physical_index = *pos & 0x7FFFFFFF; - pos += 2; - } - ctx->journal_storage.block_size = ctx->journal_storage.header->block_size; - ctx->journal_storage._length = ctx->journal_storage.header->total_size - ctx->journal_storage.header->journal_size; - - /* Initialize core IVFC storage. */ - for (unsigned int i = 0; i < 5; i++) { - ctx->core_data_ivfc_storage.levels[i].save_ctx = ctx; - } - save_ivfc_storage_init(&ctx->core_data_ivfc_storage, ctx->header.layout.ivfc_master_hash_offset_a, &ctx->header.data_ivfc_header); - - /* Initialize FAT storage. */ - if (ctx->header.layout.version < 0x50000) { - ctx->fat_storage = malloc(ctx->header.layout.fat_size); - save_remap_read(&ctx->meta_remap_storage, ctx->fat_storage, ctx->header.layout.fat_offset, ctx->header.layout.fat_size); - } else { - for (unsigned int i = 0; i < 5; i++) { - ctx->fat_ivfc_storage.levels[i].save_ctx = ctx; - } - save_ivfc_storage_init(&ctx->fat_ivfc_storage, ctx->header.layout.fat_ivfc_master_hash_a, &ctx->header.fat_ivfc_header); - ctx->fat_storage = malloc(ctx->fat_ivfc_storage._length); - save_remap_read(&ctx->meta_remap_storage, ctx->fat_storage, ctx->header.fat_ivfc_header.level_headers[ctx->header.fat_ivfc_header.num_levels - 2].logical_offset, ctx->fat_ivfc_storage._length); - } - - if (ctx->tool_ctx.action & ACTION_VERIFY) { - save_filesystem_verify(ctx); - } - - /* Initialize core save filesystem. */ - ctx->save_filesystem_core.base_storage = &ctx->core_data_ivfc_storage; - save_filesystem_init(&ctx->save_filesystem_core, ctx->fat_storage, &ctx->header.save_header, &ctx->header.fat_header); -} - -void save_process_header(save_ctx_t *ctx) { - if (ctx->header.layout.magic != MAGIC_DISF || ctx->header.duplex_header.magic != MAGIC_DPFS || - ctx->header.data_ivfc_header.magic != MAGIC_IVFC || ctx->header.journal_header.magic != MAGIC_JNGL || - ctx->header.save_header.magic != MAGIC_SAVE || ctx->header.main_remap_header.magic != MAGIC_RMAP || - ctx->header.meta_remap_header.magic != MAGIC_RMAP) { - EPRINTF("Error: Save header is corrupt!\n"); - } - - ctx->data_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.ivfc_master_hash_offset_a; - ctx->fat_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.fat_ivfc_master_hash_a; - - uint8_t hash[0x20]; - se_calc_sha256(hash, &ctx->header.duplex_header, 0x3D00); - ctx->header_hash_validity = memcmp(hash, ctx->header.layout.hash, 0x20) == 0 ? VALIDITY_VALID : VALIDITY_INVALID; - - ctx->header.data_ivfc_header.num_levels = 5; - - if (ctx->header.layout.version >= 0x50000) { - ctx->header.fat_ivfc_header.num_levels = 4; - } -} - -void save_free_contexts(save_ctx_t *ctx) { - for (unsigned int i = 0; i < ctx->data_remap_storage.header->map_segment_count; i++) { - for (unsigned int j = 0; j < ctx->data_remap_storage.segments[i].entry_count; j++) { - free(&ctx->data_remap_storage.segments[i].entries[j]); - } - } - free(ctx->data_remap_storage.segments); - for (unsigned int i = 0; i < ctx->meta_remap_storage.header->map_segment_count; i++) { - for (unsigned int j = 0; j < ctx->meta_remap_storage.segments[i].entry_count; j++) { - free(&ctx->meta_remap_storage.segments[i].entries[j]); - } - } - free(ctx->meta_remap_storage.segments); - free(ctx->data_remap_storage.map_entries); - free(ctx->meta_remap_storage.map_entries); - free(ctx->duplex_storage.layers[0].bitmap.bitmap); - free(ctx->duplex_storage.layers[1].bitmap.bitmap); - free(ctx->duplex_storage.layers[1].bitmap_storage); - for (unsigned int i = 1; i < 3; i++) { - free(ctx->duplex_layers[i].data_a); - free(ctx->duplex_layers[i].data_b); - } - free(ctx->journal_map_info.map_storage); - free(ctx->journal_storage.map.entries); - for (unsigned int i = 0; i < ctx->header.data_ivfc_header.num_levels - 1; i++) { - free(ctx->core_data_ivfc_storage.integrity_storages[i].block_validities); - } - free(ctx->core_data_ivfc_storage.level_validities); - if (ctx->header.layout.version >= 0x50000) { - for (unsigned int i = 0; i < ctx->header.fat_ivfc_header.num_levels - 1; i++) { - free(ctx->fat_ivfc_storage.integrity_storages[i].block_validities); - } - } - free(ctx->fat_ivfc_storage.level_validities); - free(ctx->fat_storage); -} diff --git a/source/keys/save.h b/source/keys/save.h deleted file mode 100644 index ea44906..0000000 --- a/source/keys/save.h +++ /dev/null @@ -1,489 +0,0 @@ -#ifndef _SAVE_H -#define _SAVE_H - -#include -#include - -#include "../libs/fatfs/ff.h" - -#define SAVE_HEADER_SIZE 0x4000 -#define SAVE_FAT_ENTRY_SIZE 8 -#define SAVE_FS_LIST_MAX_NAME_LENGTH 0x40 -#define SAVE_FS_LIST_ENTRY_SIZE 0x60 - -#define IVFC_MAX_LEVEL 6 - -#define MAGIC_DISF 0x46534944 -#define MAGIC_DPFS 0x53465044 -#define MAGIC_JNGL 0x4C474E4A -#define MAGIC_SAVE 0x45564153 -#define MAGIC_RMAP 0x50414D52 -#define MAGIC_IVFC 0x43465649 - -typedef enum { - VALIDITY_UNCHECKED = 0, - VALIDITY_INVALID, - VALIDITY_VALID -} validity_t; - -typedef struct save_ctx_t save_ctx_t; - -typedef struct { - uint32_t magic; /* DISF */ - uint32_t version; - uint8_t hash[0x20]; - uint64_t file_map_entry_offset; - uint64_t file_map_entry_size; - uint64_t meta_map_entry_offset; - uint64_t meta_map_entry_size; - uint64_t file_map_data_offset; - uint64_t file_map_data_size; - uint64_t duplex_l1_offset_a; - uint64_t duplex_l1_offset_b; - uint64_t duplex_l1_size; - uint64_t duplex_data_offset_a; - uint64_t duplex_data_offset_b; - uint64_t duplex_data_size; - uint64_t journal_data_offset; - uint64_t journal_data_size_a; - uint64_t journal_data_size_b; - uint64_t journal_size; - uint64_t duplex_master_offset_a; - uint64_t duplex_master_offset_b; - uint64_t duplex_master_size; - uint64_t ivfc_master_hash_offset_a; - uint64_t ivfc_master_hash_offset_b; - uint64_t ivfc_master_hash_size; - uint64_t journal_map_table_offset; - uint64_t journal_map_table_size; - uint64_t journal_physical_bitmap_offset; - uint64_t journal_physical_bitmap_size; - uint64_t journal_virtual_bitmap_offset; - uint64_t journal_virtual_bitmap_size; - uint64_t journal_free_bitmap_offset; - uint64_t journal_free_bitmap_size; - uint64_t ivfc_l1_offset; - uint64_t ivfc_l1_size; - uint64_t ivfc_l2_offset; - uint64_t ivfc_l2_size; - uint64_t ivfc_l3_offset; - uint64_t ivfc_l3_size; - uint64_t fat_offset; - uint64_t fat_size; - uint64_t duplex_index; - uint64_t fat_ivfc_master_hash_a; - uint64_t fat_ivfc_master_hash_b; - uint64_t fat_ivfc_l1_offset; - uint64_t fat_ivfc_l1_size; - uint64_t fat_ivfc_l2_offset; - uint64_t fat_ivfc_l2_size; - uint8_t _0x190[0x70]; -} fs_layout_t; - -#pragma pack(push, 1) -typedef struct { - uint64_t offset; - uint64_t length; - uint32_t block_size_power; -} duplex_info_t; -#pragma pack(pop) - -typedef struct { - uint32_t magic; /* DPFS */ - uint32_t version; - duplex_info_t layers[3]; -} duplex_header_t; - -typedef struct { - uint32_t version; - uint32_t main_data_block_count; - uint32_t journal_block_count; - uint32_t _0x0C; -} journal_map_header_t; - -typedef struct { - uint32_t magic; /* JNGL */ - uint32_t version; - uint64_t total_size; - uint64_t journal_size; - uint64_t block_size; -} journal_header_t; - -typedef struct { - uint32_t magic; /* SAVE */ - uint32_t version; - uint64_t block_count; - uint64_t block_size; -} save_fs_header_t; - -typedef struct { - uint64_t block_size; - uint64_t allocation_table_offset; - uint32_t allocation_table_block_count; - uint32_t _0x14; - uint64_t data_offset; - uint32_t data_block_count; - uint32_t _0x24; - uint32_t directory_table_block; - uint32_t file_table_block; -} fat_header_t; - -typedef struct { - uint32_t magic; /* RMAP */ - uint32_t version; - uint32_t map_entry_count; - uint32_t map_segment_count; - uint32_t segment_bits; - uint8_t _0x14[0x2C]; -} remap_header_t; - -typedef struct remap_segment_ctx_t remap_segment_ctx_t; -typedef struct remap_entry_ctx_t remap_entry_ctx_t; - -#pragma pack(push, 1) -struct remap_entry_ctx_t { - uint64_t virtual_offset; - uint64_t physical_offset; - uint64_t size; - uint32_t alignment; - uint32_t _0x1C; - uint64_t virtual_offset_end; - uint64_t physical_offset_end; - remap_segment_ctx_t *segment; - remap_entry_ctx_t *next; -}; -#pragma pack(pop) - -struct remap_segment_ctx_t{ - uint64_t offset; - uint64_t length; - remap_entry_ctx_t *entries; - uint64_t entry_count; -}; - -typedef struct { - uint8_t *data; - uint8_t *bitmap; -} duplex_bitmap_t; - -typedef struct { - uint32_t block_size; - uint8_t *bitmap_storage; - uint8_t *data_a; - uint8_t *data_b; - duplex_bitmap_t bitmap; - uint64_t _length; -} duplex_storage_ctx_t; - -enum base_storage_type { - STORAGE_BYTES = 0, - STORAGE_DUPLEX = 1, - STORAGE_REMAP = 2, - STORAGE_JOURNAL = 3 -}; - -typedef struct { - remap_header_t *header; - remap_entry_ctx_t *map_entries; - remap_segment_ctx_t *segments; - enum base_storage_type type; - uint64_t base_storage_offset; - duplex_storage_ctx_t *duplex; - FIL *file; -} remap_storage_ctx_t; - -typedef struct { - uint64_t title_id; - uint8_t user_id[0x10]; - uint64_t save_id; - uint8_t save_data_type; - uint8_t _0x21[0x1F]; - uint64_t save_owner_id; - uint64_t timestamp; - uint64_t _0x50; - uint64_t data_size; - uint64_t journal_size; - uint64_t commit_id; -} extra_data_t; - -typedef struct { - uint64_t logical_offset; - uint64_t hash_data_size; - uint32_t block_size; - uint32_t reserved; -} ivfc_level_hdr_t; - -typedef struct { - uint32_t magic; - uint32_t id; - uint32_t master_hash_size; - uint32_t num_levels; - ivfc_level_hdr_t level_headers[IVFC_MAX_LEVEL]; - uint8_t salt_source[0x20]; -} ivfc_save_hdr_t; - -#pragma pack(push, 1) -typedef struct { - uint8_t cmac[0x10]; - uint8_t _0x10[0xF0]; - fs_layout_t layout; - duplex_header_t duplex_header; - ivfc_save_hdr_t data_ivfc_header; - uint32_t _0x404; - journal_header_t journal_header; - journal_map_header_t map_header; - uint8_t _0x438[0x1D0]; - save_fs_header_t save_header; - fat_header_t fat_header; - remap_header_t main_remap_header, meta_remap_header; - uint64_t _0x6D0; - extra_data_t extra_data; - uint8_t _0x748[0x390]; - ivfc_save_hdr_t fat_ivfc_header; - uint8_t _0xB98[0x3468]; -} save_header_t; -#pragma pack(pop) - -typedef struct { - duplex_storage_ctx_t layers[2]; - duplex_storage_ctx_t data_layer; - uint64_t _length; -} hierarchical_duplex_storage_ctx_t; - -typedef struct { - uint8_t *data_a; - uint8_t *data_b; - duplex_info_t info; -} duplex_fs_layer_info_t; - -typedef struct { - uint8_t *map_storage; - uint8_t *physical_block_bitmap; - uint8_t *virtual_block_bitmap; - uint8_t *free_block_bitmap; -} journal_map_params_t; - -typedef struct { - uint32_t physical_index; - uint32_t virtual_index; -} journal_map_entry_t; - - -typedef struct { - journal_map_header_t *header; - journal_map_entry_t *entries; - uint8_t *map_storage; -} journal_map_ctx_t; - -typedef struct { - journal_map_ctx_t map; - journal_header_t *header; - uint32_t block_size; - uint64_t journal_data_offset; - uint64_t _length; - FIL *file; -} journal_storage_ctx_t; - -typedef struct { - uint64_t data_offset; - uint64_t data_size; - uint64_t hash_offset; - uint32_t hash_block_size; - validity_t hash_validity; - enum base_storage_type type; - save_ctx_t *save_ctx; -} ivfc_level_save_ctx_t; - -typedef struct { - ivfc_level_save_ctx_t *data; - uint32_t block_size; - uint8_t salt[0x20]; -} integrity_verification_info_ctx_t; - - -typedef struct integrity_verification_storage_ctx_t integrity_verification_storage_ctx_t; - -struct integrity_verification_storage_ctx_t { - ivfc_level_save_ctx_t *hash_storage; - ivfc_level_save_ctx_t *base_storage; - validity_t *block_validities; - uint8_t salt[0x20]; - uint32_t sector_size; - uint32_t sector_count; - uint64_t _length; - integrity_verification_storage_ctx_t *next_level; -}; - -typedef struct { - ivfc_level_save_ctx_t levels[5]; - ivfc_level_save_ctx_t *data_level; - validity_t **level_validities; - uint64_t _length; - integrity_verification_storage_ctx_t integrity_storages[4]; -} hierarchical_integrity_verification_storage_ctx_t; - -typedef struct { - uint32_t prev; - uint32_t next; -} allocation_table_entry_t; - -typedef struct { - uint32_t free_list_entry_index; - void *base_storage; - fat_header_t *header; -} allocation_table_ctx_t; - -typedef struct { - hierarchical_integrity_verification_storage_ctx_t *base_storage; - uint32_t block_size; - uint32_t initial_block; - allocation_table_ctx_t *fat; - uint64_t _length; -} allocation_table_storage_ctx_t; - -typedef struct { - allocation_table_ctx_t *fat; - uint32_t virtual_block; - uint32_t physical_block; - uint32_t current_segment_size; - uint32_t next_block; - uint32_t prev_block; -} allocation_table_iterator_ctx_t; - -typedef struct { - char name[SAVE_FS_LIST_MAX_NAME_LENGTH]; - uint32_t parent; -} save_entry_key_t; - -#pragma pack(push, 1) -typedef struct { - uint32_t start_block; - uint64_t length; - uint32_t _0xC[2]; -} save_file_info_t; -#pragma pack(pop) - -#pragma pack(push, 1) -typedef struct { - uint32_t next_directory; - uint32_t next_file; - uint32_t _0x8[3]; -} save_find_position_t; -#pragma pack(pop) - -#pragma pack(push, 1) -typedef struct { - uint32_t next_sibling; - union { /* Save table entry type. Size = 0x14. */ - save_file_info_t save_file_info; - save_find_position_t save_find_position; - }; -} save_table_entry_t; -#pragma pack(pop) - -#pragma pack(push, 1) -typedef struct { - uint32_t parent; - char name[SAVE_FS_LIST_MAX_NAME_LENGTH]; - save_table_entry_t value; - uint32_t next; -} save_fs_list_entry_t; -#pragma pack(pop) - -typedef struct { - uint32_t free_list_head_index; - uint32_t used_list_head_index; - allocation_table_storage_ctx_t storage; - uint32_t capacity; -} save_filesystem_list_ctx_t; - -typedef struct { - save_filesystem_list_ctx_t file_table; - save_filesystem_list_ctx_t directory_table; -} hierarchical_save_file_table_ctx_t; - -typedef struct { - hierarchical_integrity_verification_storage_ctx_t *base_storage; - allocation_table_ctx_t allocation_table; - save_fs_header_t *header; - hierarchical_save_file_table_ctx_t file_table; -} save_filesystem_ctx_t; - -#define ACTION_VERIFY (1<<2) - -struct save_ctx_t { - save_header_t header; - FIL *file; - struct { - FIL *file; - uint32_t action; - } tool_ctx; - validity_t header_cmac_validity; - validity_t header_hash_validity; - uint8_t *data_ivfc_master; - uint8_t *fat_ivfc_master; - remap_storage_ctx_t data_remap_storage; - remap_storage_ctx_t meta_remap_storage; - duplex_fs_layer_info_t duplex_layers[3]; - hierarchical_duplex_storage_ctx_t duplex_storage; - journal_storage_ctx_t journal_storage; - journal_map_params_t journal_map_info; - hierarchical_integrity_verification_storage_ctx_t core_data_ivfc_storage; - hierarchical_integrity_verification_storage_ctx_t fat_ivfc_storage; - uint8_t *fat_storage; - save_filesystem_ctx_t save_filesystem_core; - uint8_t save_mac_key[0x10]; -}; - -static inline uint32_t allocation_table_entry_index_to_block(uint32_t entry_index) { - return entry_index - 1; -} - -static inline uint32_t allocation_table_block_to_entry_index(uint32_t block_index) { - return block_index + 1; -} - -static inline int allocation_table_is_list_end(allocation_table_entry_t *entry) { - return (entry->next & 0x7FFFFFFF) == 0; -} - -static inline int allocation_table_is_list_start(allocation_table_entry_t *entry) { - return entry->prev == 0x80000000; -} - - -static inline int allocation_table_get_next(allocation_table_entry_t *entry) { - return entry->next & 0x7FFFFFFF; -} - -static inline int allocation_table_get_prev(allocation_table_entry_t *entry) { - return entry->prev & 0x7FFFFFFF; -} - -static inline allocation_table_entry_t *save_allocation_table_read_entry(allocation_table_ctx_t *ctx, uint32_t entry_index) { - return (allocation_table_entry_t *)((uint8_t *)ctx->base_storage + entry_index * SAVE_FAT_ENTRY_SIZE); -} - -static inline uint32_t save_allocation_table_get_free_list_entry_index(allocation_table_ctx_t *ctx) { - return allocation_table_get_next(save_allocation_table_read_entry(ctx, ctx->free_list_entry_index)); -} - -static inline uint32_t save_allocation_table_get_free_list_block_index(allocation_table_ctx_t *ctx) { - return allocation_table_entry_index_to_block(save_allocation_table_get_free_list_entry_index(ctx)); -} - -void save_process(save_ctx_t *ctx); -void save_process_header(save_ctx_t *ctx); -void save_save(save_ctx_t *ctx); -void save_print(save_ctx_t *ctx); - -void save_free_contexts(save_ctx_t *ctx); - -void save_open_fat_storage(save_filesystem_ctx_t *ctx, allocation_table_storage_ctx_t *storage_ctx, uint32_t block_index); -uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count); -int save_fs_list_get_value(save_filesystem_list_ctx_t *ctx, uint32_t index, save_fs_list_entry_t *value); -uint32_t save_fs_get_index_from_key(save_filesystem_list_ctx_t *ctx, save_entry_key_t *key, uint32_t *prev_index); -int save_hierarchical_file_table_find_path_recursive(hierarchical_save_file_table_ctx_t *ctx, save_entry_key_t *key, char *path); -int save_hierarchical_file_table_get_file_entry_by_path(hierarchical_save_file_table_ctx_t *ctx, char *path, save_fs_list_entry_t *entry); - -#endif diff --git a/source/libs/fatfs/diskio.c b/source/libs/fatfs/diskio.c index 0dea450..46c7c09 100644 --- a/source/libs/fatfs/diskio.c +++ b/source/libs/fatfs/diskio.c @@ -179,7 +179,7 @@ DRESULT disk_read ( secindex++; } } - + //system_part (pdrv == 1) ? system_part_sys : system_part_usr if (nx_emmc_part_read(&storage, system_part, sector, count, buff)) { u32 tweak_exp = 0; bool regen_tweak = true; diff --git a/source/libs/fatfs/ff.c b/source/libs/fatfs/ff.c index 87d8ead..e171ccb 100644 --- a/source/libs/fatfs/ff.c +++ b/source/libs/fatfs/ff.c @@ -48,11 +48,17 @@ Module Private Definitions ---------------------------------------------------------------------------*/ +/* +PARTITION VolToPart[] = { + {0, 1}, + {1, 8}, + {1, 9} +}; +*/ PARTITION VolToPart[] = { {0, 1}, - {1, 1}, - {1, 2} + {1, 0} }; #if FF_DEFINED != 86604 /* Revision ID */ diff --git a/source/libs/fatfs/ffconf.h b/source/libs/fatfs/ffconf.h index 00f144a..cbe319a 100644 --- a/source/libs/fatfs/ffconf.h +++ b/source/libs/fatfs/ffconf.h @@ -163,12 +163,12 @@ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ -#define FF_VOLUMES 3 +#define FF_VOLUMES 2 /* Number of volumes (logical drives) to be used. (1-10) */ #define FF_STR_VOLUME_ID 1 -#define FF_VOLUME_STRS "sd", "system", "user" +#define FF_VOLUME_STRS "sd", "emmc" /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive diff --git a/source/tegraexplorer/emmc.c b/source/tegraexplorer/emmc.c new file mode 100644 index 0000000..e177301 --- /dev/null +++ b/source/tegraexplorer/emmc.c @@ -0,0 +1,201 @@ +#include +#include "../mem/heap.h" +#include "gfx.h" +#include "fs.h" +#include "emmc.h" +#include "../utils/types.h" +#include "../libs/fatfs/ff.h" +#include "../utils/sprintf.h" +#include "../utils/btn.h" +#include "../gfx/gfx.h" +#include "../utils/util.h" +#include "../hos/pkg1.h" +#include "../storage/sdmmc.h" +#include "../storage/nx_emmc.h" +#include "../sec/tsec.h" +#include "../soc/t210.h" +#include "../soc/fuse.h" +#include "../mem/mc.h" +#include "../sec/se.h" +#include "../soc/hw_init.h" +#include "../mem/emc.h" +#include "../mem/sdram.h" + +sdmmc_storage_t storage; +emmc_part_t *system_part; +sdmmc_t sdmmc; +__attribute__ ((aligned (16))) FATFS emmc; +LIST_INIT(gpt); + +u8 bis_key[4][32]; +short pkg1ver; + +static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); }; + +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; + + se_aes_key_set(ks, master_key, 0x10); + 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); +} + +void print_biskeys(){ + gfx_printf("\n"); + gfx_hexdump(0, bis_key[0], 32); + gfx_hexdump(0, bis_key[1], 32); + gfx_hexdump(0, bis_key[2], 32); +} + +int mount_emmc(char *partition, int biskeynumb){ + f_unmount("emmc:"); + + se_aes_key_set(8, bis_key[biskeynumb] + 0x00, 0x10); + se_aes_key_set(9, bis_key[biskeynumb] + 0x10, 0x10); + + system_part = nx_emmc_part_find(&gpt, partition); + if (!system_part) { + gfx_printf("Failed to locate %s partition.", partition); + return -1; + } + + if (f_mount(&emmc, "emmc:", 1)) { + gfx_printf("Mount failed of %s.", partition); + return -1; + } + + return 0; +} + +int dump_biskeys(){ + u8 temp_key[0x10], device_key[0x10] = {0}; + tsec_ctxt_t tsec_ctxt; + + int retries = 0; + + sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4); + + // Read package1. + u8 *pkg1 = (u8 *)malloc(0x40000); + sdmmc_storage_set_mmc_partition(&storage, 1); + sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); + const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); + if (!pkg1_id) { + EPRINTF("Unknown pkg1 version."); + return -1; + } + + bool found_tsec_fw = false; + for (const u32 *pos = (const u32 *)pkg1; (u8 *)pos < pkg1 + 0x40000; pos += 0x100 / sizeof(u32)) { + if (*pos == 0xCF42004D) { + tsec_ctxt.fw = (u8 *)pos; + found_tsec_fw = true; + break; + } + } + if (!found_tsec_fw) { + EPRINTF("Failed to locate TSEC firmware."); + return -1; + } + + u8 tsec_keys[0x10] = {0}; + + tsec_key_data_t *key_data = (tsec_key_data_t *)(tsec_ctxt.fw + TSEC_KEY_DATA_ADDR); + tsec_ctxt.pkg1 = pkg1; + tsec_ctxt.size = 0x100 + key_data->blob0_size + key_data->blob1_size + key_data->blob2_size + key_data->blob3_size + key_data->blob4_size; + if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700) { + // Exit after TSEC key generation. + *((vu16 *)((u32)tsec_ctxt.fw + 0x2DB5)) = 0x02F8; + } + + int res = 0; + + mc_disable_ahb_redirect(); + + while (tsec_query(tsec_keys, 0, &tsec_ctxt) < 0) { + memset(tsec_keys, 0x00, 0x10); + retries++; + if (retries > 15) { + res = -1; + break; + } + } + free(pkg1); + + mc_enable_ahb_redirect(); + + if (res < 0) { + gfx_printf("ERROR %x dumping TSEC.\n", res); + return -1; + } + + u32 sbk[4] = {FUSE(FUSE_PRIVATE_KEY0), FUSE(FUSE_PRIVATE_KEY1), + FUSE(FUSE_PRIVATE_KEY2), FUSE(FUSE_PRIVATE_KEY3)}; + se_aes_key_set(8, tsec_keys, 0x10); + se_aes_key_set(9, sbk, 0x10); + se_aes_crypt_block_ecb(8, 0, temp_key, keyblob_key_source); + se_aes_crypt_block_ecb(9, 0, temp_key, temp_key); + se_aes_key_set(7, temp_key, 0x10); + se_aes_crypt_block_ecb(7, 0, device_key, per_console_key_source); + + /* key = unwrap(source, wrapped_key): + key_set(ks, wrapped_key), block_ecb(ks, 0, key, source) -> final key in key + */ + if (_key_exists(device_key)) { + se_aes_key_set(8, device_key, 0x10); + se_aes_unwrap_key(8, 8, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey) + se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x00, bis_key_source[0] + 0x00); // bkey = unwrap(bkeys, kek) + se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x10, bis_key_source[0] + 0x10); + // kek = generate_kek(bkeks, devkey, aeskek, aeskey) + _generate_kek(8, bis_kek_source, device_key, aes_kek_generation_source, aes_key_generation_source); + se_aes_crypt_block_ecb(8, 0, bis_key[1] + 0x00, bis_key_source[1] + 0x00); // bkey = unwrap(bkeys, kek) + se_aes_crypt_block_ecb(8, 0, bis_key[1] + 0x10, bis_key_source[1] + 0x10); + se_aes_crypt_block_ecb(8, 0, bis_key[2] + 0x00, bis_key_source[2] + 0x00); + se_aes_crypt_block_ecb(8, 0, bis_key[2] + 0x10, bis_key_source[2] + 0x10); + memcpy(bis_key[3], bis_key[2], 0x20); + } + + sdmmc_storage_set_mmc_partition(&storage, 0); + // Parse eMMC GPT. + nx_emmc_gpt_parse(&gpt, &storage); + /* + char part_name[37] = "SYSTEM"; + + // todo: menu selection for this + + u32 bis_key_index = 0; + if (strcmp(part_name, "PRODINFOF") == 0) + bis_key_index = 0; + else if (strcmp(part_name, "SAFE") == 0) + bis_key_index = 1; + else if (strcmp(part_name, "SYSTEM") == 0) + bis_key_index = 2; + else if (strcmp(part_name, "USER") == 0) + bis_key_index = 3; + else { + gfx_printf("Partition name %s unrecognized.", part_name); + return; + } + */ + se_aes_key_set(8, bis_key[2] + 0x00, 0x10); + se_aes_key_set(9, bis_key[2] + 0x10, 0x10); + + /* + system_part = nx_emmc_part_find(&gpt, "SYSTEM"); + if (!system_part) { + gfx_printf("Failed to locate SYSTEM partition."); + return -1; + } + + if (f_mount(&emmc_sys, "system:", 1)) { + gfx_printf("Mount failed of SYSTEM."); + return -1; + } + */ + + pkg1ver = pkg1_id->kb; + return 0; +} \ No newline at end of file diff --git a/source/tegraexplorer/emmc.h b/source/tegraexplorer/emmc.h new file mode 100644 index 0000000..5d68209 --- /dev/null +++ b/source/tegraexplorer/emmc.h @@ -0,0 +1,41 @@ +#pragma once + +//int mount_emmc_partition(const char *part, int logicnumb); +int dump_biskeys(); +void print_biskeys(); +int mount_emmc(char *partition, int biskeynumb); + +static const u8 zeros[0x10] = {0}; + +static const u8 keyblob_key_source[0x10] = { + 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3}; + +//======================================Keys======================================// +// from Package1 -> Secure_Monitor +static const u8 aes_kek_generation_source[0x10] = { + 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9}; +static const u8 retail_specific_aes_key_source[0x10] = { + 0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95}; + +// from Package1ldr (or Secure_Monitor on 6.2.0) +static const u8 per_console_key_source[0x10] = { + 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78}; + +// from SPL +static const u8 aes_key_generation_source[0x10] = { + 0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8}; + +// from FS +static const u8 bis_kek_source[0x10] = { + 0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F}; +static const u8 bis_key_source[3][0x20] = { + { + 0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48, + 0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06}, + { + 0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F, + 0x44, 0x42, 0x4E, 0xDA, 0xB4, 0x9D, 0xFC, 0xD9, 0x87, 0x77, 0x24, 0x9A, 0xDC, 0x9F, 0x7C, 0xA4}, + { + 0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C, + 0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4} +}; \ No newline at end of file diff --git a/source/tegraexplorer/fs.c b/source/tegraexplorer/fs.c index 54572ca..91f406e 100644 --- a/source/tegraexplorer/fs.c +++ b/source/tegraexplorer/fs.c @@ -221,7 +221,10 @@ void copyfile(const char *path, const char *outfolder){ gfx_printf("Note:\nTo stop the transfer hold Vol-\n\n%s\nProgress: ", outstring); if (clipboardhelper & OPERATIONMOVE){ - f_rename(path, outstring); + if (strcmp(rootpath, "emmc:/")) + f_rename(path, outstring); + else + message("\nMoving in emummc is not allowed!", COLOR_RED); } else if (clipboardhelper & OPERATIONCOPY) { @@ -301,30 +304,17 @@ int readfolder(const char *path){ } int delfile(const char *path, const char *filename){ - clearscreen(); - int res; - int amount = -1; - u32 start = get_tmr_s(); + char *tempmessage; + size_t tempmessagesize = strlen(filename) + 65; + tempmessage = (char*) malloc (tempmessagesize); - gfx_printf("Are you sure you want to delete:\n%s\n\nPress vol+/- to cancel\n", filename); - while(1){ - res = btn_read(); - if (res & BTN_VOL_UP || res & BTN_VOL_DOWN) - break; - - if (start + 3 > get_tmr_s()){ - gfx_printf("\r", 3 + start - get_tmr_s()); - } - else if (res & BTN_POWER){ - f_unlink(path); - amount = readfolder(currentpath); - break; - } - else { - gfx_printf("\r%kPress power to delete%k", COLOR_RED, COLOR_WHITE); - } + sprintf(tempmessage, "Are you sure you want to delete:\n%s\n\nPress vol+/- to cancel\n", filename); + if (makewaitmenu(tempmessage, "Press power to delete", 3)){ + f_unlink(path); + return readfolder(currentpath); } - return amount; + else + return -1; } void filemenu(const char *startpath){ @@ -334,6 +324,11 @@ void filemenu(const char *startpath){ writecurpath(startpath); amount = readfolder(currentpath); + if (strcmp(rootpath, "emmc:/")) + explfilemenu[5].property = 1; + else + explfilemenu[5].property = -1; + while (1){ res = makefilemenu(fileobjects, amount, currentpath); if (res < 1){ diff --git a/source/tegraexplorer/gfx.c b/source/tegraexplorer/gfx.c index 77b97bf..cc73e60 100644 --- a/source/tegraexplorer/gfx.c +++ b/source/tegraexplorer/gfx.c @@ -12,7 +12,7 @@ const char fixedoptions[3][50] = { "Folder -> previous folder ", "Clipboard -> Current folder ", - "Folder options " + "Return to main menu " }; const char sizevalues[4][3] = { @@ -85,6 +85,30 @@ void printbytes(u8 print[], u32 size, u32 offset){ gfx_hexdump(offset, print, size * sizeof(u8)); } +int makewaitmenu(char *initialmessage, char *hiddenmessage, int timer){ + clearscreen(); + int res; + u32 start = get_tmr_s(); + + gfx_printf(initialmessage); + + while(1){ + res = btn_read(); + + if (res & BTN_VOL_DOWN || res & BTN_VOL_UP) + return 0; + + if (start + timer > get_tmr_s()) + gfx_printf("\r", timer + start - get_tmr_s()); + + else if (res & BTN_POWER) + return 1; + + else + gfx_printf("\r%k%s%k", COLOR_RED, hiddenmessage, COLOR_WHITE); + } +} + void printfsentry(fs_entry file, bool highlight, bool refresh){ int size = 0; char *display; diff --git a/source/tegraexplorer/gfx.h b/source/tegraexplorer/gfx.h index 729820a..5db04b1 100644 --- a/source/tegraexplorer/gfx.h +++ b/source/tegraexplorer/gfx.h @@ -6,4 +6,5 @@ int makemenu(menu_item menu[], int menuamount); int message(char* message, u32 color); void clearscreen(); int makefilemenu(fs_entry *files, int amount, char *path); -void printbytes(u8 print[], u32 size, u32 offset); \ No newline at end of file +void printbytes(u8 print[], u32 size, u32 offset); +int makewaitmenu(char *initialmessage, char *hiddenmessage, int timer); \ No newline at end of file diff --git a/source/tegraexplorer/te.c b/source/tegraexplorer/te.c index 13858e1..05e1321 100644 --- a/source/tegraexplorer/te.c +++ b/source/tegraexplorer/te.c @@ -5,6 +5,8 @@ #include "../utils/util.h" #include "tools.h" #include "fs.h" +#include "../utils/btn.h" +#include "emmc.h" extern bool sd_mount(); extern void sd_unmount(); @@ -13,9 +15,10 @@ bool sd_mounted; menu_item mainmenu[MAINMENU_AMOUNT] = { {"[SD:/] SD CARD", COLOR_GREEN, SD_CARD, 1}, - {"[EMMC:/] ?", COLOR_GREEN, EMMC, 1}, + {"[SYSTEM:/] EMMC", COLOR_GREEN, EMMC_SYS, 1}, {"\nMount/Unmount SD", COLOR_WHITE, MOUNT_SD, 1}, {"Tools", COLOR_VIOLET, TOOLS, 1}, + {"SD format", COLOR_VIOLET, SD_FORMAT, 1}, {"\nCredits", COLOR_WHITE, CREDITS, 1}, {"Exit", COLOR_WHITE, EXIT, 1} }; @@ -59,6 +62,12 @@ void fillmainmenu(){ strcpy(mainmenu[i].name, "\nMount SD"); } break; + case 5: + if (sd_mounted) + mainmenu[i].property = 1; + else + mainmenu[i].property = -1; + break; } } } @@ -66,6 +75,9 @@ void fillmainmenu(){ void te_main(){ int res; + dump_biskeys(); + mount_emmc("SYSTEM", 2); + sd_mounted = sd_mount(); while (1){ @@ -76,8 +88,16 @@ void te_main(){ case SD_CARD: filemenu("SD:/"); break; - case EMMC: + case EMMC_SYS: + if (makewaitmenu("You're about to enter EMMC\nModifying anything here\n can result in a BRICK!\n\nPlease only continue\n if you know what you're doing\n\nPress Vol+/- to return\n", "Press Power to enter", 4)) + filemenu("emmc:/"); break; + /* + case EMMC_USR: + mount_emmc("USER", 2); + filemenu("emmc:/"); + break; + */ case MOUNT_SD: if (sd_mounted){ sd_mounted = false; diff --git a/source/tegraexplorer/te.h b/source/tegraexplorer/te.h index d4e4b36..72e83d9 100644 --- a/source/tegraexplorer/te.h +++ b/source/tegraexplorer/te.h @@ -1,7 +1,7 @@ #pragma once #include "../utils/types.h" -#define MAINMENU_AMOUNT 6 +#define MAINMENU_AMOUNT 7 #define CREDITS_MESSAGE "\nTegraexplorer, made by:\nSuch Meme, Many Skill\n\nProject based on:\nLockpick_RCM\nHekate\n\nCool people:\nshchmue\ndennthecafebabe\nDax" typedef struct _menu_item { @@ -13,9 +13,11 @@ typedef struct _menu_item { enum mainmenu_return { SD_CARD = 1, - EMMC, + EMMC_SYS, + EMMC_USR, MOUNT_SD, TOOLS, + SD_FORMAT, CREDITS, EXIT }; diff --git a/source/tegraexplorer/tools.c b/source/tegraexplorer/tools.c index a1998ce..3d83f3d 100644 --- a/source/tegraexplorer/tools.c +++ b/source/tegraexplorer/tools.c @@ -8,6 +8,7 @@ #include "../utils/types.h" #include "../libs/fatfs/diskio.h" #include "../storage/sdmmc.h" +#include "emmc.h" extern bool sd_mount(); extern void sd_unmount(); @@ -16,31 +17,34 @@ extern sdmmc_storage_t sd_storage; void displayinfo(){ clearscreen(); + + FATFS *fs; - DWORD fre_clust, fre_sect, tot_sect, temp_sect, sz_disk; - s64 capacity; + DWORD fre_clust, fre_sect, tot_sect; + u32 capacity; int res; - gfx_printf("Getting storage info: please wait..."); + gfx_printf("Biskeys:\n"); + print_biskeys(); - res = f_getfree("sd:", &fre_clust, &fs); - gfx_printf("\nResult getfree: %d\n\n", res); + if (!sd_mount()){ + gfx_printf("SD mount failed!\nFailed to display SD info\n"); + } + else { + gfx_printf("Getting storage info: please wait..."); - tot_sect = (fs->n_fatent - 2) * fs->csize; - fre_sect = fre_clust * fs->csize; + res = f_getfree("sd:", &fre_clust, &fs); + gfx_printf("\nResult getfree: %d\n\n", res); - gfx_printf("%d KiB total\n%d KiB free\n\nPress any key to continue\n", tot_sect / 2, fre_sect / 2); + tot_sect = (fs->n_fatent - 2) * fs->csize; + fre_sect = fre_clust * fs->csize; + capacity = sd_storage.csd.capacity; - temp_sect = tot_sect; - temp_sect -= 61145088; - - gfx_printf("\n%k1st part: %d\n2nd part: 61145088\n\n%k", COLOR_RED, temp_sect, COLOR_WHITE); - - capacity = sd_storage.csd.capacity; - capacity -= 61145088; - - gfx_printf("\n%k1st part: %d\n2nd part: 61145088\n\n%k", COLOR_RED, capacity, COLOR_WHITE); + gfx_printf("Entire sd:\nSectors: %d\nSpace total: %d MB\n\n", capacity, capacity / 2048); + gfx_printf("First partition on SD:\nSectors: %d\nSpace total: %d MB\nSpace free: %d MB\n\n", tot_sect, tot_sect / 2048, fre_sect / 2048); + } + gfx_printf("Press any key to continue"); btn_wait(); } @@ -76,7 +80,7 @@ void format(){ DWORD clustsize = 16 * 512; BYTE formatoptions = 0; formatoptions |= (FM_FAT32); - formatoptions |= (FM_SFD); + //formatoptions |= (FM_SFD); timer = get_tmr_s();