diff --git a/Makefile b/Makefile index cf556bb8..08036c12 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ include $(DEVKITPRO)/libnx/switch_rules VERSION_MAJOR := 1 VERSION_MINOR := 1 -VERSION_MICRO := 10 +VERSION_MICRO := 11 APP_TITLE := nxdumptool APP_AUTHOR := DarkMatterCore diff --git a/README.md b/README.md index ea5fd36c..c74f9ccc 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,14 @@ Thanks to Changelog -------------- +**v1.1.11:** + +* Built using libnx `f01fb21`. +* The application will now only attempt to decrypt the eTicket device RSA keypair if the target title uses a ticket with personalized titlekey crypto, instead of always decrypting it regardless of the ticket crypto type. +* Fixed a NSP dumping issue where the decrypted titlekey wasn't being set for the current NCA if both the ticket and the decrypted titlekey were retrieved while parsing a previous NCA. Big thanks to [sadboys2001](https://github.com/sadboys2001) for reporting it. + +This is only a bugfix release. I don't expect to release any new versions until the rewrite is finished - the only exception being fixing some kind of feature-breaking bug. Please understand. + **v1.1.10:** * Built using libnx v3.1.0. diff --git a/source/keys.c b/source/keys.c index 2d342947..b4a08fec 100644 --- a/source/keys.c +++ b/source/keys.c @@ -930,6 +930,7 @@ int retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_en if (!foundRightsId || (rightsIdType != 1 && rightsIdType != 2)) { uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: NCA rights ID unavailable in this console!", __func__); + breaks++; ret = -2; return ret; } @@ -937,52 +938,55 @@ int retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_en // Load external keys if (!loadExternalKeys()) return ret; - if (!setcal_eticket_retrieved) + if (rightsIdType == 2) { - // Get extended eTicket RSA key from PRODINFO - memset(&eticket_data, 0, sizeof(SetCalRsa2048DeviceKey)); - - result = setcalInitialize(); - if (R_FAILED(result)) + if (!setcal_eticket_retrieved) { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to initialize the set:cal service! (0x%08X)", __func__, result); - return ret; - } - - result = setcalGetEticketDeviceKey(&eticket_data); - - setcalExit(); - - if (R_FAILED(result)) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: setcalGetEticketDeviceKey failed! (0x%08X)", __func__, result); - return ret; + // Get extended eTicket RSA key from PRODINFO + memset(&eticket_data, 0, sizeof(SetCalRsa2048DeviceKey)); + + result = setcalInitialize(); + if (R_FAILED(result)) + { + uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to initialize the set:cal service! (0x%08X)", __func__, result); + return ret; + } + + result = setcalGetEticketDeviceKey(&eticket_data); + + setcalExit(); + + if (R_FAILED(result)) + { + uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: setcalGetEticketDeviceKey failed! (0x%08X)", __func__, result); + return ret; + } + + // Decrypt eTicket RSA key + memcpy(ctr, eticket_data.key, ETICKET_DEVKEY_RSA_CTR_SIZE); + aes128CtrContextCreate(&eticket_aes_ctx, nca_keyset.eticket_rsa_kek, ctr); + aes128CtrCrypt(&eticket_aes_ctx, eticket_data.key + ETICKET_DEVKEY_RSA_OFFSET, eticket_data.key + ETICKET_DEVKEY_RSA_OFFSET, ETICKET_DEVKEY_RSA_SIZE); + + // Public exponent must use RSA-2048 SHA-1 signature method + // The value is stored use big endian byte order + if (__builtin_bswap32(*((u32*)(eticket_data.key + ETICKET_DEVKEY_RSA_OFFSET + 0x200))) != SIGTYPE_RSA2048_SHA1) + { + uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid public RSA exponent for eTicket data! Wrong keys?\nTry running Lockpick_RCM to generate the keys file from scratch.", __func__); + return ret; + } } - // Decrypt eTicket RSA key - memcpy(ctr, eticket_data.key, ETICKET_DEVKEY_RSA_CTR_SIZE); - aes128CtrContextCreate(&eticket_aes_ctx, nca_keyset.eticket_rsa_kek, ctr); - aes128CtrCrypt(&eticket_aes_ctx, eticket_data.key + ETICKET_DEVKEY_RSA_OFFSET, eticket_data.key + ETICKET_DEVKEY_RSA_OFFSET, ETICKET_DEVKEY_RSA_SIZE); + D = (eticket_data.key + ETICKET_DEVKEY_RSA_OFFSET); + N = (eticket_data.key + ETICKET_DEVKEY_RSA_OFFSET + 0x100); + E = (eticket_data.key + ETICKET_DEVKEY_RSA_OFFSET + 0x200); - // Public exponent must use RSA-2048 SHA-1 signature method - // The value is stored use big endian byte order - if (__builtin_bswap32(*((u32*)(eticket_data.key + ETICKET_DEVKEY_RSA_OFFSET + 0x200))) != SIGTYPE_RSA2048_SHA1) + if (!setcal_eticket_retrieved) { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid public RSA exponent for eTicket data! Wrong keys?\nTry running Lockpick_RCM to generate the keys file from scratch.", __func__); - return ret; + if (!testKeyPair(E, D, N)) return ret; + setcal_eticket_retrieved = true; } } - D = (eticket_data.key + ETICKET_DEVKEY_RSA_OFFSET); - N = (eticket_data.key + ETICKET_DEVKEY_RSA_OFFSET + 0x100); - E = (eticket_data.key + ETICKET_DEVKEY_RSA_OFFSET + 0x200); - - if (!setcal_eticket_retrieved) - { - if (!testKeyPair(E, D, N)) return ret; - setcal_eticket_retrieved = true; - } - eTicketSave = calloc(1, sizeof(FIL)); if (!eTicketSave) { @@ -1122,6 +1126,7 @@ int retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_en if (!foundEticket) { uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to find a matching eTicket entry for NCA rights ID!", __func__); + breaks++; ret = -2; return ret; } diff --git a/source/nca.c b/source/nca.c index 3f82d2cd..36a3696d 100644 --- a/source/nca.c +++ b/source/nca.c @@ -837,7 +837,13 @@ bool retrieveTitleKeyFromGameCardTicket(title_rights_ctx *rights_info, u8 *decry } // Check if the ticket has already been retrieved from the HFS0 partition in the gamecard - if (rights_info->retrieved_tik) return true; + if (rights_info->retrieved_tik) + { + // Save the decrypted NCA key area keys + memset(decrypted_nca_keys, 0, NCA_KEY_AREA_SIZE); + memcpy(decrypted_nca_keys + (NCA_KEY_AREA_KEY_SIZE * 2), rights_info->dec_titlekey, 0x10); + return true; + } // Load external keys if (!loadExternalKeys()) return false; diff --git a/source/util.c b/source/util.c index ecc75ce7..06e0787a 100644 --- a/source/util.c +++ b/source/util.c @@ -908,7 +908,7 @@ static bool initServices() initPmdmnt = true; /* Initialize pl service */ - result = plInitialize(); + result = plInitialize(PlServiceType_User); if (R_FAILED(result)) { consoleErrorScreen("%s: failed to initialize pl service! (0x%08X)", __func__, result);