crypto.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. #include <stdint.h>
  2. #include <stdbool.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <switch.h>
  6. #include "nx/crypto.h"
  7. #include "nx/nca.h"
  8. #include "nx/fs.h"
  9. #include "util/util.h"
  10. #include "util/file.h"
  11. #include "util/log.h"
  12. #define KEYGEN_LIMIT 0x20
  13. uint8_t HEADER_KEK[0x10];
  14. uint8_t HEADER_KEY[0x20];
  15. uint8_t HEADER_KEY_0[0x10];
  16. uint8_t HEADER_KEY_1[0x10];
  17. typedef struct
  18. {
  19. uint8_t total;
  20. NcaKeyArea_t key[KEYGEN_LIMIT];
  21. } KeySection_t;
  22. typedef struct
  23. {
  24. KeySection_t keak[0x3]; // index
  25. KeySection_t title_key;
  26. KeySection_t mkey;
  27. } keyz_t;
  28. uint32_t g_max_keygen = 0;
  29. bool g_has_keyz = false;
  30. keyz_t g_keyz = {0};
  31. // no, these are no the actual keys.
  32. const uint8_t g_header_kek_src[0x10] = { 0x1F, 0x12, 0x91, 0x3A, 0x4A, 0xCB, 0xF0, 0x0D, 0x4C, 0xDE, 0x3A, 0xF6, 0xD5, 0x23, 0x88, 0x2A };
  33. const uint8_t g_header_key_src[0x20] = { 0x5A, 0x3E, 0xD8, 0x4F, 0xDE, 0xC0, 0xD8, 0x26, 0x31, 0xF7, 0xE2, 0x5D, 0x19, 0x7B, 0xF5, 0xD0, 0x1C, 0x9B, 0x7B, 0xFA, 0xF6, 0x28, 0x18, 0x3D, 0x71, 0xF6, 0x4D, 0x73, 0xF1, 0x50, 0xB9, 0xD2 };
  34. // neither are these.
  35. const uint8_t g_keak_application_source[0x10] = { 0x7F, 0x59, 0x97, 0x1E, 0x62, 0x9F, 0x36, 0xA1, 0x30, 0x98, 0x06, 0x6F, 0x21, 0x44, 0xC3, 0x0D };
  36. const uint8_t g_keak_ocean_source[0x10] = { 0x32, 0x7D, 0x36, 0x08, 0x5A, 0xD1, 0x75, 0x8D, 0xAB, 0x4E, 0x6F, 0xBA, 0xA5, 0x55, 0xD8, 0x82 };
  37. const uint8_t g_keak_system_source[0x10] = { 0x87, 0x45, 0xF1, 0xBB, 0xA6, 0xBE, 0x79, 0x64, 0x7D, 0x04, 0x8B, 0xA6, 0x7B, 0x5F, 0xDA, 0x4A };
  38. // nor is this.
  39. const uint8_t g_titlekey_source[0x10] = { 0x1e, 0xdc, 0x7b, 0x3b, 0x60, 0xe6, 0xb4, 0xd8, 0x78, 0xb8, 0x17, 0x15, 0x98, 0x5e, 0x62, 0x9b };
  40. bool parse_keys(void);
  41. bool init_crypto(void)
  42. {
  43. if (R_FAILED(splCryptoInitialize()))
  44. {
  45. return false;
  46. }
  47. // generate header kek.
  48. if (R_FAILED(splCryptoGenerateAesKek(g_header_kek_src, 0, 0, HEADER_KEK)))
  49. {
  50. return false;
  51. }
  52. // gen header key 0.
  53. if (R_FAILED(splCryptoGenerateAesKey(HEADER_KEK, g_header_key_src, HEADER_KEY_0)))
  54. {
  55. return false;
  56. }
  57. // gen header key 1.
  58. if (R_FAILED(splCryptoGenerateAesKey(HEADER_KEK, g_header_key_src + 0x10, HEADER_KEY_1)))
  59. {
  60. return false;
  61. }
  62. // parse keys file.
  63. g_has_keyz = parse_keys();
  64. // get HOS keygen.
  65. g_max_keygen = fs_get_key_gen_from_boot0();
  66. return true;
  67. }
  68. void exit_crypto(void)
  69. {
  70. splCryptoExit();
  71. }
  72. uint32_t crypto_get_sys_key_gen(void)
  73. {
  74. return g_max_keygen;
  75. }
  76. uint32_t crypto_get_highest_key_gen(NcaKeyAreaEncryptionKeyIndex index)
  77. {
  78. return g_keyz.keak[index].total > g_max_keygen ? g_keyz.keak[index].total : g_max_keygen;
  79. }
  80. bool crypto_has_key_gen(NcaKeyAreaEncryptionKeyIndex index, uint32_t key_gen)
  81. {
  82. return key_gen <= crypto_get_highest_key_gen(index);
  83. }
  84. bool crypto_has_keys_file(void)
  85. {
  86. return g_has_keyz;
  87. }
  88. bool crypto_has_key_gen_from_keys(NcaKeyAreaEncryptionKeyIndex index, uint8_t key_gen)
  89. {
  90. if (!crypto_has_keys_file() || index > NcaKeyAreaEncryptionKeyIndex_System || key_gen > KEYGEN_LIMIT)
  91. {
  92. write_log("missing params in %s\n", __func__);
  93. return false;
  94. }
  95. return key_gen <= g_keyz.keak[index].total;
  96. }
  97. const uint8_t *crypto_get_keak_from_keys(NcaKeyAreaEncryptionKeyIndex index, uint8_t key_gen)
  98. {
  99. if (!crypto_has_key_gen_from_keys(index, key_gen))
  100. {
  101. return NULL;
  102. }
  103. if (key_gen) key_gen--;
  104. #ifdef DEBUG
  105. write_log("\n keygen: %u got key: ", key_gen);
  106. for (int i = 0; i < sizeof(NcaKeyArea_t); i++)
  107. {
  108. write_log("%X", g_keyz.keak[index].key[key_gen].area[i]);
  109. }
  110. write_log("\n");
  111. #endif
  112. return g_keyz.keak[index].key[key_gen].area;
  113. }
  114. const uint8_t *crypto_get_titlekek_from_keys(uint8_t key_gen)
  115. {
  116. if (!crypto_has_keys_file() || key_gen > KEYGEN_LIMIT || g_keyz.title_key.total < key_gen)
  117. {
  118. return NULL;
  119. }
  120. if (key_gen) key_gen--;
  121. #ifdef DEBUG
  122. write_log("\n keygen: %u got key: ", key_gen);
  123. for (int i = 0; i < sizeof(NcaKeyArea_t); i++)
  124. {
  125. write_log("%X", g_keyz.title_key.key[key_gen].area[i]);
  126. }
  127. write_log("\n");
  128. #endif
  129. return g_keyz.title_key.key[key_gen].area;
  130. }
  131. size_t __get_file_size(FILE *fp)
  132. {
  133. if (!fp) return 0;
  134. size_t off = ftell(fp);
  135. fseek(fp, 0, SEEK_END);
  136. size_t size = ftell(fp);
  137. fseek(fp, off, SEEK_SET);
  138. return size;
  139. }
  140. bool find_keys_file(char **out, size_t *out_size)
  141. {
  142. if (!out || !out_size)
  143. {
  144. write_log("missing params in %s\n", __func__);
  145. return false;
  146. }
  147. const char *KEY_PATHS[] =
  148. {
  149. // default
  150. "sdmc:/switch/prod.keys",
  151. "sdmc:/switch/keys.txt",
  152. "sdmc:/switch/gamecard_installer/prod.keys",
  153. "sdmc:/switch/gamecard_installer/keys.txt",
  154. };
  155. FILE *fp = {0};
  156. for (uint8_t i = 0; i < 4; i++)
  157. {
  158. fp = fopen(KEY_PATHS[i], "rb");
  159. if (fp)
  160. {
  161. *out_size = __get_file_size(fp) + 1;
  162. if (*out_size > 0x800000) // way too big to be a simple keys file. lets not load that.
  163. {
  164. write_log("keys file is way too large: %lu\n", *out_size);
  165. fclose(fp);
  166. return false;
  167. }
  168. *out = calloc(1, *out_size);
  169. if (!(*out))
  170. {
  171. fclose(fp);
  172. return false;
  173. }
  174. fread(*out, *out_size - 1, 1, fp);
  175. fclose(fp);
  176. return true;
  177. }
  178. }
  179. return false;
  180. }
  181. bool parse_hex_key(NcaKeyArea_t *keak, const char *hex, uint32_t len)
  182. {
  183. if (!keak || !hex)
  184. {
  185. write_log("missing params in %s\n", __func__);
  186. return false;
  187. }
  188. char low[0x11] = {0};
  189. char upp[0x11] = {0};
  190. memcpy(low, hex, 0x10);
  191. memcpy(upp, hex + 0x10, 0x10);
  192. *(uint64_t *)keak->area = __bswap64(strtoul(low, NULL, 0x10));
  193. *(uint64_t *)(keak->area + 8) = __bswap64(strtoul(upp, NULL, 0x10));
  194. return true;
  195. }
  196. void find_keys_in_file(char *loaded_file, const char *search_key, KeySection_t *key_section)
  197. {
  198. if (!loaded_file || !search_key || !key_section)
  199. {
  200. write_log("missing params in %s\n", __func__);
  201. return;
  202. }
  203. char *ed = loaded_file;
  204. char parse_string[0x100] = {0};
  205. uint8_t skip = strlen(search_key) + 2 + 3; // two extra hex + 2 spaces and =.
  206. for (uint8_t i = 0; i < KEYGEN_LIMIT; i++)
  207. {
  208. sprintf(parse_string, "%s%02x", search_key, i);
  209. if (!(ed = strstr(ed, parse_string)))
  210. break;
  211. ed += skip;
  212. write_log("found %s: %.32s\n", parse_string, ed);
  213. parse_hex_key(&key_section->key[i], ed, sizeof(NcaKeyArea_t));
  214. ed += (sizeof(NcaKeyArea_t) * 2) + 1;
  215. key_section->total++;
  216. }
  217. }
  218. bool parse_keys(void)
  219. {
  220. // find keys.
  221. char *buf = {0};
  222. size_t size = 0;
  223. if (!find_keys_file(&buf, &size))
  224. {
  225. return false;
  226. }
  227. const char *key_text_keak_app = "key_area_key_application_";
  228. const char *key_text_keak_oce = "key_area_key_ocean_";
  229. const char *key_text_keak_sys = "key_area_key_system_";
  230. const char *key_text_title_kek = "titlekek_";
  231. const char *key_text_mkey = "master_key_";
  232. find_keys_in_file(buf, key_text_keak_app, &g_keyz.keak[NcaKeyAreaEncryptionKeyIndex_Application]);
  233. find_keys_in_file(buf, key_text_keak_oce, &g_keyz.keak[NcaKeyAreaEncryptionKeyIndex_Ocean]);
  234. find_keys_in_file(buf, key_text_keak_sys, &g_keyz.keak[NcaKeyAreaEncryptionKeyIndex_System]);
  235. find_keys_in_file(buf, key_text_title_kek, &g_keyz.title_key);
  236. find_keys_in_file(buf, key_text_mkey, &g_keyz.mkey);
  237. free(buf);
  238. return true;
  239. }
  240. const uint8_t *crypto_return_keak_source(NcaKeyAreaEncryptionKeyIndex index)
  241. {
  242. switch (index)
  243. {
  244. case NcaKeyAreaEncryptionKeyIndex_Application:
  245. return g_keak_application_source;
  246. case NcaKeyAreaEncryptionKeyIndex_Ocean:
  247. return g_keak_ocean_source;
  248. case NcaKeyAreaEncryptionKeyIndex_System:
  249. return g_keak_system_source;
  250. default:
  251. return NULL;
  252. }
  253. }
  254. void *crypto_aes(const void *in, void *out, const uint8_t *key, EncryptMode mode)
  255. {
  256. Aes128Context ctx = {0};
  257. aes128ContextCreate(&ctx, key, mode);
  258. switch (mode)
  259. {
  260. case EncryptMode_Decrypt:
  261. {
  262. aes128DecryptBlock(&ctx, out, in);
  263. break;
  264. }
  265. case EncryptMode_Encrypt:
  266. {
  267. aes128EncryptBlock(&ctx, out, in);
  268. break;
  269. }
  270. }
  271. return out;
  272. }
  273. void *crypto_aes_ctr(const void *in, void *out, const uint8_t *key, uint8_t *counter, size_t size, uint64_t offset)
  274. {
  275. Aes128CtrContext ctx = {0};
  276. aes128CtrContextCreate(&ctx, key, counter);
  277. uint64_t swp = __bswap64(offset >> 4);
  278. memcpy(&counter[0x8], &swp, 0x8);
  279. aes128CtrContextResetCtr(&ctx, counter);
  280. aes128CtrCrypt(&ctx, out, in, size);
  281. return out;
  282. }
  283. void *crypto_aes_cbc(const void *in, void *out, const uint8_t *key, size_t size, void *iv, EncryptMode mode)
  284. {
  285. Aes128CbcContext ctx = {0};
  286. aes128CbcContextCreate(&ctx, key, iv, mode);
  287. aes128CbcContextResetIv(&ctx, iv);
  288. switch (mode)
  289. {
  290. case EncryptMode_Decrypt:
  291. {
  292. aes128CbcDecrypt(&ctx, out, in, size);
  293. break;
  294. }
  295. case EncryptMode_Encrypt:
  296. {
  297. aes128CbcEncrypt(&ctx, out, in, size);
  298. break;
  299. }
  300. }
  301. return out;
  302. }
  303. void *crypto_aes_xts(const void *in, void *out, const uint8_t *key0, const uint8_t *key1, uint64_t sector, size_t sector_size, size_t data_size, EncryptMode mode)
  304. {
  305. Aes128XtsContext ctx = {0};
  306. aes128XtsContextCreate(&ctx, key0, key1, mode);
  307. for (uint64_t pos = 0; pos < data_size; pos += sector_size)
  308. {
  309. aes128XtsContextResetSector(&ctx, sector++, true);
  310. switch (mode)
  311. {
  312. case EncryptMode_Decrypt:
  313. {
  314. aes128XtsDecrypt(&ctx, (uint8_t*)out + pos, (const uint8_t*)in + pos, sector_size);
  315. break;
  316. }
  317. case EncryptMode_Encrypt:
  318. {
  319. aes128XtsEncrypt(&ctx, (uint8_t*)out + pos, (const uint8_t*)in + pos, sector_size);
  320. break;
  321. }
  322. }
  323. }
  324. return out;
  325. }