mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 13:42:47 +00:00
Handle SD data crypto
This commit is contained in:
parent
779b6fe25b
commit
94c0608477
@ -6,6 +6,15 @@
|
||||
#define SDCRYPT_BUFFER_SIZE (0x100000)
|
||||
|
||||
#define NUM_ALIAS_DRV 2
|
||||
#define NUM_FILCRYPTINFO 16
|
||||
|
||||
typedef struct {
|
||||
FIL* fptr;
|
||||
u8 ctr[16];
|
||||
u8 keyy[16];
|
||||
} __attribute__((packed)) FilCryptInfo;
|
||||
|
||||
static FilCryptInfo filcrypt[NUM_FILCRYPTINFO] = { 0 };
|
||||
|
||||
char alias_drv[NUM_ALIAS_DRV]; // 1 char ASCII drive number of the alias drive / 0x00 if unused
|
||||
char alias_path[NUM_ALIAS_DRV][128]; // full path to resolve the alias into
|
||||
@ -31,86 +40,107 @@ void dealias_path (TCHAR* alias, const TCHAR* path) {
|
||||
else strncpy(alias, path, 256);
|
||||
}
|
||||
|
||||
void fx_crypt(XFIL* xfp, void* buff, FSIZE_t off, UINT bt) {
|
||||
FilCryptInfo* fx_find_cryptinfo(FIL* fptr) {
|
||||
FilCryptInfo* info = NULL;
|
||||
|
||||
for (u32 i = 0; i < NUM_FILCRYPTINFO; i++) {
|
||||
if (!info && !filcrypt[i].fptr) // use first free
|
||||
info = &filcrypt[i];
|
||||
if (fptr == filcrypt[i].fptr) {
|
||||
info = &filcrypt[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void fx_crypt(FilCryptInfo* info, void* buff, FSIZE_t off, UINT bt) {
|
||||
u32 mode = AES_CNT_CTRNAND_MODE;
|
||||
u8 ctr[16] __attribute__((aligned(32)));
|
||||
u8 buff16[16];
|
||||
u8* buffer = buff;
|
||||
|
||||
// copy CTR and increment it
|
||||
memcpy(ctr, xfp->iv, 16);
|
||||
memcpy(ctr, info->ctr, 16);
|
||||
add_ctr(ctr, off / 16);
|
||||
|
||||
// setup the key
|
||||
setup_aeskeyY(xfp->keyslot, xfp->keyy);
|
||||
use_aeskey(xfp->keyslot);
|
||||
setup_aeskeyY(0x34, info->keyy);
|
||||
use_aeskey(0x34);
|
||||
|
||||
// handle misaligned offset (at beginning)
|
||||
if (off % 16) {
|
||||
memcpy(buff16 + (off % 16), buff, 16 - (off % 16));
|
||||
memcpy(buff16 + (off % 16), buffer, 16 - (off % 16));
|
||||
ctr_decrypt(buff16, buff16, 1, mode, ctr);
|
||||
bt -= 16 - (off % 16);
|
||||
memcpy(buffer, buff16 + (off % 16), 16 - (off % 16));
|
||||
buffer += 16 - (off % 16);
|
||||
bt -= 16 - (off % 16);
|
||||
}
|
||||
|
||||
// de/encrypt the data
|
||||
ctr_decrypt(buff, buff, bt / 16, mode, ctr);
|
||||
bt -= 16 * (UINT) (bt / 16);
|
||||
ctr_decrypt(buffer, buffer, bt / 16, mode, ctr);
|
||||
buffer += 16 * (UINT) (bt / 16);
|
||||
bt -= 16 * (UINT) (bt / 16);
|
||||
|
||||
// handle misaligned offset (at end)
|
||||
if (bt) {
|
||||
memcpy(buff16, buff, bt);
|
||||
memcpy(buff16, buffer, bt);
|
||||
ctr_decrypt(buff16, buff16, 1, mode, ctr);
|
||||
memcpy(buffer, buff16, bt);
|
||||
buffer += bt;
|
||||
bt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
FRESULT fx_open (FIL* fp, XFIL* xfp, const TCHAR* path, BYTE mode) {
|
||||
FRESULT fx_open (FIL* fp, const TCHAR* path, BYTE mode) {
|
||||
int num = alias_num(path);
|
||||
xfp->keyslot = 0x40;
|
||||
if (num >= 0) {
|
||||
FilCryptInfo* info = fx_find_cryptinfo(fp);
|
||||
if (info) info->fptr = NULL;
|
||||
|
||||
if (info && (num >= 0)) {
|
||||
// get AES counter, see: http://www.3dbrew.org/wiki/Extdata#Encryption
|
||||
// path is the part of the full path after //Nintendo 3DS/<ID0>/<ID1>
|
||||
u8 hashstr[256];
|
||||
u8 sha256sum[32];
|
||||
u32 plen = 0;
|
||||
// poor man's UTF-8 -> UTF-16
|
||||
for (u32 plen = 0; plen < 128; plen++) {
|
||||
for (plen = 0; plen < 128; plen++) {
|
||||
hashstr[2*plen] = path[2 + plen];
|
||||
hashstr[2*plen+1] = 0;
|
||||
if (path[plen] == 0) break;
|
||||
if (path[2 + plen] == 0) break;
|
||||
}
|
||||
sha_quick(sha256sum, hashstr, (plen + 1) * 2, SHA256_MODE);
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
xfp->iv[i] = sha256sum[i] ^ sha256sum[i+16];
|
||||
// copy over key, set keyslot
|
||||
memcpy(xfp->keyy, sd_keyy[num], 16);
|
||||
xfp->keyslot = 0x34;
|
||||
info->ctr[i] = sha256sum[i] ^ sha256sum[i+16];
|
||||
// copy over key, FIL pointer
|
||||
memcpy(info->keyy, sd_keyy[num], 16);
|
||||
info->fptr = fp;
|
||||
}
|
||||
|
||||
return fa_open(fp, path, mode);
|
||||
}
|
||||
|
||||
FRESULT fx_read (FIL* fp, XFIL* xfp, void* buff, UINT btr, UINT* br) {
|
||||
FRESULT fx_read (FIL* fp, void* buff, UINT btr, UINT* br) {
|
||||
FilCryptInfo* info = fx_find_cryptinfo(fp);
|
||||
FSIZE_t off = f_tell(fp);
|
||||
FRESULT res = f_read(fp, buff, btr, br);
|
||||
if (xfp && (xfp->keyslot < 0x40))
|
||||
fx_crypt(xfp, buff, off, btr);
|
||||
if (info && info->fptr)
|
||||
fx_crypt(info, buff, off, btr);
|
||||
return res;
|
||||
}
|
||||
|
||||
FRESULT fx_write (FIL* fp, XFIL* xfp, const void* buff, UINT btw, UINT* bw) {
|
||||
FRESULT fx_write (FIL* fp, const void* buff, UINT btw, UINT* bw) {
|
||||
FilCryptInfo* info = fx_find_cryptinfo(fp);
|
||||
FSIZE_t off = f_tell(fp);
|
||||
FRESULT res = FR_OK;
|
||||
if (xfp && (xfp->keyslot < 0x40)) {
|
||||
if (info && info->fptr) {
|
||||
*bw = 0;
|
||||
for (UINT p = 0; (p < btw) && (res == FR_OK); p += SDCRYPT_BUFFER_SIZE) {
|
||||
UINT pcount = min(SDCRYPT_BUFFER_SIZE, (btw - p));
|
||||
UINT bwl = 0;
|
||||
memcpy(SDCRYPT_BUFFER, (u8*) buff + p, pcount);
|
||||
fx_crypt(xfp, SDCRYPT_BUFFER, off + p, pcount);
|
||||
fx_crypt(info, SDCRYPT_BUFFER, off + p, pcount);
|
||||
res = f_write(fp, (const void*) SDCRYPT_BUFFER, pcount, &bwl);
|
||||
*bw += bwl;
|
||||
}
|
||||
|
@ -3,17 +3,11 @@
|
||||
#include "common.h"
|
||||
#include "ff.h"
|
||||
|
||||
typedef struct {
|
||||
u8 iv[16];
|
||||
u8 keyy[16];
|
||||
u32 keyslot;
|
||||
} __attribute__((packed)) XFIL;
|
||||
|
||||
// wrapper functions for ff.h
|
||||
// incomplete(!) extension to FatFS to support on-the-fly crypto & path aliases
|
||||
FRESULT fx_open (FIL* fp, XFIL* xfp, const TCHAR* path, BYTE mode);
|
||||
FRESULT fx_read (FIL* fp, XFIL* xfp, void* buff, UINT btr, UINT* br);
|
||||
FRESULT fx_write (FIL* fp, XFIL* xfp, const void* buff, UINT btw, UINT* bw);
|
||||
FRESULT fx_open (FIL* fp, const TCHAR* path, BYTE mode);
|
||||
FRESULT fx_read (FIL* fp, void* buff, UINT btr, UINT* br);
|
||||
FRESULT fx_write (FIL* fp, const void* buff, UINT btw, UINT* bw);
|
||||
|
||||
void dealias_path (TCHAR* alias, const TCHAR* path);
|
||||
FRESULT fa_open (FIL* fp, const TCHAR* path, BYTE mode);
|
||||
|
36
source/fs.c
36
source/fs.c
@ -343,10 +343,10 @@ bool FileSetData(const char* path, const u8* data, size_t size, size_t foffset,
|
||||
if (drvtype & DRV_FAT) {
|
||||
UINT bytes_written = 0;
|
||||
FIL file;
|
||||
if (fa_open(&file, path, FA_WRITE | (create ? FA_CREATE_ALWAYS : FA_OPEN_ALWAYS)) != FR_OK)
|
||||
if (fx_open(&file, path, FA_WRITE | (create ? FA_CREATE_ALWAYS : FA_OPEN_ALWAYS)) != FR_OK)
|
||||
return false;
|
||||
f_lseek(&file, foffset);
|
||||
f_write(&file, data, size, &bytes_written);
|
||||
fx_write(&file, data, size, &bytes_written);
|
||||
f_close(&file);
|
||||
return (bytes_written == size);
|
||||
} else if (drvtype & DRV_VIRTUAL) {
|
||||
@ -363,10 +363,10 @@ size_t FileGetData(const char* path, u8* data, size_t size, size_t foffset) {
|
||||
if (drvtype & DRV_FAT) {
|
||||
UINT bytes_read = 0;
|
||||
FIL file;
|
||||
if (fa_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||
if (fx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||
return 0;
|
||||
f_lseek(&file, foffset);
|
||||
if (f_read(&file, data, size, &bytes_read) != FR_OK) {
|
||||
if (fx_read(&file, data, size, &bytes_read) != FR_OK) {
|
||||
f_close(&file);
|
||||
return 0;
|
||||
}
|
||||
@ -423,7 +423,7 @@ bool FileGetSha256(const char* path, u8* sha256) {
|
||||
FIL file;
|
||||
size_t fsize;
|
||||
|
||||
if (fa_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||
if (fx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||
return false;
|
||||
fsize = f_size(&file);
|
||||
f_lseek(&file, 0);
|
||||
@ -431,7 +431,7 @@ bool FileGetSha256(const char* path, u8* sha256) {
|
||||
|
||||
for (size_t pos = 0; (pos < fsize) && ret; pos += MAIN_BUFFER_SIZE) {
|
||||
UINT bytes_read = 0;
|
||||
if (f_read(&file, MAIN_BUFFER, MAIN_BUFFER_SIZE, &bytes_read) != FR_OK)
|
||||
if (fx_read(&file, MAIN_BUFFER, MAIN_BUFFER_SIZE, &bytes_read) != FR_OK)
|
||||
ret = false;
|
||||
if (!ShowProgress(pos + bytes_read, fsize, path))
|
||||
ret = false;
|
||||
@ -502,7 +502,7 @@ bool FileInjectFile(const char* dest, const char* orig, u32 offset) {
|
||||
dsize = dvfile.size;
|
||||
} else {
|
||||
vdest = false;
|
||||
if (fa_open(&dfile, dest, FA_WRITE | FA_OPEN_EXISTING) != FR_OK)
|
||||
if (fx_open(&dfile, dest, FA_WRITE | FA_OPEN_EXISTING) != FR_OK)
|
||||
return false;
|
||||
dsize = f_size(&dfile);
|
||||
f_lseek(&dfile, offset);
|
||||
@ -519,7 +519,7 @@ bool FileInjectFile(const char* dest, const char* orig, u32 offset) {
|
||||
osize = ovfile.size;
|
||||
} else {
|
||||
vorig = false;
|
||||
if (fa_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK) {
|
||||
if (fx_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK) {
|
||||
if (!vdest) f_close(&dfile);
|
||||
return false;
|
||||
}
|
||||
@ -542,12 +542,12 @@ bool FileInjectFile(const char* dest, const char* orig, u32 offset) {
|
||||
UINT read_bytes = min(MAIN_BUFFER_SIZE, osize - pos);
|
||||
UINT bytes_read = read_bytes;
|
||||
UINT bytes_written = read_bytes;
|
||||
if ((!vorig && (f_read(&ofile, MAIN_BUFFER, read_bytes, &bytes_read) != FR_OK)) ||
|
||||
if ((!vorig && (fx_read(&ofile, MAIN_BUFFER, read_bytes, &bytes_read) != FR_OK)) ||
|
||||
(vorig && ReadVirtualFile(&ovfile, MAIN_BUFFER, pos, read_bytes, NULL) != 0))
|
||||
ret = false;
|
||||
if (!ShowProgress(pos + (bytes_read / 2), osize, orig))
|
||||
ret = false;
|
||||
if ((!vdest && (f_write(&dfile, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK)) ||
|
||||
if ((!vdest && (fx_write(&dfile, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK)) ||
|
||||
(vdest && WriteVirtualFile(&dvfile, MAIN_BUFFER, offset + pos, read_bytes, NULL) != 0))
|
||||
ret = false;
|
||||
if (bytes_read != bytes_written)
|
||||
@ -616,7 +616,7 @@ bool PathCopyVirtual(const char* destdir, const char* orig, u32* flags) {
|
||||
FIL ofile;
|
||||
u32 osize;
|
||||
|
||||
if (fa_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||
if (fx_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||
return false;
|
||||
f_lseek(&ofile, 0);
|
||||
f_sync(&ofile);
|
||||
@ -654,7 +654,7 @@ bool PathCopyVirtual(const char* destdir, const char* orig, u32* flags) {
|
||||
if (!ShowProgress(0, 0, orig)) ret = false;
|
||||
for (size_t pos = 0; (pos < osize) && ret; pos += MAIN_BUFFER_SIZE) {
|
||||
UINT bytes_read = 0;
|
||||
if (f_read(&ofile, MAIN_BUFFER, MAIN_BUFFER_SIZE, &bytes_read) != FR_OK)
|
||||
if (fx_read(&ofile, MAIN_BUFFER, MAIN_BUFFER_SIZE, &bytes_read) != FR_OK)
|
||||
ret = false;
|
||||
if (!ShowProgress(pos + (bytes_read / 2), osize, orig))
|
||||
ret = false;
|
||||
@ -703,7 +703,7 @@ bool PathCopyVirtual(const char* destdir, const char* orig, u32* flags) {
|
||||
}
|
||||
}
|
||||
|
||||
if (fa_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)
|
||||
if (fx_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)
|
||||
return false;
|
||||
f_lseek(&dfile, 0);
|
||||
f_sync(&dfile);
|
||||
@ -722,7 +722,7 @@ bool PathCopyVirtual(const char* destdir, const char* orig, u32* flags) {
|
||||
ret = false;
|
||||
if (!ShowProgress(pos + (read_bytes / 2), osize, orig))
|
||||
ret = false;
|
||||
if (f_write(&dfile, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK)
|
||||
if (fx_write(&dfile, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK)
|
||||
ret = false;
|
||||
if (read_bytes != bytes_written)
|
||||
ret = false;
|
||||
@ -845,7 +845,7 @@ bool PathCopyWorker(char* dest, char* orig, u32* flags, bool move) {
|
||||
FIL dfile;
|
||||
size_t fsize;
|
||||
|
||||
if (fa_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||
if (fx_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||
return false;
|
||||
fsize = f_size(&ofile);
|
||||
if (GetFreeSpace(dest) < fsize) {
|
||||
@ -854,7 +854,7 @@ bool PathCopyWorker(char* dest, char* orig, u32* flags, bool move) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fa_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) {
|
||||
if (fx_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) {
|
||||
ShowPrompt(false, "Error: Cannot create destination file");
|
||||
f_close(&ofile);
|
||||
return false;
|
||||
@ -869,11 +869,11 @@ bool PathCopyWorker(char* dest, char* orig, u32* flags, bool move) {
|
||||
for (size_t pos = 0; (pos < fsize) && ret; pos += MAIN_BUFFER_SIZE) {
|
||||
UINT bytes_read = 0;
|
||||
UINT bytes_written = 0;
|
||||
if (f_read(&ofile, MAIN_BUFFER, MAIN_BUFFER_SIZE, &bytes_read) != FR_OK)
|
||||
if (fx_read(&ofile, MAIN_BUFFER, MAIN_BUFFER_SIZE, &bytes_read) != FR_OK)
|
||||
ret = false;
|
||||
if (!ShowProgress(pos + (bytes_read / 2), fsize, orig))
|
||||
ret = false;
|
||||
if (f_write(&dfile, MAIN_BUFFER, bytes_read, &bytes_written) != FR_OK)
|
||||
if (fx_write(&dfile, MAIN_BUFFER, bytes_read, &bytes_written) != FR_OK)
|
||||
ret = false;
|
||||
if (bytes_read != bytes_written)
|
||||
ret = false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user