Skip to content

Commit

Permalink
Get SRL encrypted title key and IV
Browse files Browse the repository at this point in the history
  • Loading branch information
rvtr committed Mar 30, 2024
1 parent 907c2fe commit 5eab2d4
Showing 1 changed file with 136 additions and 46 deletions.
182 changes: 136 additions & 46 deletions arm9/src/tad.c
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
#include "tad.h"
#include "storage.h"
#include "nand/twltool/dsi.h"
#include <nds/ndstypes.h>
#include <malloc.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <dirent.h>

/*
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:
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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");
}
Expand All @@ -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");
}
Expand All @@ -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");
}
Expand All @@ -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;
Expand Down

0 comments on commit 5eab2d4

Please sign in to comment.