KeyCollection.cpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. /*
  2. * Copyright (c) 2018 shchmue
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms and conditions of the GNU General Public License,
  6. * version 2, as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope it will be useful, but WITHOUT
  9. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  11. * more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include "KeyCollection.hpp"
  17. #include "Common.hpp"
  18. #include "Stopwatch.hpp"
  19. #include <algorithm>
  20. #include <chrono>
  21. #include <filesystem>
  22. #include <functional>
  23. #include <string>
  24. #include <unordered_map>
  25. #include <unordered_set>
  26. #include <stdio.h>
  27. #include <switch.h>
  28. #include "fatfs/ff.h"
  29. extern "C" {
  30. #include "nx/es.h"
  31. #include "nx/set_ext.h"
  32. }
  33. #define TITLEKEY_BUFFER_SIZE 0x40000
  34. // hash of empty string
  35. const u8 KeyCollection::null_hash[0x20] = {
  36. 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24,
  37. 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55};
  38. FsStorage storage;
  39. // function timer
  40. template<typename Duration = std::chrono::microseconds, typename FT, typename ... Args>
  41. typename Duration::rep profile(FT&& fun, Args&&... args) {
  42. const auto beg = std::chrono::high_resolution_clock::now();
  43. std::invoke(fun, std::forward<Args>(args)...);
  44. const auto end = std::chrono::high_resolution_clock::now();
  45. return std::chrono::duration_cast<Duration>(end - beg).count();
  46. }
  47. KeyCollection::KeyCollection() {
  48. // init all key hashes
  49. u8 index = 0;
  50. char keynum[] = "00";
  51. for (auto key : std::vector<byte_vector>
  52. {
  53. {0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3},
  54. {0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC},
  55. {0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B},
  56. {0x2D, 0x1F, 0x48, 0x80, 0xED, 0xEC, 0xED, 0x3E, 0x3C, 0xF2, 0x48, 0xB5, 0x65, 0x7D, 0xF7, 0xBE},
  57. {0xBB, 0x5A, 0x01, 0xF9, 0x88, 0xAF, 0xF5, 0xFC, 0x6C, 0xFF, 0x07, 0x9E, 0x13, 0x3C, 0x39, 0x80},
  58. {0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0}
  59. })
  60. {
  61. sprintf(keynum, "%02x", index++);
  62. keyblob_key_source.push_back(Key {"keyblob_key_source_" + std::string(keynum), 0x10, key});
  63. }
  64. for (auto key : std::vector<byte_vector>
  65. {
  66. {0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D}, /* Zeroes encrypted with Master Key 00. */
  67. {0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD}, /* Master key 00 encrypted with Master key 01. */
  68. {0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72}, /* Master key 01 encrypted with Master key 02. */
  69. {0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07}, /* Master key 02 encrypted with Master key 03. */
  70. {0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9}, /* Master key 03 encrypted with Master key 04. */
  71. {0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */
  72. {0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */
  73. })
  74. {
  75. mkey_vector.push_back(Key {key, 0x10});
  76. }
  77. master_kek_source.resize(KNOWN_KEYBLOBS);
  78. master_kek_source.push_back(Key {"master_kek_source_06", 0x10, {
  79. 0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}});
  80. //======================================Keys======================================//
  81. // from Package1 -> Secure_Monitor
  82. aes_kek_generation_source = {"aes_kek_generation_source", 0x10, {
  83. 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9}};
  84. aes_kek_seed_01 = {"aes_kek_seed_01", 0x10, {
  85. 0xA2, 0xAB, 0xBF, 0x9C, 0x92, 0x2F, 0xBB, 0xE3, 0x78, 0x79, 0x9B, 0xC0, 0xCC, 0xEA, 0xA5, 0x74}};
  86. aes_kek_seed_03 = {"aes_kek_seed_03", 0x10, {
  87. 0xE5, 0x4D, 0x9A, 0x02, 0xF0, 0x4F, 0x5F, 0xA8, 0xAD, 0x76, 0x0A, 0xF6, 0x32, 0x95, 0x59, 0xBB}};
  88. package2_key_source = {"package2_key_source", 0x10, {
  89. 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7}};
  90. titlekek_source = {"titlekek_source", 0x10, {
  91. 0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B}};
  92. retail_specific_aes_key_source = {"retail_specific_aes_key_source", 0x10, {
  93. 0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95}};
  94. // from Package1ldr (or Secure_Monitor on 6.2.0)
  95. keyblob_mac_key_source = {"keyblob_mac_key_source", 0x10, {
  96. 0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5}};
  97. master_key_source = {"master_key_source", 0x10, {
  98. 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C}};
  99. per_console_key_source = {"per_console_key_source", 0x10, {
  100. 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78}};
  101. // from SPL
  102. aes_key_generation_source = {"aes_key_generation_source", 0x10, {
  103. 0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8}};
  104. // from FS
  105. bis_kek_source = {"bis_kek_source", 0x10, {
  106. 0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F}};
  107. bis_key_source_00 = {"bis_key_source_00", 0x20, {
  108. 0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48,
  109. 0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06}};
  110. bis_key_source_01 = {"bis_key_source_01", 0x20, {
  111. 0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F,
  112. 0x44, 0x42, 0x4E, 0xDA, 0xB4, 0x9D, 0xFC, 0xD9, 0x87, 0x77, 0x24, 0x9A, 0xDC, 0x9F, 0x7C, 0xA4}};
  113. bis_key_source_02 = {"bis_key_source_02", 0x20, {
  114. 0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C,
  115. 0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4}};
  116. //=====================================Hashes=====================================//
  117. // from FS
  118. header_kek_source = {"header_kek_source", 0x9fd1b07be05b8f4d, {
  119. 0x18, 0x88, 0xca, 0xed, 0x55, 0x51, 0xb3, 0xed, 0xe0, 0x14, 0x99, 0xe8, 0x7c, 0xe0, 0xd8, 0x68,
  120. 0x27, 0xf8, 0x08, 0x20, 0xef, 0xb2, 0x75, 0x92, 0x10, 0x55, 0xaa, 0x4e, 0x2a, 0xbd, 0xff, 0xc2}, 0x10};
  121. header_key_source = {"header_key_source", 0x3e7228ec5873427b, {
  122. 0x8f, 0x78, 0x3e, 0x46, 0x85, 0x2d, 0xf6, 0xbe, 0x0b, 0xa4, 0xe1, 0x92, 0x73, 0xc4, 0xad, 0xba,
  123. 0xee, 0x16, 0x38, 0x00, 0x43, 0xe1, 0xb8, 0xc4, 0x18, 0xc4, 0x08, 0x9a, 0x8b, 0xd6, 0x4a, 0xa6}, 0x20};
  124. key_area_key_application_source = {"key_area_key_application_source", 0x0b14ccce20dbb59b, {
  125. 0x04, 0xad, 0x66, 0x14, 0x3c, 0x72, 0x6b, 0x2a, 0x13, 0x9f, 0xb6, 0xb2, 0x11, 0x28, 0xb4, 0x6f,
  126. 0x56, 0xc5, 0x53, 0xb2, 0xb3, 0x88, 0x71, 0x10, 0x30, 0x42, 0x98, 0xd8, 0xd0, 0x09, 0x2d, 0x9e}, 0x10};
  127. key_area_key_ocean_source = {"key_area_key_ocean_source", 0x055b26945075ff88, {
  128. 0xfd, 0x43, 0x40, 0x00, 0xc8, 0xff, 0x2b, 0x26, 0xf8, 0xe9, 0xa9, 0xd2, 0xd2, 0xc1, 0x2f, 0x6b,
  129. 0xe5, 0x77, 0x3c, 0xbb, 0x9d, 0xc8, 0x63, 0x00, 0xe1, 0xbd, 0x99, 0xf8, 0xea, 0x33, 0xa4, 0x17}, 0x10};
  130. key_area_key_system_source = {"key_area_key_system_source", 0xb2c28e84e1796251, {
  131. 0x1f, 0x17, 0xb1, 0xfd, 0x51, 0xad, 0x1c, 0x23, 0x79, 0xb5, 0x8f, 0x15, 0x2c, 0xa4, 0x91, 0x2e,
  132. 0xc2, 0x10, 0x64, 0x41, 0xe5, 0x17, 0x22, 0xf3, 0x87, 0x00, 0xd5, 0x93, 0x7a, 0x11, 0x62, 0xf7}, 0x10};
  133. save_mac_kek_source = {"save_mac_kek_source", 0x1e15ac1f6f21a26a, {
  134. 0x3D, 0xCB, 0xA1, 0x00, 0xAD, 0x4D, 0xF1, 0x54, 0x7F, 0xE3, 0xC4, 0x79, 0x5C, 0x4B, 0x22, 0x8A,
  135. 0xA9, 0x80, 0x38, 0xF0, 0x7A, 0x36, 0xF1, 0xBC, 0x14, 0x8E, 0xEA, 0xF3, 0xDC, 0xD7, 0x50, 0xF4}, 0x10};
  136. save_mac_key_source = {"save_mac_key_source", 0x68b9ed0d367e6dc4, {
  137. 0xB4, 0x7B, 0x60, 0x0B, 0x1A, 0xD3, 0x14, 0xF9, 0x41, 0x14, 0x7D, 0x8B, 0x39, 0x1D, 0x4B, 0x19,
  138. 0x87, 0xCC, 0x8C, 0x88, 0x4A, 0xC8, 0x9F, 0xFC, 0x91, 0xCA, 0xE2, 0x21, 0xC5, 0x24, 0x51, 0xF7}, 0x10};
  139. sd_card_kek_source = {"sd_card_kek_source", 0xc408d710a3b821eb, {
  140. 0x6B, 0x2E, 0xD8, 0x77, 0xC2, 0xC5, 0x23, 0x34, 0xAC, 0x51, 0xE5, 0x9A, 0xBF, 0xA7, 0xEC, 0x45,
  141. 0x7F, 0x4A, 0x7D, 0x01, 0xE4, 0x62, 0x91, 0xE9, 0xF2, 0xEA, 0xA4, 0x5F, 0x01, 0x1D, 0x24, 0xB7}, 0x10};
  142. sd_card_nca_key_source = {"sd_card_nca_key_source", 0xb026106d9699fec0, { // xxhash of first 0x10 bytes
  143. 0x2E, 0x75, 0x1C, 0xEC, 0xF7, 0xD9, 0x3A, 0x2B, 0x95, 0x7B, 0xD5, 0xFF, 0xCB, 0x08, 0x2F, 0xD0,
  144. 0x38, 0xCC, 0x28, 0x53, 0x21, 0x9D, 0xD3, 0x09, 0x2C, 0x6D, 0xAB, 0x98, 0x38, 0xF5, 0xA7, 0xCC}, 0x20};
  145. sd_card_save_key_source = {"sd_card_save_key_source", 0x9697ba2fec3d3ed1, { // xxhash of first 0x10 bytes
  146. 0xD4, 0x82, 0x74, 0x35, 0x63, 0xD3, 0xEA, 0x5D, 0xCD, 0xC3, 0xB7, 0x4E, 0x97, 0xC9, 0xAC, 0x8A,
  147. 0x34, 0x21, 0x64, 0xFA, 0x04, 0x1A, 0x1D, 0xC8, 0x0F, 0x17, 0xF6, 0xD3, 0x1E, 0x4B, 0xC0, 0x1C}, 0x20};
  148. // from ES
  149. eticket_rsa_kek_source = {"eticket_rsa_kek_source", 0x76d15de09d439bdc, {
  150. 0xB7, 0x1D, 0xB2, 0x71, 0xDC, 0x33, 0x8D, 0xF3, 0x80, 0xAA, 0x2C, 0x43, 0x35, 0xEF, 0x88, 0x73,
  151. 0xB1, 0xAF, 0xD4, 0x08, 0xE8, 0x0B, 0x35, 0x82, 0xD8, 0x71, 0x9F, 0xC8, 0x1C, 0x5E, 0x51, 0x1C}, 0x10};
  152. eticket_rsa_kekek_source = {"eticket_rsa_kekek_source", 0x97436d4ff39703da, {
  153. 0xE8, 0x96, 0x5A, 0x18, 0x7D, 0x30, 0xE5, 0x78, 0x69, 0xF5, 0x62, 0xD0, 0x43, 0x83, 0xC9, 0x96,
  154. 0xDE, 0x48, 0x7B, 0xBA, 0x57, 0x61, 0x36, 0x3D, 0x2D, 0x4D, 0x32, 0x39, 0x18, 0x66, 0xA8, 0x5C}, 0x10};
  155. // from SSL
  156. ssl_rsa_kek_source_x = {"ssl_rsa_kek_source_x", 0xa7084dadd5d9da93, {
  157. 0x69, 0xA0, 0x8E, 0x62, 0xE0, 0xAE, 0x50, 0x7B, 0xB5, 0xDA, 0x0E, 0x65, 0x17, 0x9A, 0xE3, 0xBE,
  158. 0x05, 0x1F, 0xED, 0x3C, 0x49, 0x94, 0x1D, 0xF4, 0xEF, 0x29, 0x56, 0xD3, 0x6D, 0x30, 0x11, 0x0C}, 0x10};
  159. ssl_rsa_kek_source_y = {"ssl_rsa_kek_source_y", 0xbafd95c9f258dc4a, {
  160. 0x1C, 0x86, 0xF3, 0x63, 0x26, 0x54, 0x17, 0xD4, 0x99, 0x22, 0x9E, 0xB1, 0xC4, 0xAD, 0xC7, 0x47,
  161. 0x9B, 0x2A, 0x15, 0xF9, 0x31, 0x26, 0x1F, 0x31, 0xEE, 0x67, 0x76, 0xAE, 0xB4, 0xC7, 0x65, 0x42}, 0x10};
  162. // from TSEC
  163. tsec_root_key = {"tsec_root_key", 0x57b73665b0bbd424, {
  164. 0x03, 0x2a, 0xdf, 0x0a, 0x6b, 0xe7, 0xdd, 0x7c, 0x11, 0xa4, 0xfa, 0x5c, 0xd6, 0x4a, 0x15, 0x75,
  165. 0xe4, 0x69, 0xb9, 0xda, 0x5d, 0x8b, 0xd5, 0x6a, 0x12, 0xd0, 0xfb, 0xc0, 0xeb, 0x84, 0xe8, 0xe7}, 0x10};
  166. rsa_oaep_kek_generation_source = {"rsa_oaep_kek_generation_source", 0x10};
  167. rsa_private_kek_generation_source = {"rsa_private_kek_generation_source", 0x10};
  168. es_keys = {
  169. &eticket_rsa_kek_source,
  170. &eticket_rsa_kekek_source
  171. };
  172. fs_rodata_keys = {
  173. &header_kek_source,
  174. &key_area_key_application_source,
  175. &key_area_key_ocean_source,
  176. &key_area_key_system_source,
  177. &save_mac_kek_source,
  178. &save_mac_key_source
  179. };
  180. // only look for sd keys if at least firm 2.0.0
  181. if (kernelAbove200()) {
  182. fs_rodata_keys.insert(fs_rodata_keys.end(), {
  183. &sd_card_kek_source,
  184. &sd_card_nca_key_source,
  185. &sd_card_save_key_source
  186. });
  187. }
  188. ssl_keys = {
  189. &ssl_rsa_kek_source_x,
  190. &ssl_rsa_kek_source_y
  191. };
  192. };
  193. void KeyCollection::get_keys() {
  194. Stopwatch total_time;
  195. total_time.start();
  196. int64_t profiler_time = profile(Common::get_tegra_keys, sbk, tsec, tsec_root_key);
  197. if ((sbk.found() && tsec.found()) || tsec_root_key.found()) {
  198. Common::draw_text_with_time(0x10, 0x60, GREEN, "Get Tegra keys...", profiler_time);
  199. } else {
  200. Common::draw_text(0x010, 0x60, RED, "Get Tegra keys...");
  201. Common::draw_text(0x190, 0x60, RED, "Failed");
  202. Common::draw_text(0x2a0, 0x60, RED, "Warning: Saving limited keyset.");
  203. Common::draw_text(0x2a0, 0x80, RED, "Dump TSEC and Fuses with Hekate.");
  204. }
  205. profiler_time = profile(&KeyCollection::get_memory_keys, *this);
  206. Common::draw_text_with_time(0x10, 0x080, GREEN, "Get keys from memory...", profiler_time);
  207. profiler_time = profile(&KeyCollection::get_master_keys, *this);
  208. Common::draw_text_with_time(0x10, 0x0a0, GREEN, "Get master keys...", profiler_time);
  209. profiler_time = profile(&KeyCollection::derive_keys, *this);
  210. Common::draw_text_with_time(0x10, 0x0c0, GREEN, "Derive remaining keys...", profiler_time);
  211. // avoid crash on CFWs that don't use /switch folder
  212. if (!std::filesystem::exists("/switch"))
  213. std::filesystem::create_directory("/switch");
  214. // since Lockpick_RCM can dump newer keys, check for existing keyfile
  215. bool Lockpick_RCM_file_found = false;
  216. if (std::filesystem::exists("/switch/prod.keys")) {
  217. FILE *key_file = fopen("/switch/prod.keys", "r");
  218. char line[0x200];
  219. while (fgets(line, sizeof(line), key_file)) {
  220. if (strncmp("master_key_07", line, 13) == 0) {
  221. Lockpick_RCM_file_found = true;
  222. } else if (!eticket_rsa_kek.found() && (strncmp("eticket_rsa_kek", line, 15)) == 0) {
  223. // grab eticket_rsa_kek from existing file to make sure we can dump titlekeys
  224. eticket_rsa_kek = Key("eticket_rsa_kek", 0x10, Common::key_string_to_byte_vector(line));
  225. }
  226. }
  227. fclose(key_file);
  228. }
  229. if (!Lockpick_RCM_file_found) {
  230. profiler_time = profile(&KeyCollection::save_keys, *this);
  231. Common::draw_text_with_time(0x10, 0x0e0, GREEN, "Saving keys to keyfile...", profiler_time);
  232. } else {
  233. Common::draw_text(0x10, 0x0e0, YELLOW, "Saving keys to keyfile...");
  234. Common::draw_text(0x190, 0x0e0, YELLOW, "Newer keyfile found. Skipped overwriting keys");
  235. }
  236. total_time.stop();
  237. Common::draw_line(0x8, 0xf0, 0x280, GREEN);
  238. Common::draw_text_with_time(0x10, 0x110, GREEN, "Total time elapsed:", total_time.get_elapsed());
  239. char keys_str[32];
  240. if (!Lockpick_RCM_file_found) {
  241. sprintf(keys_str, "Total keys found: %lu", Key::get_saved_key_count());
  242. Common::draw_text(0x2a0, 0x110, CYAN, keys_str);
  243. Common::draw_text(0x80, 0x140, YELLOW, "Keys saved to \"/switch/prod.keys\"!");
  244. }
  245. Common::draw_text(0x10, 0x170, CYAN, "Dumping titlekeys...");
  246. Common::update_display();
  247. profiler_time = profile(&KeyCollection::get_titlekeys, *this);
  248. Common::draw_text_with_time(0x10, 0x170, GREEN, "Dumping titlekeys...", profiler_time);
  249. sprintf(keys_str, "Titlekeys found: %lu", titlekeys_dumped);
  250. Common::draw_text(0x2a0, 0x170, CYAN, keys_str);
  251. if (titlekeys_dumped > 0)
  252. Common::draw_text(0x80, 0x1a0, YELLOW, "Titlekeys saved to \"/switch/title.keys\"!");
  253. else
  254. Common::draw_text(0x80, 0x1a0, GREEN, "No titlekeys found. Either you've never played or installed a game or dump failed.");
  255. }
  256. void KeyCollection::get_master_keys() {
  257. char keynum[] = "00";
  258. if (sbk.found() && tsec.found()) {
  259. for (u8 i = 0; i < keyblob_key_source.size(); i++) {
  260. sprintf(keynum, "%02x", i);
  261. keyblob_key.push_back(Key {"keyblob_key_" + std::string(keynum), 0x10,
  262. sbk.aes_decrypt_ecb(tsec.aes_decrypt_ecb(keyblob_key_source[i].key))});
  263. keyblob_mac_key.push_back(Key {"keyblob_mac_key_" + std::string(keynum), 0x10,
  264. keyblob_key.back().aes_decrypt_ecb(keyblob_mac_key_source.key)});
  265. }
  266. }
  267. if (!keyblob_mac_key.empty()) {
  268. KeyLocation Keyblobs;
  269. Keyblobs.get_keyblobs();
  270. u8 index = 0;
  271. for (byte_vector::const_iterator It = Keyblobs.data.begin(); It != Keyblobs.data.end(); It += 0x200) {
  272. sprintf(keynum, "%02x", index);
  273. encrypted_keyblob.push_back(Key {"encrypted_keyblob_" + std::string(keynum), 0xb0, byte_vector(It, It + 0xb0)});
  274. byte_vector keyblob_mac(keyblob_mac_key[index].cmac(byte_vector(encrypted_keyblob.back().key.begin() + 0x10, encrypted_keyblob.back().key.end())));
  275. if (!std::equal(encrypted_keyblob.back().key.begin(), encrypted_keyblob.back().key.begin() + 0x10, keyblob_mac.begin())) {
  276. // if keyblob cmac fails, invalidate all console-unique keys to prevent faulty derivation or saving bad values
  277. sbk = Key();
  278. tsec = Key();
  279. keyblob_key.clear();
  280. keyblob_mac_key.clear();
  281. break;
  282. }
  283. index++;
  284. }
  285. }
  286. for (u8 i = 0; i < keyblob_key.size(); i++) {
  287. sprintf(keynum, "%02x", i);
  288. keyblob.push_back(Key {"keyblob_" + std::string(keynum), 0x90,
  289. keyblob_key[i].aes_decrypt_ctr(
  290. byte_vector(encrypted_keyblob[i].key.begin() + 0x20, encrypted_keyblob[i].key.end()),
  291. byte_vector(encrypted_keyblob[i].key.begin() + 0x10, encrypted_keyblob[i].key.begin() + 0x20))});
  292. package1_key.push_back(Key {"package1_key_" + std::string(keynum), 0x10,
  293. byte_vector(keyblob.back().key.begin() + 0x80, keyblob.back().key.end())});
  294. master_kek.push_back(Key {"master_kek_" + std::string(keynum), 0x10,
  295. byte_vector(keyblob.back().key.begin(), keyblob.back().key.begin() + 0x10)});
  296. master_key.push_back(Key {"master_key_" + std::string(keynum), 0x10, master_kek.back().aes_decrypt_ecb(master_key_source.key)});
  297. }
  298. if (tsec_root_key.found()) {
  299. if (master_kek.empty()) {
  300. master_kek.resize(KNOWN_KEYBLOBS);
  301. master_key.resize(KNOWN_KEYBLOBS);
  302. }
  303. master_kek.push_back(Key {"master_kek_06", 0x10, tsec_root_key.aes_decrypt_ecb(master_kek_source[KNOWN_KEYBLOBS].key)});
  304. master_key.push_back(Key {"master_key_06", 0x10, master_kek[KNOWN_KEYBLOBS].aes_decrypt_ecb(master_key_source.key)});
  305. if (!master_key[KNOWN_KEYBLOBS - 1].found()) {
  306. for (int i = KNOWN_KEYBLOBS - 1; i >= 0; i--) {
  307. sprintf(keynum, "%02x", i);
  308. master_key[i] = Key {"master_key_" + std::string(keynum), 0x10, master_key[i+1].aes_decrypt_ecb(mkey_vector[i+1].key)};
  309. }
  310. byte_vector zeroes(0x10, 0);
  311. if (!std::equal(zeroes.begin(), zeroes.end(), master_key[0].aes_decrypt_ecb(mkey_vector[0].key).begin())) {
  312. // if last mkey doesn't decrypt vector to zeroes, invalidate all master_keys and keks
  313. master_kek.clear();
  314. master_key.clear();
  315. }
  316. }
  317. }
  318. }
  319. void KeyCollection::get_memory_keys() {
  320. KeyLocation
  321. ESRodata,
  322. FSRodata,
  323. FSData,
  324. SSLRodata;
  325. FSRodata.get_from_memory(FS_TID, SEG_RODATA);
  326. FSData.get_from_memory(FS_TID, SEG_DATA);
  327. FSRodata.find_keys(fs_rodata_keys);
  328. size_t i = 0;
  329. /*for ( ; i < FSData.data.size(); i++) {
  330. // speeds things up but i'm not 100% sure this is always here
  331. if (*reinterpret_cast<u128 *>(FSData.data.data() + i) == 0x10001)
  332. break;
  333. }*/
  334. header_key_source.find_key(FSData.data, i);
  335. SSLRodata.get_from_memory(SSL_TID, SEG_RODATA);
  336. // using find_keys on these is actually slower
  337. for (auto k : ssl_keys)
  338. k->find_key(SSLRodata.data);
  339. // firmware 1.0.0 doesn't have the ES keys
  340. if (!kernelAbove200())
  341. return;
  342. ESRodata.get_from_memory(ES_TID, SEG_RODATA);
  343. for (auto k : es_keys)
  344. k->find_key(ESRodata.data);
  345. }
  346. void KeyCollection::derive_keys() {
  347. if (header_kek_source.found() && header_key_source.found()) {
  348. u8 tempheaderkek[0x10], tempheaderkey[0x20];
  349. splCryptoInitialize();
  350. splCryptoGenerateAesKek(header_kek_source.key.data(), 0, 0, tempheaderkek);
  351. splCryptoGenerateAesKey(tempheaderkek, header_key_source.key.data() + 0x00, tempheaderkey + 0x00);
  352. splCryptoGenerateAesKey(tempheaderkek, header_key_source.key.data() + 0x10, tempheaderkey + 0x10);
  353. header_key = {"header_key", 0x20, byte_vector(tempheaderkey, tempheaderkey + 0x20)};
  354. splCryptoExit();
  355. }
  356. if (bis_key_source_00.found() && bis_key_source_01.found() && bis_key_source_02.found()) {
  357. u8 tempbiskek[0x10], tempbiskey[0x20];
  358. splFsInitialize();
  359. splFsGenerateSpecificAesKey(bis_key_source_00.key.data() + 0x00, 0, 0, tempbiskey + 0x00);
  360. splFsGenerateSpecificAesKey(bis_key_source_00.key.data() + 0x10, 0, 0, tempbiskey + 0x10);
  361. bis_key.push_back(Key {"bis_key_00", 0x20, byte_vector(tempbiskey, tempbiskey + 0x20)});
  362. splFsExit();
  363. splCryptoInitialize();
  364. splCryptoGenerateAesKek(bis_kek_source.key.data(), 0, 1, tempbiskek);
  365. splCryptoGenerateAesKey(tempbiskek, bis_key_source_01.key.data() + 0x00, tempbiskey + 0x00);
  366. splCryptoGenerateAesKey(tempbiskek, bis_key_source_01.key.data() + 0x10, tempbiskey + 0x10);
  367. bis_key.push_back(Key {"bis_key_01", 0x20, byte_vector(tempbiskey, tempbiskey + 0x20)});
  368. splCryptoGenerateAesKey(tempbiskek, bis_key_source_02.key.data() + 0x00, tempbiskey + 0x00);
  369. splCryptoGenerateAesKey(tempbiskek, bis_key_source_02.key.data() + 0x10, tempbiskey + 0x10);
  370. bis_key.push_back(Key {"bis_key_02", 0x20, byte_vector(tempbiskey, tempbiskey + 0x20)});
  371. bis_key.push_back(Key {"bis_key_03", 0x20, bis_key[2].key});
  372. splCryptoExit();
  373. }
  374. for (u8 i = 0; i < aes_kek_generation_source.key.size(); i++) {
  375. rsa_oaep_kek_generation_source.key.push_back(aes_kek_generation_source.key[i] ^ aes_kek_seed_03.key[i]);
  376. rsa_private_kek_generation_source.key.push_back(aes_kek_generation_source.key[i] ^ aes_kek_seed_01.key[i]);
  377. }
  378. rsa_oaep_kek_generation_source.set_found();
  379. rsa_private_kek_generation_source.set_found();
  380. if (!keyblob_key.empty())
  381. device_key = Key {"device_key", 0x10, keyblob_key[0].aes_decrypt_ecb(per_console_key_source.key)};
  382. if (device_key.found() && save_mac_kek_source.found() && save_mac_key_source.found()) {
  383. Key kek = {save_mac_kek_source.generate_kek(device_key, aes_kek_generation_source, Key {}), 0x10};
  384. save_mac_key = Key {"save_mac_key", 0x10, kek.aes_decrypt_ecb(save_mac_key_source.key)};
  385. }
  386. char keynum[] = "00";
  387. for (u8 i = 0; i < master_key.size(); i++) {
  388. if (!master_key[i].found())
  389. continue;
  390. sprintf(keynum, "%02x", i);
  391. key_area_key_application.push_back(Key {"key_area_key_application_" + std::string(keynum), 0x10,
  392. key_area_key_application_source.generate_kek(master_key[i], aes_kek_generation_source, aes_key_generation_source)});
  393. key_area_key_ocean.push_back(Key {"key_area_key_ocean_" + std::string(keynum), 0x10,
  394. key_area_key_ocean_source.generate_kek(master_key[i], aes_kek_generation_source, aes_key_generation_source)});
  395. key_area_key_system.push_back(Key {"key_area_key_system_" + std::string(keynum), 0x10,
  396. key_area_key_system_source.generate_kek(master_key[i], aes_kek_generation_source, aes_key_generation_source)});
  397. package2_key.push_back(Key {"package2_key_" + std::string(keynum), 0x10, master_key[i].aes_decrypt_ecb(package2_key_source.key)});
  398. titlekek.push_back(Key {"titlekek_" + std::string(keynum), 0x10, master_key[i].aes_decrypt_ecb(titlekek_source.key)});
  399. }
  400. if (eticket_rsa_kek_source.found() && eticket_rsa_kekek_source.found() && !master_key.empty())
  401. eticket_rsa_kek = Key {"eticket_rsa_kek", 0x10,
  402. eticket_rsa_kekek_source.generate_kek(master_key[0], rsa_oaep_kek_generation_source, eticket_rsa_kek_source)};
  403. if (ssl_rsa_kek_source_x.found() && ssl_rsa_kek_source_y.found() && !master_key.empty())
  404. ssl_rsa_kek = Key {"ssl_rsa_kek", 0x10,
  405. ssl_rsa_kek_source_x.generate_kek(master_key[0], rsa_private_kek_generation_source, ssl_rsa_kek_source_y)};
  406. char seed_vector[0x10], seed[0x10], buffer[0x10];
  407. u32 bytes_read, file_pos = 0;
  408. // dump sd seed
  409. if (!kernelAbove200())
  410. return;
  411. FILE *sd_private = fopen("/Nintendo/Contents/private", "rb");
  412. if (!sd_private) return;
  413. fread(seed_vector, 0x10, 1, sd_private);
  414. fclose(sd_private);
  415. FATFS fs;
  416. FRESULT fr;
  417. FIL save_file;
  418. fsOpenBisStorage(&storage, 31);
  419. if (f_mount(&fs, "", 1) ||
  420. f_chdir("/save") ||
  421. f_open(&save_file, "8000000000000043", FA_READ | FA_OPEN_EXISTING))
  422. {
  423. fsStorageClose(&storage);
  424. return;
  425. }
  426. for (;;) {
  427. fr = f_read(&save_file, buffer, 0x10, &bytes_read);
  428. if (fr || (bytes_read == 0)) break;
  429. if (std::equal(seed_vector, seed_vector + 0x10, buffer)) {
  430. f_read(&save_file, seed, 0x10, &bytes_read);
  431. sd_seed = Key {"sd_seed", 0x10, byte_vector(seed, seed + 0x10)};
  432. break;
  433. }
  434. file_pos += 0x4000;
  435. if (f_lseek(&save_file, file_pos)) break;
  436. }
  437. f_close(&save_file);
  438. fsStorageClose(&storage);
  439. }
  440. void KeyCollection::save_keys() {
  441. FILE *key_file = fopen("/switch/prod.keys", "w");
  442. if (!key_file) return;
  443. aes_kek_generation_source.save_key(key_file);
  444. aes_key_generation_source.save_key(key_file);
  445. bis_kek_source.save_key(key_file);
  446. for (auto k : bis_key)
  447. k.save_key(key_file);
  448. bis_key_source_00.save_key(key_file);
  449. bis_key_source_01.save_key(key_file);
  450. bis_key_source_02.save_key(key_file);
  451. device_key.save_key(key_file);
  452. eticket_rsa_kek.save_key(key_file);
  453. for (auto k : es_keys)
  454. k->save_key(key_file);
  455. header_kek_source.save_key(key_file);
  456. header_key.save_key(key_file);
  457. header_key_source.save_key(key_file);
  458. for (auto k : key_area_key_application)
  459. k.save_key(key_file);
  460. key_area_key_application_source.save_key(key_file);
  461. for (auto k : key_area_key_ocean)
  462. k.save_key(key_file);
  463. key_area_key_ocean_source.save_key(key_file);
  464. for (auto k : key_area_key_system)
  465. k.save_key(key_file);
  466. key_area_key_system_source.save_key(key_file);
  467. for (auto k : keyblob)
  468. k.save_key(key_file);
  469. for (auto k : keyblob_key)
  470. k.save_key(key_file);
  471. for (auto k : keyblob_key_source)
  472. k.save_key(key_file);
  473. for (auto k : keyblob_mac_key)
  474. k.save_key(key_file);
  475. keyblob_mac_key_source.save_key(key_file);
  476. for (auto k : master_kek)
  477. k.save_key(key_file);
  478. for (auto k : master_kek_source)
  479. k.save_key(key_file);
  480. for (auto k : master_key)
  481. k.save_key(key_file);
  482. master_key_source.save_key(key_file);
  483. for (auto k : package1_key)
  484. k.save_key(key_file);
  485. for (auto k : package2_key)
  486. k.save_key(key_file);
  487. package2_key_source.save_key(key_file);
  488. per_console_key_source.save_key(key_file);
  489. retail_specific_aes_key_source.save_key(key_file);
  490. rsa_oaep_kek_generation_source.save_key(key_file);
  491. rsa_private_kek_generation_source.save_key(key_file);
  492. save_mac_kek_source.save_key(key_file);
  493. save_mac_key.save_key(key_file);
  494. save_mac_key_source.save_key(key_file);
  495. sd_card_kek_source.save_key(key_file);
  496. sd_card_nca_key_source.save_key(key_file);
  497. sd_card_save_key_source.save_key(key_file);
  498. sd_seed.save_key(key_file);
  499. sbk.save_key(key_file);
  500. ssl_rsa_kek.save_key(key_file);
  501. for (auto k : ssl_keys)
  502. k->save_key(key_file);
  503. for (auto k : titlekek)
  504. k.save_key(key_file);
  505. titlekek_source.save_key(key_file);
  506. tsec.save_key(key_file);
  507. tsec_root_key.save_key(key_file);
  508. fclose(key_file);
  509. }
  510. void KeyCollection::get_titlekeys() {
  511. if (!kernelAbove200() || !eticket_rsa_kek.found())
  512. return;
  513. u32 common_count, personalized_count, bytes_read, ids_written;
  514. esInitialize();
  515. esCountCommonTicket(&common_count);
  516. esCountPersonalizedTicket(&personalized_count);
  517. NcmNcaId common_rights_ids[common_count], personalized_rights_ids[personalized_count];
  518. esListCommonTicket(&ids_written, common_rights_ids, sizeof(common_rights_ids));
  519. esListPersonalizedTicket(&ids_written, personalized_rights_ids, sizeof(personalized_rights_ids));
  520. esExit();
  521. if (common_count + personalized_count == 0)
  522. return;
  523. /*
  524. catalog all currently installed rights ids
  525. since we are crawling the whole save file, we might accidentally find previously deleted tickets
  526. this would be fine, except we have to match the exact list so we don't stop too early
  527. */
  528. char titlekey_block[0x100], buffer[TITLEKEY_BUFFER_SIZE], rights_id_string[0x21], titlekey_string[0x21];
  529. std::unordered_set<std::string> rights_ids;
  530. for (size_t i = 0; i < common_count; i++) {
  531. for (size_t j = 0; j < 0x10; j++) {
  532. sprintf(&rights_id_string[j*2], "%02x", common_rights_ids[i].c[j]);
  533. }
  534. rights_ids.insert(rights_id_string);
  535. }
  536. for (size_t i = 0; i < personalized_count; i++) {
  537. for (size_t j = 0; j < 0x10; j++) {
  538. sprintf(&rights_id_string[j*2], "%02x", personalized_rights_ids[i].c[j]);
  539. }
  540. rights_ids.insert(rights_id_string);
  541. }
  542. // get extended eticket RSA key from PRODINFO
  543. u8 eticket_data[0x244] = {};
  544. setcalInitialize();
  545. setcalGetEticketDeviceKey(eticket_data);
  546. setcalExit();
  547. byte_vector dec_keypair = eticket_rsa_kek.aes_decrypt_ctr(
  548. byte_vector(eticket_data + 0x14, eticket_data + 0x244),
  549. byte_vector(eticket_data + 4, eticket_data + 0x14)
  550. );
  551. // public exponent must be 65537 == 0x10001 (big endian)
  552. if (!(dec_keypair[0x200] == 0) || !(dec_keypair[0x201] == 1) || !(dec_keypair[0x202] == 0) || !(dec_keypair[0x203] == 1))
  553. return;
  554. u8 *D = &dec_keypair[0], *N = &dec_keypair[0x100], *E = &dec_keypair[0x200];
  555. if (!test_key_pair(E, D, N))
  556. return;
  557. FATFS fs;
  558. FRESULT fr;
  559. FIL save_file;
  560. // map of all found rights ids and corresponding titlekeys
  561. std::unordered_map<std::string, std::string> titlekeys;
  562. fsOpenBisStorage(&storage, 31);
  563. if (f_mount(&fs, "", 1) || f_chdir("/save")) return;
  564. if (f_open(&save_file, "80000000000000e1", FA_READ | FA_OPEN_EXISTING)) return;
  565. while ((common_count != 0) && (titlekeys_dumped < common_count)) {
  566. fr = f_read(&save_file, buffer, TITLEKEY_BUFFER_SIZE, &bytes_read);
  567. if (fr || (bytes_read == 0)) break;
  568. for (size_t i = 0; i < bytes_read; i += 0x4000) {
  569. for (size_t j = i; j < i + 0x4000; j += 0x400) {
  570. if (*reinterpret_cast<u32 *>(&buffer[j]) == 0x10004) {
  571. for (size_t k = 0; k < 0x10; k++)
  572. sprintf(&rights_id_string[k*2], "%02x", buffer[j + 0x2a0 + k]);
  573. // skip if rights id not reported by es
  574. if (rights_ids.find(rights_id_string) == rights_ids.end())
  575. continue;
  576. // skip if rights id already in map
  577. if (titlekeys.find(rights_id_string) != titlekeys.end())
  578. continue;
  579. for (size_t k = 0; k < 0x10; k++)
  580. sprintf(&titlekey_string[k*2], "%02x", buffer[j + 0x180 + k]);
  581. titlekeys[rights_id_string] = titlekey_string;
  582. titlekeys_dumped++;
  583. } else {
  584. break;
  585. }
  586. }
  587. }
  588. }
  589. f_close(&save_file);
  590. u8 M[0x100];
  591. if (f_open(&save_file, "80000000000000e2", FA_READ | FA_OPEN_EXISTING)) return;
  592. while ((personalized_count != 0) && (titlekeys_dumped < common_count + personalized_count)) {
  593. fr = f_read(&save_file, buffer, TITLEKEY_BUFFER_SIZE, &bytes_read);
  594. if (fr || (bytes_read == 0)) break;
  595. for (size_t i = 0; i < bytes_read; i += 0x4000) {
  596. for (size_t j = i; j < i + 0x4000; j += 0x400) {
  597. if (*reinterpret_cast<u32 *>(&buffer[j]) == 0x10004) {
  598. for (size_t k = 0; k < 0x10; k++)
  599. sprintf(&rights_id_string[k*2], "%02x", buffer[j + 0x2a0 + k]);
  600. // skip if rights id not reported by es
  601. if (rights_ids.find(rights_id_string) == rights_ids.end())
  602. continue;
  603. // skip if rights id already in map
  604. if (titlekeys.find(rights_id_string) != titlekeys.end())
  605. continue;
  606. std::copy(buffer + j + 0x180, buffer + j + 0x280, titlekey_block);
  607. splUserExpMod(titlekey_block, N, D, 0x100, M);
  608. // decrypts the titlekey from personalized ticket
  609. u8 salt[0x20], db[0xdf];
  610. mgf1(M + 0x21, 0xdf, salt, 0x20);
  611. for (size_t k = 0; k < 0x20; k++)
  612. salt[k] ^= M[k + 1];
  613. mgf1(salt, 0x20, db, 0xdf);
  614. for (size_t k = 0; k < 0xdf; k++)
  615. db[k] ^= M[k + 0x21];
  616. // verify it starts with hash of null string
  617. if (!std::equal(db, db + 0x20, null_hash))
  618. continue;
  619. for (size_t k = 0; k < 0x10; k++)
  620. sprintf(&titlekey_string[k*2], "%02x", db[k + 0xcf]);
  621. titlekeys[rights_id_string] = titlekey_string;
  622. titlekeys_dumped++;
  623. } else {
  624. break;
  625. }
  626. }
  627. }
  628. }
  629. f_close(&save_file);
  630. fsStorageClose(&storage);
  631. if (titlekeys.empty())
  632. return;
  633. FILE *titlekey_file = fopen("/switch/title.keys", "wb");
  634. if (!titlekey_file) return;
  635. for (auto k : titlekeys)
  636. fprintf(titlekey_file, "%s = %s\n", k.first.c_str(), k.second.c_str());
  637. fclose(titlekey_file);
  638. }
  639. void KeyCollection::mgf1(const u8 *data, size_t data_length, u8 *mask, size_t mask_length) {
  640. u8 data_counter[data_length + 4] = {};
  641. std::copy(data, data + data_length, data_counter);
  642. sha256CalculateHash(mask, data_counter, data_length + 4);
  643. for (u32 i = 1; i < (mask_length / 0x20) + 1; i++) {
  644. for (size_t j = 0; j < 4; j++)
  645. data_counter[data_length + 3 - j] = (i >> (8 * j)) & 0xff;
  646. if (i * 0x20 <= mask_length)
  647. sha256CalculateHash(mask + (i * 0x20), data_counter, data_length + 4);
  648. else {
  649. u8 temp_mask[0x20];
  650. sha256CalculateHash(temp_mask, data_counter, data_length + 4);
  651. std::copy(temp_mask, temp_mask + mask_length - (i * 0x20), mask + (i * 0x20));
  652. }
  653. }
  654. }
  655. bool KeyCollection::test_key_pair(const void *E, const void *D, const void *N) {
  656. u8 X[0x100] = {0}, Y[0x100] = {0}, Z[0x100] = {0};
  657. // 0xCAFEBABE
  658. X[0xfc] = 0xca; X[0xfd] = 0xfe; X[0xfe] = 0xba; X[0xff] = 0xbe;
  659. splUserExpMod(X, N, D, 0x100, Y);
  660. splUserExpMod(Y, N, E, 4, Z);
  661. for (size_t i = 0; i < 0x100; i++)
  662. if (X[i] != Z[i])
  663. return false;
  664. return true;
  665. }