Handle SD data crypto

This commit is contained in:
d0k3 2016-10-30 15:57:54 +01:00
parent 779b6fe25b
commit 94c0608477
3 changed files with 75 additions and 51 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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;