diff --git a/arm9/src/tad.c b/arm9/src/tad.c index f4a23e1..86e4acc 100644 --- a/arm9/src/tad.c +++ b/arm9/src/tad.c @@ -1,17 +1,22 @@ #include "tad.h" #include "storage.h" +#include "nand/twltool/dsi.h" #include #include #include #include #include #include +#include #include + /* The common keys for decrypting TADs. DEV: Used in most TADs. Anything created with the standard maketad will be dev. - PROD: Used in some TADs for factory tools like PRE_IMPORT and IMPORT. Really uncommon. I only know of 24 prod TADs to have ever been found, and 19 of those haven't ever been released (pleeeeeaaaaase release IMPORT soon). All retail signed and can't be created with any leaked maketads. + PROD: Used in some TADs for factory tools like PRE_IMPORT and IMPORT. Really uncommon. I only know of 24 prod TADs + to have ever been found, and 19 of those haven't ever been released (pleeeeeaaaaase release IMPORT soon). + All retail signed and can't be created with any leaked maketads. DEBUGGER: Used in TwlSystemUpdater TADs. Created with maketad_updater. If for whatever reason you want to make TADs, see here: @@ -56,6 +61,50 @@ uint32_t round_up( const u32 v, const u32 align ) return r; } + /* + This is SRL decryption. Again, just like WADs: + + Common key + title key IV to decrypt title key, title key + content IV to decrypt content + + We have to try each possible common key until we find one that works. I don't know a better way to do this + (nothing in the TAD would specify the key needed) so we'll try keys in the order of which ones are more common: + + DEV --> DEBUGGER --> PROD + + We check for only zerobytes at 0x15-1B to see if the SRL is decrypted properly. (should always be zerobytes) + + https://problemkaputt.de/gbatek.htm#dscartridgeheader + https://gist.github.com/rvtr/f1069530129b7a57967e3fc4b30866b4#file-decrypt_tad-py-L84 + */ +void decrypt_title_key(const unsigned char* key, unsigned char* iv, const unsigned char* encryptedData, size_t dataSize, unsigned char* decryptedData) { + aes_context ctx; + unsigned char decryptedBlock[16]; + /* ============================================= */ + iprintf(" Dev common key...\n"); + for (int i = 0; i < sizeof(key); i++) { + iprintf("%02X", key[i]); + } + iprintf("\n"); + iprintf(" Title key IV...\n"); + for (int i = 0; i < sizeof(iv); i++) { + iprintf("%02X", iv[i]); + } + iprintf("\n"); + iprintf(" Enc title key...\n"); + for (int i = 0; i < sizeof(encryptedData); i++) { + iprintf("%02X", encryptedData[i]); + } + iprintf("\n"); + iprintf(" Title key size...\n"); + iprintf("%u", dataSize); + iprintf("\n"); + /* ============================================= */ + aes_setkey_dec(&ctx, key, 256); + aes_crypt_cbc(&ctx, AES_DECRYPT, dataSize, iv, encryptedData, decryptedBlock); + + memcpy(decryptedData, decryptedBlock, dataSize); +} + int decryptTad(char const* src) { if (!src) return 1; @@ -66,18 +115,49 @@ int decryptTad(char const* src) return 1; } - mkdir("sd:/tadtests", 0777); + mkdir("sd:/_nds/tadtests", 0777); - // A lot of this is heavily """inspired""" by remaketad.pl in TwlIPL (/tools/bin/remaketad.pl) - // This is made to decrypt + unpack a dev TAD and and rebuild for SystemUpdaters. + // A lot of this is heavily "inspired" by remaketad.pl in TwlIPL (/tools/bin/remaketad.pl) + // That script was made to decrypt + unpack a dev TAD and and rebuild for SystemUpdaters. // // https://github.com/rvtr/TwlIPL/blob/trunk/tools/bin/remaketad.pl + /* + Please excuse my terrible copy paste coding. I do not know C and I'm translating from other languages + that I don't know (python, perl). + + Anyways, the code below is determining the file offsets and sizes within the TAD. + This is done using the 32 byte header. + + Example header from "KART_K04.tad" + + 00000020 49730000 00000E80 00000000 + 000002A4 00000208 000DFC00 00000000 + + Breaking it down... + + Hex | Dec | Meaning + -----------+--------+------------ + 0x00000020 | 32 | Header size + 0x4973 | Is | TAD type + 0x0000 | 0 | TAD version + 0x00000E80 | 3712 | Cert size + 0x00000000 | 0 | Crl size + 0x000002A4 | 676 | Ticket size + 0x00000208 | 520 | TMD size + 0x000DFC00 | 916480 | SRL size + 0x00000000 | 0 | Meta size + + Gee, looks awfully like a WAD header, doesn't it? Turns out TADs are just renamed WADs. Not even changed one bit. + There's literally a commit replacing every instance of WAD with TAD in TwlIPL... + https://github.com/rvtr/TwlIPL/commit/baca65d35d5d62d815c88e6374b895d5b0755277 + */ Header header; fread(&header, sizeof(Header), 1, file); - iprintf("Parsing TAD header...\n"); + iprintf("Parsing TAD header:\n"); Tad tad; tad.hdrOffset = 0; + // All offsets in the TAD are aligned to 64 bytes. tad.certOffset = round_up(swap_endian_u32(header.hdrSize), 64); tad.crlOffset = round_up(tad.certOffset + swap_endian_u32(header.certSize), 64); tad.ticketOffset = round_up(tad.crlOffset + swap_endian_u32(header.crlSize), 64); @@ -108,41 +188,18 @@ int decryptTad(char const* src) iprintf(" metaSize: %lu\n", swap_endian_u32(header.metaSize)); iprintf(" metaOffset: %lu\n", tad.metaOffset); /* - Please excuse my terrible copy paste coding. I do not know C and I'm translating from other languages - that I don't know (python, perl). + Copy the contents of the TAD to the SD card. - Anyways, the code above is determining the file offsets and sizes within the TAD. - This is done using the 32 byte header. - - Example header from "KART_K04.tad" - - 00000020 49730000 00000E80 00000000 - 000002A4 00000208 000DFC00 00000000 - - Breaking it down... - - Hex | Dec | Meaning - -----------+--------+------------ - 0x00000020 | 32 | Header size - 0x4973 | Is | TAD type - 0x0000 | 0 | TAD version - 0x00000E80 | 3712 | Cert size - 0x00000000 | 0 | Crl size - 0x000002A4 | 676 | Ticket size - 0x00000208 | 520 | TMD size - 0x000DFC00 | 916480 | SRL size - 0x00000000 | 0 | Meta size + For installing we only need the TMD, ticket, and SRL (obviously lol). - Gee, looks awfully like a WAD header, doesn't it? Turns out TADs are just renamed WADs. Not even changed one bit. - There's literally a commit replacing every instance of WAD with TAD in TwlIPL... - https://github.com/rvtr/TwlIPL/commit/baca65d35d5d62d815c88e6374b895d5b0755277 + We can skip the cert since that already exists in NAND, and using the TAD's cert could introduce problems like + trying to sign files for dev on a prod console. */ - - iprintf("================================\nCopying output files...\n"); + iprintf("\n--------------------------------\nCopying output files:\n"); // ChatGPT ahh code // Also more copy pasting because I am a silly idiot! iprintf(" Copying TMD...\n"); - FILE *tmdFile = fopen("sd:/tadtests/tmd.bin", "wb"); + FILE *tmdFile = fopen("sd:/_nds/tadtests/tmd.bin", "wb"); if (tmdFile == NULL) { iprintf("ERROR: fopen()\n"); } @@ -155,7 +212,7 @@ int decryptTad(char const* src) fclose(tmdFile); iprintf(" Copying ticket...\n"); - FILE *ticketFile = fopen("sd:/tadtests/ticket.bin", "wb"); + FILE *ticketFile = fopen("sd:/_nds/tadtests/ticket.bin", "wb"); if (ticketFile == NULL) { iprintf("ERROR: fopen()\n"); } @@ -166,9 +223,9 @@ int decryptTad(char const* src) fputc(ch, ticketFile); } fclose(ticketFile); - + /* iprintf(" Copying SRL...\n"); - FILE *srlFile = fopen("sd:/tadtests/srl_enc.bin", "wb"); + FILE *srlFile = fopen("sd:/_nds/tadtests/srl_enc.bin", "wb"); if (srlFile == NULL) { iprintf("ERROR: fopen()\n"); } @@ -179,20 +236,53 @@ int decryptTad(char const* src) fputc(ch, srlFile); } fclose(srlFile); + */ fclose(file); - iprintf("================================\nDone!\n"); + iprintf("\n--------------------------------\n"); /* - Try to decrypt the SRL with each key until one works. I don't know a better way to do this (nothing in the TAD would - specify the key needed) so we'll try keys in the order of which ones are more common: - DEV --> DEBUGGER --> PROD - - We check for only zerobytes at 0x15-1B to see if the SRL is decrypted properly. That region should always be blank. - - https://problemkaputt.de/gbatek.htm#dscartridgeheader - https://gist.github.com/rvtr/f1069530129b7a57967e3fc4b30866b4#file-decrypt_tad-py-L84 + Get the title key + IV from the ticket. */ + iprintf("Decrypting SRL:\n\n"); + iprintf(" Finding title key...\n"); + FILE *ticket = fopen("sd:/_nds/tadtests/ticket.bin", "rb"); + unsigned char title_key_enc[16]; + fseek(ticket, 447, SEEK_SET); + fread(title_key_enc, 1, 8, ticket); + iprintf(" Title key found!\n"); + for (int i = 0; i < 16; i++) { + iprintf("%02X", title_key_enc[i]); + } + iprintf("\n"); + iprintf(" Finding title key IV...\n"); + unsigned char title_key_iv[16]; + fseek(ticket, 476, SEEK_SET); + fread(title_key_iv, 1, 8, ticket); + memset(title_key_iv + 8, 0, 8); + iprintf(" Title key IV found!\n"); + for (int i = 0; i < 16; i++) { + iprintf("%02X", title_key_iv[i]); + } + iprintf("\n"); + fclose(ticket); + + iprintf(" Decrypting title key...\n"); + unsigned char decryptedBlock[16]; + /* ============================================= */ + iprintf(" Trying dev common key...\n"); + for (int i = 0; i < sizeof(devKey); i++) { + printf("%02X", devKey[i]); + } + printf("\n"); + /* ============================================= */ + unsigned char title_key_dec[16]; + decrypt_title_key(devKey, title_key_iv, title_key_enc, sizeof(title_key_enc), title_key_dec); + printf(" Title key decrypted!\n"); + for (int i = 0; i < sizeof(title_key_dec); i++) { + printf("%02X", title_key_dec[i]); + } + printf("\n"); //return copyFilePart(src, 0, size, dst); return 0;