diff --git a/source/fatfs/alias.c b/source/fatfs/alias.c index 7c618d3..6d81d8d 100644 --- a/source/fatfs/alias.c +++ b/source/fatfs/alias.c @@ -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// 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; } diff --git a/source/fatfs/alias.h b/source/fatfs/alias.h index a06846a..7bac9f7 100644 --- a/source/fatfs/alias.h +++ b/source/fatfs/alias.h @@ -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); diff --git a/source/fs.c b/source/fs.c index 94885d6..1e29595 100644 --- a/source/fs.c +++ b/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;