Skip to content

Commit 8e2e748

Browse files
[wii] correct filesize when enumerating CNTSD DLC, read key from SD
1 parent c3e2ded commit 8e2e748

File tree

4 files changed

+150
-23
lines changed

4 files changed

+150
-23
lines changed

include/wii_cnt_crypt.h

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,23 @@
77
#include <stdint.h>
88

99
typedef struct _RB3E_CNTFileSD {
10-
int fd;
11-
uint32_t titleId;
12-
int contentLength;
13-
int startOffset;
14-
uint16_t contentIndex;
15-
struct AES_ctx *aesCtx;
16-
uint8_t *arcHeader;
17-
int lastBlockIndex;
18-
uint8_t lastBlock[0x10];
19-
uint8_t lastBlockEnc[0x10];
10+
int fd; // 0x0
11+
uint32_t titleId; // 0x4
12+
int contentLength; // 0x8
13+
int startOffset; // 0xC
14+
uint16_t contentIndex; // 0x10
15+
uint16_t padding; // 0x12 - probably not needed
16+
struct AES_ctx *aesCtx; // 0x14
17+
uint8_t *arcHeader; // 0x18
18+
int lastBlockIndex; // 0x1c
19+
uint8_t aesKey[0x10]; // 0x20
20+
uint8_t lastBlock[0x10]; // 0x30
21+
uint8_t lastBlockEnc[0x10]; // 0x40
2022
} RB3E_CNTFileSD;
2123

22-
RB3E_CNTFileSD *RB3E_OpenCNTFileSD(const char *filepath);
24+
RB3E_CNTFileSD *RB3E_OpenCNTFileSD(const char *filepath, unsigned long long titleid, unsigned int index);
2325
void RB3E_CloseCNTFileSD(RB3E_CNTFileSD *file);
2426
void RB3E_CNTFileRead(RB3E_CNTFileSD *file, int offset, uint8_t *buffer, int length);
27+
void TryToLoadPRNGKeyFromFile();
2528

2629
#endif // RB3E_WII

source/rb3enhanced.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ void ApplyHooks()
435435
}
436436

437437
void InitCNTHooks();
438+
void TryToLoadPRNGKeyFromFile();
438439

439440
void StartupHook(void *ThisApp, int argc, char **argv)
440441
{
@@ -456,7 +457,10 @@ void StartupHook(void *ThisApp, int argc, char **argv)
456457

457458
#ifdef RB3E_WII
458459
if (RB3E_Mounted && config.LegacySDMode == false)
460+
{
461+
TryToLoadPRNGKeyFromFile();
459462
InitCNTHooks();
463+
}
460464
#endif
461465

462466
// start the game by calling the proper app constructor

source/wii_cnt_crypt.c

Lines changed: 129 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,31 @@
2222
#define PRINT_BLOCK(name, x) RB3E_DEBUG(name ": %08x%08x%08x%08x", *(uint32_t *)&x[0], *(uint32_t *)&x[4], *(uint32_t *)&x[8], *(uint32_t *)&x[12])
2323

2424
// to be filled in by the brainslug launcher
25-
uint8_t RB3E_ConsolePRNGKey[0x10];
25+
uint8_t RB3E_ConsolePRNGKey[0x10] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
26+
27+
static uint8_t nullKey[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
28+
29+
// This is really slow apparently
30+
void IOS_AES_Decrypt(uint8_t *input, uint8_t *key, uint8_t *iv, uint8_t *output)
31+
{
32+
static ios_fd_t aesFd = -1;
33+
if (aesFd == -1)
34+
aesFd = IOS_Open("/dev/aes", IPC_OPEN_NONE);
35+
36+
ioctlv vec[4] __attribute__((align(32)));
37+
// input vector
38+
vec[0].data = input;
39+
vec[0].len = 0x10;
40+
vec[1].data = key;
41+
vec[1].len = 0x10;
42+
// output vector
43+
vec[2].data = output;
44+
vec[2].len = 0x10;
45+
vec[3].data = iv;
46+
vec[3].len = 0x10;
47+
// decrypt
48+
IOS_Ioctlv(aesFd, 0x3, 2, 2, vec);
49+
}
2650

2751
uint64_t OSGetTime();
2852
uint64_t timeSpentInAES = 0;
@@ -78,13 +102,12 @@ void RB3E_CNTFileReadBlock(RB3E_CNTFileSD *file, int blockIndex)
78102
}
79103
time = OSGetTime();
80104
// read and decrypt the current block
81-
SD_read(file->fd, file->lastBlock, 0x10);
105+
SD_read(file->fd, file->lastBlockEnc, 0x10);
82106
timeSpentInSD += OSGetTime() - time;
83107

84108
time = OSGetTime();
85-
memcpy(file->lastBlockEnc, file->lastBlock, 0x10); // keep a copy of the encrypted last block to use as the next IV
86-
// TODO(Emma): can we use the hardware AES engine to make this faster?
87-
// TODO(Emma): can we
109+
//memcpy(file->lastBlockEnc, file->lastBlock, 0x10); // keep a copy of the encrypted last block to use as the next IV
110+
memcpy(file->lastBlock, file->lastBlockEnc, 0x10);
88111
AES_CBC_decrypt_buffer(file->aesCtx, file->lastBlock, 0x10);
89112
timeSpentInAES += OSGetTime() - time;
90113
file->lastBlockIndex = blockIndex;
@@ -162,7 +185,7 @@ static inline int getFlippedContent(uint8_t *contentFlags)
162185
return index;
163186
}
164187

165-
RB3E_CNTFileSD *RB3E_OpenCNTFileSD(const char *filepath)
188+
RB3E_CNTFileSD *RB3E_OpenCNTFileSD(const char *filepath, unsigned long long titleid, unsigned int index)
166189
{
167190
// open a handle to the file
168191
int fd = RB3E_OpenFile(filepath, 0);
@@ -235,16 +258,17 @@ RB3E_CNTFileSD *RB3E_OpenCNTFileSD(const char *filepath)
235258
file->startOffset = startOfData;
236259
// try to decrypt it with the NULL PRNG key (sZA-sZG)
237260
RB3E_DEBUG("Attempting to read with NULLed key", NULL);
238-
static uint8_t nullKey[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
239261
PRINT_BLOCK("Key", nullKey);
240262
AES_init_ctx(file->aesCtx, nullKey);
263+
memcpy(file->aesKey, nullKey, 0x10);
241264
RB3E_CNTFileReadBlock(file, 0);
242265
if (*(uint32_t *)file->lastBlock != ARC_MAGIC)
243266
{
244267
// that failed - try to decrypt it with the console-specific PRNG key (sZH+)
245268
RB3E_DEBUG("Trying console specific PRNG key", NULL);
246269
PRINT_BLOCK("Key", RB3E_ConsolePRNGKey);
247270
AES_init_ctx(file->aesCtx, RB3E_ConsolePRNGKey);
271+
memcpy(file->aesKey, RB3E_ConsolePRNGKey, 0x10);
248272
file->lastBlockIndex = -1;
249273
RB3E_CNTFileReadBlock(file, 0);
250274
if (*(uint32_t *)file->lastBlock != ARC_MAGIC)
@@ -278,10 +302,10 @@ RB3E_CNTFileSD *RB3E_OpenCNTFileSD(const char *filepath)
278302
{
279303
// untested, just try to handle the ARC file directly
280304
file->aesCtx = NULL;
281-
file->contentIndex = 0xFFFF; // TODO(Emma): get this from the filename and a TMD file
305+
file->contentIndex = index;
282306
file->contentLength = RB3E_FileSize(file->fd);
283307
file->startOffset = 0;
284-
file->titleId = 0x72423345; // 'rB3E'
308+
file->titleId = (uint32_t)titleid;
285309
// read the ARC file header into RAM
286310
u8_header_t archeader;
287311
RB3E_CNTFileRead(file, 0, (uint8_t *)&archeader, sizeof(u8_header_t));
@@ -305,4 +329,100 @@ RB3E_CNTFileSD *RB3E_OpenCNTFileSD(const char *filepath)
305329
}
306330
}
307331

332+
void ParseKeysFile(uint8_t *keys_data, size_t keys_len)
333+
{
334+
RB3E_DEBUG("0x%x bytes key file", keys_len);
335+
// check if its a BootMii-style keys.bin
336+
if (keys_len >= 0x400 && *(uint32_t *)&keys_data[0x114] == 0xEBE42A22)
337+
{
338+
memcpy(RB3E_ConsolePRNGKey, keys_data + 0x168, 0x10);
339+
}
340+
// check if its an OTP file dump
341+
else if (keys_len >= 0x100 && *(uint32_t *)&keys_data[0x14] == 0xEBE42A22)
342+
{
343+
memcpy(RB3E_ConsolePRNGKey, keys_data + 0x68, 0x10);
344+
}
345+
// check if its a straight up key
346+
else if (keys_len == 0x10)
347+
{
348+
memcpy(RB3E_ConsolePRNGKey, keys_data, 0x10);
349+
}
350+
else
351+
{
352+
RB3E_DEBUG("FAILED TO LOAD KEY!", NULL);
353+
return;
354+
}
355+
PRINT_BLOCK("Loaded Key", RB3E_ConsolePRNGKey);
356+
}
357+
358+
void TryToLoadPRNGKeyFromFile()
359+
{
360+
uint8_t keys_buffer[0x400]; // size of keys.bin file
361+
362+
// check if the loader already loaded a prng key
363+
if (memcmp(RB3E_ConsolePRNGKey, nullKey, 0x10) != 0)
364+
{
365+
RB3E_DEBUG("PRNG key loaded, not scanning for file", NULL);
366+
return;
367+
}
368+
369+
// DOLPHIN ONLY: try to load keys.bin from the NAND
370+
if (RB3E_IsEmulator())
371+
{
372+
ios_fd_t nandfd = IOS_Open("/keys.bin", IPC_OPEN_READ);
373+
if (nandfd >= 0)
374+
{
375+
RB3E_DEBUG("Loading keys from NAND", NULL);
376+
ios_ret_t readret = IOS_Read(nandfd, keys_buffer, sizeof(keys_buffer));
377+
IOS_Close(nandfd);
378+
if (readret >= IPC_OK)
379+
{
380+
ParseKeysFile(keys_buffer, readret);
381+
}
382+
return;
383+
}
384+
}
385+
386+
// try a few files on SD
387+
// PRNG key as binary
388+
if (RB3E_FileExists("sd:/prng_key.bin"))
389+
{
390+
int keysfd = RB3E_OpenFile("sd:/prng_key.bin", 0);
391+
if (keysfd != -1)
392+
{
393+
RB3E_DEBUG("Loading keys from prng_key.bin", NULL);
394+
int r = RB3E_ReadFile(keysfd, 0, keys_buffer, 0x10);
395+
RB3E_CloseFile(keysfd);
396+
ParseKeysFile(keys_buffer, r == 0x10 ? 0x10 : 0);
397+
return;
398+
}
399+
}
400+
// vWii/xyzzy OTP backup
401+
if (RB3E_FileExists("sd:/otp.bin"))
402+
{
403+
int otpfd = RB3E_OpenFile("sd:/otp.bin", 0);
404+
if (otpfd != -1)
405+
{
406+
RB3E_DEBUG("Loading keys from otp.bin", NULL);
407+
int r = RB3E_ReadFile(otpfd, 0, keys_buffer, sizeof(keys_buffer));
408+
RB3E_CloseFile(otpfd);
409+
ParseKeysFile(keys_buffer, r);
410+
return;
411+
}
412+
}
413+
// BootMii/xyzzy keys.bin backup
414+
if (RB3E_FileExists("sd:/keys.bin"))
415+
{
416+
int keysfd = RB3E_OpenFile("sd:/keys.bin", 0);
417+
if (keysfd != -1)
418+
{
419+
RB3E_DEBUG("Loading keys from keys.bin", NULL);
420+
int r = RB3E_ReadFile(keysfd, 0, keys_buffer, sizeof(keys_buffer));
421+
RB3E_CloseFile(keysfd);
422+
ParseKeysFile(keys_buffer, r);
423+
return;
424+
}
425+
}
426+
}
427+
308428
#endif // RB3E_WII

source/wii_cnt_hooks.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ int contentInitHandleTitleNAND_hook(unsigned long long title_id, unsigned int co
2828
if (RB3E_FileExists(sdfilepath))
2929
{
3030
// open the bin file on the SD
31-
RB3E_CNTFileSD *cntfilesd = RB3E_OpenCNTFileSD(sdfilepath);
31+
RB3E_CNTFileSD *cntfilesd = RB3E_OpenCNTFileSD(sdfilepath, title_id, content_index);
3232
if (cntfilesd == NULL) {
3333
return -1; // TODO: what's the proper CNT error for "file not found"?
3434
}
@@ -125,8 +125,8 @@ int EC_GetContentInfos_hook(unsigned long long titleId, ec_content_info_t *conte
125125
contentInfos[contentIndex].flags = 3;
126126
contentInfos[contentIndex].index = contentIndex;
127127
contentInfos[contentIndex].type = 0x4001; // DLC
128-
// ROCK BAND HACK - the filesize of the DLC is checked to determine if something is a song or not
129-
contentInfos[contentIndex].size = (contentIndex & 1) == 0 ? 0x414141 : 1;
128+
// the filesize of the DLC is checked to determine if something is a song or not
129+
contentInfos[contentIndex].size = fs.st_size;
130130
}
131131
else
132132
{

0 commit comments

Comments
 (0)