nca.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964
  1. #include <stdio.h>
  2. #include <stdbool.h>
  3. #include <stdint.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <threads.h>
  7. #include <switch.h>
  8. #include "nx/nca.h"
  9. #include "nx/ncm.h"
  10. #include "nx/fs.h"
  11. #include "nx/crypto.h"
  12. #include "ui/menu.h"
  13. #include "ui/settings.h"
  14. #include "util/file.h"
  15. #include "util/log.h"
  16. #define BUFFER_SIZE 0x800000
  17. mtx_t nca_mtx = {0};
  18. cnd_t can_read = {0};
  19. cnd_t can_write = {0};
  20. typedef struct
  21. {
  22. FILE *fp;
  23. uint8_t *data;
  24. uint64_t offset;
  25. size_t data_size;
  26. size_t data_read;
  27. size_t data_written;
  28. size_t total_size;
  29. NcmInstall_t ncm;
  30. } NcaInstall_t;
  31. NcaKeySlot_t KEYSLOT = {0};
  32. bool nca_set_keyslot(uint64_t id, const uint8_t *key)
  33. {
  34. if (!id || !key)
  35. {
  36. write_log("missing params in %s\n", __func__);
  37. return false;
  38. }
  39. // reset to 0.
  40. memset(&KEYSLOT, 0, sizeof(NcaKeySlot_t));
  41. // set new values.
  42. KEYSLOT.id = id;
  43. memcpy(KEYSLOT.key.area, key, 0x10);
  44. return true;
  45. }
  46. NcaKeySlot_t *nca_get_keyslot(void)
  47. {
  48. return &KEYSLOT;
  49. }
  50. NcaKeyArea_t *nca_get_keyslot_key(void)
  51. {
  52. return &KEYSLOT.key;
  53. }
  54. uint64_t nca_get_keyslot_id(void)
  55. {
  56. return KEYSLOT.id;
  57. }
  58. bool nca_check_if_magic_valid(uint32_t magic)
  59. {
  60. switch (magic)
  61. {
  62. case NCA0_MAGIC:
  63. return true;
  64. case NCA2_MAGIC:
  65. return true;
  66. case NCA3_MAGIC:
  67. return true;
  68. default:
  69. return false;
  70. }
  71. }
  72. const char *nca_get_magic_string(uint32_t magic)
  73. {
  74. switch (magic)
  75. {
  76. case NCA0_MAGIC:
  77. return "NCA0";
  78. case NCA2_MAGIC:
  79. return "NCA1";
  80. case NCA3_MAGIC:
  81. return "NCA3";
  82. default:
  83. return "NULL";
  84. }
  85. }
  86. const char *nca_get_distribution_type_string(NcaDistributionType type)
  87. {
  88. switch (type)
  89. {
  90. case NcaDistributionType_System:
  91. return "System";
  92. case NcaDistributionType_GameCard:
  93. return "GameCard";
  94. default:
  95. return "NULL";
  96. }
  97. }
  98. const char *nca_get_content_type_string(NcaContentType type)
  99. {
  100. switch (type)
  101. {
  102. case NcaContentType_Program:
  103. return "Program";
  104. case NcaContentType_Meta:
  105. return "Meta";
  106. case NcaContentType_Control:
  107. return "Control";
  108. case NcaContentType_Manual:
  109. return "Manual";
  110. case NcaContentType_Data:
  111. return "Data";
  112. case NcaContentType_PublicData:
  113. return "PublicData";
  114. default:
  115. return "NULL";
  116. }
  117. }
  118. const char *nca_get_keak_index_string(NcaKeyAreaEncryptionKeyIndex index)
  119. {
  120. switch (index)
  121. {
  122. case NcaKeyAreaEncryptionKeyIndex_Application:
  123. return "Application";
  124. case NcaKeyAreaEncryptionKeyIndex_Ocean:
  125. return "Ocean";
  126. case NcaKeyAreaEncryptionKeyIndex_System:
  127. return "System";
  128. default:
  129. return "NULL";
  130. }
  131. }
  132. const char *nca_get_file_system_type_string(NcaFileSystemType type)
  133. {
  134. switch (type)
  135. {
  136. case NcaFileSystemType_RomFS:
  137. return "RomFS";
  138. case NcaFileSystemType_PFS0:
  139. return "PFS0";
  140. default:
  141. return "NULL";
  142. }
  143. }
  144. const char *nca_get_hash_type_string(NcaHashType type)
  145. {
  146. switch (type)
  147. {
  148. case NcaHashType_Auto:
  149. return "Auto";
  150. case NcaHashType_HierarchicalSha256:
  151. return "HierarchicalSha256";
  152. case NcaHashType_HierarchicalIntegrity:
  153. return "HierarchicalIntegrity";
  154. default:
  155. return "NULL";
  156. }
  157. }
  158. const char *nca_get_encryption_type_string(NcaEncryptionType type)
  159. {
  160. switch (type)
  161. {
  162. case NcaEncryptionType_Auto:
  163. return "Auto";
  164. case NcaEncryptionType_None:
  165. return "None";
  166. case NcaEncryptionType_AesCtrOld:
  167. return "AesCtrOld";
  168. case NcaEncryptionType_AesCtr:
  169. return "AesCtr";
  170. case NcaEncryptionType_AesCtrEx:
  171. return "AesCtrEx";
  172. default:
  173. return "NULL";
  174. }
  175. }
  176. const char *nca_return_key_gen_string(uint8_t key_gen)
  177. {
  178. switch (key_gen)
  179. {
  180. case NcaOldKeyGeneration_100:
  181. return "1.0.0";
  182. case NcaOldKeyGeneration_Unused:
  183. return "Unused";
  184. case NcaOldKeyGeneration_300:
  185. return "3.0.0";
  186. case NcaKeyGeneration_301:
  187. return "3.0.1";
  188. case NcaKeyGeneration_400:
  189. return "4.0.0";
  190. case NcaKeyGeneration_500:
  191. return "5.0.0";
  192. case NcaKeyGeneration_600:
  193. return "6.0.0";
  194. case NcaKeyGeneration_620:
  195. return "6.2.0";
  196. case NcaKeyGeneration_700:
  197. return "7.0.0";
  198. case NcaKeyGeneration_810:
  199. return "8.1.0";
  200. case NcaKeyGeneration_900:
  201. return "9.0.0";
  202. case NcaKeyGeneration_910:
  203. return "9.1.0";
  204. case NcaKeyGeneration_1210:
  205. return "12.1.0";
  206. case NcaKeyGeneration_1300:
  207. return "13.0.0";
  208. case NcaKeyGeneration_1400:
  209. return "14.0.0";
  210. case NcaKeyGeneration_1500:
  211. return "15.0.0";
  212. case NcaKeyGeneration_Invalid:
  213. return "Invalid";
  214. default:
  215. return "UNKNOWN";
  216. }
  217. }
  218. uint16_t nca_return_key_gen_int(uint8_t key_gen)
  219. {
  220. switch (key_gen)
  221. {
  222. case NcaOldKeyGeneration_100:
  223. return 100;
  224. case NcaOldKeyGeneration_Unused:
  225. return 100;
  226. case NcaOldKeyGeneration_300:
  227. return 300;
  228. case NcaKeyGeneration_301:
  229. return 301;
  230. case NcaKeyGeneration_400:
  231. return 400;
  232. case NcaKeyGeneration_500:
  233. return 500;
  234. case NcaKeyGeneration_600:
  235. return 600;
  236. case NcaKeyGeneration_620:
  237. return 620;
  238. case NcaKeyGeneration_700:
  239. return 700;
  240. case NcaKeyGeneration_810:
  241. return 810;
  242. case NcaKeyGeneration_900:
  243. return 900;
  244. case NcaKeyGeneration_910:
  245. return 910;
  246. case NcaKeyGeneration_1210:
  247. return 1210;
  248. case NcaKeyGeneration_1300:
  249. return 1300;
  250. case NcaKeyGeneration_1400:
  251. return 1400;
  252. case NcaKeyGeneration_1500:
  253. return 1500;
  254. case NcaKeyGeneration_Invalid:
  255. return UINT16_MAX;
  256. default:
  257. return 0;
  258. }
  259. }
  260. const char *nca_get_string_from_id(const NcmContentId *nca_id, char *out)
  261. {
  262. uint64_t nca_id_lower = __bswap64(*(uint64_t *)nca_id->c);
  263. uint64_t nca_id_upper = __bswap64(*(uint64_t *)(nca_id->c + 0x8));
  264. snprintf(out, 0x21, "%016lx%016lx", nca_id_lower, nca_id_upper);
  265. return out;
  266. }
  267. const NcmContentId nca_get_id_from_string(const char *nca_in_string)
  268. {
  269. NcmContentId nca_id = {0};
  270. char lowerU64[0x11] = {0};
  271. char upperU64[0x11] = {0};
  272. memcpy(lowerU64, nca_in_string, 0x10);
  273. memcpy(upperU64, nca_in_string + 0x10, 0x10);
  274. *(uint64_t *)nca_id.c = __bswap64(strtoul(lowerU64, NULL, 0x10));
  275. *(uint64_t *)(nca_id.c + 8) = __bswap64(strtoul(upperU64, NULL, 0x10));
  276. return nca_id;
  277. }
  278. bool nca_encrypt_header(const NcaHeader_t *in_header, NcaHeader_t *out_header)
  279. {
  280. if (!in_header || !out_header)
  281. {
  282. write_log("empty params in %s\n", __func__);
  283. return false;
  284. }
  285. if (!crypto_aes_xts(in_header, out_header, HEADER_KEY_0, HEADER_KEY_1, 0, NCA_SECTOR_SIZE, NCA_XTS_SECTION_SIZE, EncryptMode_Encrypt))
  286. {
  287. return false;
  288. }
  289. return true;
  290. }
  291. bool nca_decrypt_header(const NcaHeader_t *in_header, NcaHeader_t *out_header)
  292. {
  293. if (!in_header || !out_header)
  294. {
  295. write_log("empty params in %s\n", __func__);
  296. return false;
  297. }
  298. if (!crypto_aes_xts(in_header, out_header, HEADER_KEY_0, HEADER_KEY_1, 0, NCA_SECTOR_SIZE, NCA_XTS_SECTION_SIZE, EncryptMode_Decrypt))
  299. {
  300. write_log("failed to decrypt nac header\n");
  301. return false;
  302. }
  303. return true;
  304. }
  305. bool nca_get_header(FILE *fp, uint64_t offset, NcaHeader_t *header)
  306. {
  307. if (!fp || !header)
  308. {
  309. write_log("missing params in %s\n", __func__);
  310. return false;
  311. }
  312. return read_file(header, NCA_XTS_SECTION_SIZE, offset, fp) == NCA_XTS_SECTION_SIZE;
  313. }
  314. bool nca_get_header_decrypted(FILE *fp, uint64_t offset, NcaHeader_t *header)
  315. {
  316. if (!fp || !header)
  317. {
  318. write_log("missing params in %s\n", __func__);
  319. return false;
  320. }
  321. if (!nca_get_header(fp, offset, header))
  322. {
  323. return false;
  324. }
  325. return nca_decrypt_header(header, header);
  326. }
  327. bool nca_has_rights_id(const FsRightsId *rights_id)
  328. {
  329. if (!rights_id)
  330. {
  331. write_log("empty param in %s\n", __func__);
  332. return false;
  333. }
  334. for (uint8_t i = 0; i < sizeof(FsRightsId); i++)
  335. {
  336. if (rights_id->c[i])
  337. {
  338. return true;
  339. }
  340. }
  341. return false;
  342. }
  343. bool nca_set_rights_id(FsRightsId *rights_id)
  344. {
  345. if (!rights_id)
  346. {
  347. write_log("missing args in %s\n", __func__);
  348. return false;
  349. }
  350. for (uint8_t i = 0; i < sizeof(FsRightsId); i++)
  351. {
  352. rights_id->c[i] = 0x0;
  353. }
  354. return true;
  355. }
  356. void nca_set_distribution_type(NcaHeader_t *header)
  357. {
  358. if (!header)
  359. {
  360. write_log("empty param in %s\n", __func__);
  361. return;
  362. }
  363. header->distribution_type = NcaDistributionType_System;
  364. }
  365. /*
  366. * nca install stuff.
  367. */
  368. int nca_read(void *in)
  369. {
  370. NcaInstall_t *t = (NcaInstall_t *)in;
  371. if (!t)
  372. {
  373. write_log("missing params in %s\n", __func__);
  374. return -1;
  375. }
  376. void *buf = calloc(1, BUFFER_SIZE);
  377. if (!buf)
  378. {
  379. write_log("failed to alloc buffer in %s\n", __func__);
  380. return -1;
  381. }
  382. for (uint64_t done = t->data_written, bufsize = BUFFER_SIZE; done < t->total_size; done += bufsize, t->offset += bufsize)
  383. {
  384. if (done + bufsize > t->total_size)
  385. bufsize = t->total_size - done;
  386. read_file(buf, bufsize, t->offset, t->fp);
  387. mtx_lock(&nca_mtx);
  388. if (t->data_size != 0)
  389. {
  390. cnd_wait(&can_read, &nca_mtx);
  391. }
  392. memcpy(t->data, buf, bufsize);
  393. t->data_size = bufsize;
  394. mtx_unlock(&nca_mtx);
  395. cnd_signal(&can_write);
  396. }
  397. free(buf);
  398. return 0;
  399. }
  400. int nca_write(void *in)
  401. {
  402. NcaInstall_t *t = (NcaInstall_t *)in;
  403. if (!t)
  404. {
  405. write_log("missing params in %s\n", __func__);
  406. return -1;
  407. }
  408. while (t->data_written < t->total_size)
  409. {
  410. mtx_lock(&nca_mtx);
  411. if (t->data_size == 0)
  412. {
  413. cnd_wait(&can_write, &nca_mtx);
  414. }
  415. if (!ncm_write_placeholder_id(&t->ncm.storage, &t->ncm.placeholder_id, t->data_written, t->data, t->data_size))
  416. {
  417. return -1;
  418. }
  419. t->data_written += t->data_size;
  420. t->data_size = 0;
  421. mtx_unlock(&nca_mtx);
  422. cnd_signal(&can_read);
  423. }
  424. return 0;
  425. }
  426. bool nca_setup_placeholder_id(NcmInstall_t *out, size_t size, const NcmContentId *content_id, NcmStorageId storage_id)
  427. {
  428. // open ncm storage.
  429. if (!ncm_open_storage(&out->storage, storage_id))
  430. {
  431. return false;
  432. }
  433. // generate a placeholder id.
  434. if (!ncm_generate_placeholder_id(&out->storage, &out->placeholder_id))
  435. {
  436. ncm_close_storage(&out->storage);
  437. return false;
  438. }
  439. // check if the placeholder exists, delete if found.
  440. if (ncm_check_if_placeholder_id_exists(&out->storage, &out->placeholder_id))
  441. {
  442. if (!ncm_delete_placeholder_id(&out->storage, &out->placeholder_id))
  443. {
  444. ncm_close_storage(&out->storage);
  445. return false;
  446. }
  447. }
  448. // finally create placeholder.
  449. if (!ncm_create_placeholder_id(&out->storage, memcpy(&out->content_id, content_id, sizeof(NcmContentId)), &out->placeholder_id, size))
  450. {
  451. ncm_close_storage(&out->storage);
  452. return false;
  453. }
  454. return true;
  455. }
  456. void nca_update_lower_ctr(uint8_t *ctr, uint64_t offset)
  457. {
  458. if (!ctr)
  459. {
  460. write_log("missing params in %s\n", __func__);
  461. return;
  462. }
  463. uint64_t swp = __bswap64(offset);
  464. memcpy(ctr, &swp, 0x8);
  465. }
  466. void nca_update_upper_ctr(uint8_t *ctr, uint64_t offset)
  467. {
  468. if (!ctr)
  469. {
  470. write_log("missing params in %s\n", __func__);
  471. return;
  472. }
  473. uint64_t swp = __bswap64(offset >> 4);
  474. memcpy(ctr + 0x8, &swp, 0x8);
  475. }
  476. bool nca_decrypt_section(const void *in, void *out, const NcaKeyArea_t *key, uint8_t *ctr, size_t size, uint64_t offset)
  477. {
  478. return true;
  479. }
  480. bool nca_read_encrypted(void *out, const NcaKeyArea_t *key, uint8_t *ctr, size_t size, uint64_t offset, FILE *fp)
  481. {
  482. fread(out, size, 1, fp);
  483. return nca_decrypt_section(out, out, key, ctr, size, offset);
  484. }
  485. bool __nca_decrypt_keak_keyz(const NcaHeader_t *header, NcaKeyArea_t *out, uint32_t key_gen)
  486. {
  487. write_log("using keys to decrypt keak\n");
  488. const uint8_t *keak = crypto_get_keak_from_keys(header->kaek_index, key_gen);
  489. if (!keak)
  490. {
  491. write_log("no return keak %s\n", __func__);
  492. return false;
  493. }
  494. // decrypt to get the key.
  495. NcaKeyArea_t decrypted_nca_keys[NCA_SECTION_TOTAL] = {0};
  496. Aes128Context ctx_dec = {0};
  497. aes128ContextCreate(&ctx_dec, keak, false);
  498. for (uint8_t i = 0; i < NCA_SECTION_TOTAL; i++)
  499. {
  500. aes128DecryptBlock(&ctx_dec, &decrypted_nca_keys[i], &header->key_area[i]);
  501. }
  502. nca_print_key_area(header->key_area);
  503. nca_print_key_area(decrypted_nca_keys);
  504. // copy decrypted key.
  505. memcpy(out, &decrypted_nca_keys[0x2], sizeof(NcaKeyArea_t));
  506. return true;
  507. }
  508. bool __nca_decrypt_keak_spl(const NcaHeader_t *header, NcaKeyArea_t *out, uint32_t key_gen)
  509. {
  510. write_log("using spl to decrypt keak\n");
  511. NcaKeyArea_t kek = {0};
  512. if (R_FAILED(splCryptoGenerateAesKek(crypto_return_keak_source(header->kaek_index), key_gen, 0, kek.area)))
  513. {
  514. write_log("failed to generate aea kek\n");
  515. return false;
  516. }
  517. NcaKeyArea_t decrypted_nca_keys[NCA_SECTION_TOTAL] = {0};
  518. for (uint8_t i = 0; i < NCA_SECTION_TOTAL; i++)
  519. {
  520. if (R_FAILED(splCryptoGenerateAesKey(kek.area, &header->key_area[i].area, &decrypted_nca_keys[i].area)))
  521. {
  522. write_log("failed to aes key %i %s\n", i, __func__);
  523. return false;
  524. }
  525. }
  526. nca_print_key_area(header->key_area);
  527. nca_print_key_area(decrypted_nca_keys);
  528. // copy decrypted key.
  529. memcpy(out, &decrypted_nca_keys[0x2], sizeof(NcaKeyArea_t));
  530. return true;
  531. }
  532. bool nca_decrypt_keak(const NcaHeader_t *header, NcaKeyArea_t *out)
  533. {
  534. if (!header || !out)
  535. {
  536. write_log("missing params in %s\n", __func__);
  537. return false;
  538. }
  539. // sort out the key gen.
  540. uint8_t key_gen = header->key_gen ? header->key_gen : header->old_key_gen;
  541. // check if we can use spl.
  542. if (crypto_get_sys_key_gen() >= key_gen)
  543. {
  544. return __nca_decrypt_keak_spl(header, out, key_gen);
  545. }
  546. else
  547. {
  548. return __nca_decrypt_keak_keyz(header, out, key_gen);
  549. }
  550. return true;
  551. }
  552. bool __nca_encrypt_keak_keyz(NcaHeader_t *header, const NcaKeyArea_t *decrypted_key, uint8_t key_gen)
  553. {
  554. if (!header || !decrypted_key)
  555. {
  556. write_log("missing params in %s\n", __func__);
  557. return false;
  558. }
  559. Aes128Context ctx = {0};
  560. NcaKeyArea_t decrypted_nca_keys[NCA_SECTION_TOTAL] = {0};
  561. memcpy(&decrypted_nca_keys[0x2].area, decrypted_key->area, sizeof(NcaKeyArea_t));
  562. const uint8_t *keak = crypto_get_keak_from_keys(header->kaek_index, key_gen);
  563. if (!keak)
  564. {
  565. return false;
  566. }
  567. aes128ContextCreate(&ctx, keak, true);
  568. for (uint8_t i = 0; i < NCA_SECTION_TOTAL; i++)
  569. {
  570. aes128EncryptBlock(&ctx, &header->key_area[i].area, &decrypted_nca_keys[i].area);
  571. }
  572. return true;
  573. }
  574. bool __nca_ecnrypt_keak_spl(NcaHeader_t *header, const NcaKeyArea_t *decrypted_key, uint8_t key_gen)
  575. {
  576. /*
  577. * TODO:
  578. */
  579. return true;
  580. }
  581. bool nca_encrypt_keak(NcaHeader_t *header, const NcaKeyArea_t *decrypted_key, uint8_t key_gen)
  582. {
  583. if (!header || !decrypted_key)
  584. {
  585. write_log("missing params in %s\n", __func__);
  586. return false;
  587. }
  588. if (!__nca_encrypt_keak_keyz(header, decrypted_key, key_gen))
  589. {
  590. return false;
  591. }
  592. // set the rights_id field.
  593. memset(&header->rights_id, 0, sizeof(FsRightsId));
  594. // update with new keygen version.
  595. if (key_gen > NcaOldKeyGeneration_300)
  596. {
  597. header->key_gen = key_gen;
  598. header->old_key_gen = NcaOldKeyGeneration_300;
  599. }
  600. else
  601. {
  602. header->key_gen = 0;
  603. header->old_key_gen = key_gen;
  604. }
  605. return true;
  606. }
  607. bool nca_start_install(const char *name, const NcmContentId *content_id, uint64_t offset, NcmStorageId storage_id, FILE *fp)
  608. {
  609. if (!content_id || !fp || !name)
  610. {
  611. write_log("missing params in %s\n", __func__);
  612. return false;
  613. }
  614. // this will be the thread that is passed to the read / write.
  615. NcaInstall_t nca = {0};
  616. nca.fp = fp;
  617. // next we need to get the header.
  618. NcaHeader_t *header = calloc(1, NCA_XTS_SECTION_SIZE);
  619. if (!header)
  620. {
  621. write_log("failed to malloc header\n");
  622. return false;
  623. }
  624. if (!nca_get_header_decrypted(nca.fp, offset, header))
  625. {
  626. write_log("failed to get nca header\n");
  627. free(header);
  628. return false;
  629. }
  630. nca_print_header(header);
  631. if (setting_get_install_lower_key_gen())
  632. {
  633. if (nca_has_rights_id(&header->rights_id))
  634. {
  635. if (!nca_encrypt_keak(header, nca_get_keyslot_key(), 0))
  636. {
  637. free(header);
  638. return false;
  639. }
  640. }
  641. else
  642. {
  643. NcaKeyArea_t keak = {0};
  644. if (!nca_decrypt_keak(header, &keak))
  645. {
  646. free(header);
  647. return false;
  648. }
  649. if (!nca_encrypt_keak(header, &keak, 0))
  650. {
  651. free(header);
  652. return false;
  653. }
  654. }
  655. }
  656. // now that we have the actual size of the nca, we can setup the placeholder.
  657. if (!nca_setup_placeholder_id(&nca.ncm, header->size, content_id, storage_id))
  658. {
  659. write_log("failed to setup placeholder\n");
  660. free(header);
  661. return false;
  662. }
  663. // we need to flip the distribution bit so that gamecards can be installed.
  664. nca_set_distribution_type(header);
  665. // now update the nca struct with the actual size of the nca.
  666. nca.total_size = header->size;
  667. // re encrypt the header.
  668. if (!nca_encrypt_header(header, header))
  669. {
  670. write_log("Failed to encrypt header\n");
  671. free(header);
  672. ncm_delete_placeholder_id(&nca.ncm.storage, &nca.ncm.placeholder_id);
  673. ncm_close_storage(&nca.ncm.storage);
  674. return false;
  675. }
  676. // now write the header to the placeholder.
  677. if (!ncm_write_placeholder_id(&nca.ncm.storage, &nca.ncm.placeholder_id, 0, header, NCA_XTS_SECTION_SIZE))
  678. {
  679. write_log("failed to write to placeholder\n");
  680. free(header);
  681. ncm_delete_placeholder_id(&nca.ncm.storage, &nca.ncm.placeholder_id);
  682. ncm_close_storage(&nca.ncm.storage);
  683. return false;
  684. }
  685. // update the struct with the amount of data written.
  686. nca.offset = offset + NCA_XTS_SECTION_SIZE;
  687. nca.data_written = NCA_XTS_SECTION_SIZE;
  688. // free the header as its not needed.
  689. free(header);
  690. // allocate memory that will be shared between the read and write threads. (memory is protected).
  691. nca.data = calloc(1, BUFFER_SIZE);
  692. if (!nca.data)
  693. {
  694. write_log("allocating nca buffer, size is: 0x%X\n", BUFFER_SIZE);
  695. return false;
  696. }
  697. // setup the 2 worker threads.
  698. mtx_init(&nca_mtx, mtx_plain);
  699. cnd_init(&can_read);
  700. cnd_init(&can_write);
  701. write_log("init mtx and cnd for nca threaded install\n");
  702. thrd_t t_read = {0};
  703. thrd_t t_write = {0};
  704. write_log("creating threads\n");
  705. thrd_create(&t_read, nca_read, &nca);
  706. thrd_create(&t_write, nca_write, &nca);
  707. write_log("created threads\n");
  708. // TODO: make this into a struct
  709. // also dont do ui stuff in nca
  710. // instead, just have a state system for the ui, then do a callback in nca with the progress.
  711. uint8_t prev_time = 0;
  712. uint64_t prev_size = 0;
  713. uint64_t speed = 0;
  714. uint32_t eta_min = 0;
  715. uint8_t eta_sec = 0;
  716. // init the progress bar.
  717. progress_bar_t *p_bar = ui_init_progress_bar(name, speed, eta_min, eta_sec, nca.data_written, nca.total_size);
  718. if (!p_bar)
  719. {
  720. write_log("Failed to init progress bar!\n");
  721. }
  722. // loop until file has finished installing.
  723. while (nca.data_written != nca.total_size)
  724. {
  725. time_t uinx_time = time(NULL);
  726. struct tm* time_struct = gmtime(&uinx_time);
  727. if (prev_time != time_struct->tm_sec)
  728. {
  729. prev_time = time_struct->tm_sec;
  730. size_t size = nca.data_written;
  731. speed = size - prev_size;
  732. eta_min = ((nca.total_size - size) / speed) / 60;
  733. eta_sec = ((nca.total_size - size) / speed) % 60;
  734. prev_size = size;
  735. ui_update_progress_bar(p_bar, speed, eta_min, eta_sec, nca.data_written, nca.total_size);
  736. }
  737. update_button_spin();
  738. ui_display_progress_bar(p_bar);
  739. thrd_yield();
  740. }
  741. ui_free_progress_bar(p_bar);
  742. int ret_read = 0;
  743. int ret_write = 0;
  744. write_log("Waiting to joing threads\n");
  745. thrd_join(t_read, &ret_read);
  746. thrd_join(t_write, &ret_write);
  747. write_log("joined threads\n");
  748. mtx_destroy(&nca_mtx);
  749. cnd_destroy(&can_read);
  750. cnd_destroy(&can_write);
  751. free(nca.data);
  752. // check if the threads were unsuccesful.
  753. if (ret_read == -1 || ret_write == -1)
  754. {
  755. write_log("threading error read: %d write: %d\n", ret_read, ret_write);
  756. ncm_delete_placeholder_id(&nca.ncm.storage, &nca.ncm.placeholder_id);
  757. ncm_close_storage(&nca.ncm.storage);
  758. return false;
  759. }
  760. // check if the ncas exists, if so, delete it.
  761. if (ncm_check_if_content_id_exists(&nca.ncm.storage, &nca.ncm.content_id))
  762. {
  763. write_log("nca seems to exist already, attempting to delete\n");
  764. if (!ncm_delete_content_id(&nca.ncm.storage, &nca.ncm.content_id))
  765. {
  766. write_log("failed to delete nca\n");
  767. ncm_delete_placeholder_id(&nca.ncm.storage, &nca.ncm.placeholder_id);
  768. ncm_close_storage(&nca.ncm.storage);
  769. return false;
  770. }
  771. write_log("deleted nca\n");
  772. }
  773. // register the placeholder.
  774. if (!ncm_register_placeholder_id(&nca.ncm.storage, &nca.ncm.content_id, &nca.ncm.placeholder_id))
  775. {
  776. write_log("failed to register placeholder\n");
  777. ncm_delete_placeholder_id(&nca.ncm.storage, &nca.ncm.placeholder_id);
  778. ncm_close_storage(&nca.ncm.storage);
  779. return false;
  780. }
  781. ncm_close_storage(&nca.ncm.storage);
  782. write_log("finished nca install\n\n");
  783. return true;
  784. }
  785. /*
  786. * Debug
  787. */
  788. void nca_print_header(const NcaHeader_t *header)
  789. {
  790. #ifdef DEBUG
  791. if (!header)
  792. {
  793. write_log("missing params in nca_print_header\n");
  794. return;
  795. }
  796. write_log("\nnca header print\n");
  797. write_log("magic: %s\n", nca_get_magic_string(header->magic));
  798. write_log("title_id: 0%lX\n", header->title_id);
  799. write_log("context_id: %u\n", header->context_id);
  800. write_log("header1sig: %u\n", header->header_1_sig_key_gen);
  801. write_log("size: %lu\n", header->size);
  802. write_log("sdk_version: %u\n", header->sdk_version);
  803. write_log("encryption_type: %s\n", nca_has_rights_id(&header->rights_id) ? "titlekey" : "standard crypto");
  804. write_log("content_type: %s\n", nca_get_content_type_string(header->content_type));
  805. write_log("distribution_type: %s\n", nca_get_distribution_type_string(header->distribution_type));
  806. write_log("keak_index: %s\n", nca_get_keak_index_string(header->kaek_index));
  807. write_log("key_gen: %u (%s)\n\n", header->key_gen ? header->key_gen : header->old_key_gen, nca_return_key_gen_string(header->key_gen ? header->key_gen : header->old_key_gen));
  808. #endif
  809. }
  810. void nca_print_key_area(const NcaKeyArea_t *keak)
  811. {
  812. #ifdef DEBUG
  813. if (!keak)
  814. {
  815. write_log("missing params in keak\n");
  816. return;
  817. }
  818. write_log("\nprinting keak\n");
  819. for (uint8_t i = 0; i < 4; i++)
  820. {
  821. for (uint8_t j = 0; j < 0x10; j++)
  822. {
  823. write_log("%x", keak[i].area[j]);
  824. }
  825. write_log("\n");
  826. }
  827. #endif
  828. }