diff --git a/README.md b/README.md index d518cfd..8cea31f 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ todo: romfs: filelist generation methods romfs: patch writing function + bktr: filelist generation methods + Result txIsFat32(bool *mode) { Result rc = serviceDispatch(&g_tx, 137); if (rc == 0xa08) { diff --git a/source/bktr.c b/source/bktr.c index bca0bf3..3637e8d 100644 --- a/source/bktr.c +++ b/source/bktr.c @@ -18,520 +18,62 @@ #include #include -#include "romfs.h" +#include "bktr.h" #include "utils.h" /* Function prototypes. */ -static RomFileSystemDirectoryEntry *romfsGetChildDirectoryEntryByName(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, const char *name); -static RomFileSystemFileEntry *romfsGetChildFileEntryByName(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, const char *name); -bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_fs_ctx) + + +bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ctx, NcaFsSectionContext *update_nca_fs_ctx) { - NcaContext *nca_ctx = NULL; - u64 dir_table_offset = 0, file_table_offset = 0; + NcaContext *base_nca_ctx = NULL, *update_nca_ctx = NULL; - if (!out || !nca_fs_ctx || nca_fs_ctx->section_type != NcaFsSectionType_RomFs || !nca_fs_ctx->header || !(nca_ctx = (NcaContext*)nca_fs_ctx->nca_ctx) || \ - (nca_ctx->format_version == NcaVersion_Nca0 && (nca_fs_ctx->section_type != NcaFsSectionType_Nca0RomFs || nca_fs_ctx->header->hash_type != NcaHashType_HierarchicalSha256)) || \ - (nca_ctx->format_version != NcaVersion_Nca0 && (nca_fs_ctx->section_type != NcaFsSectionType_RomFs || nca_fs_ctx->header->hash_type != NcaHashType_HierarchicalIntegrity))) + if (!out || !base_nca_fs_ctx || !(base_nca_ctx = (NcaContext*)base_nca_fs_ctx->nca_ctx) || base_nca_fs_ctx->section_type != NcaFsSectionType_RomFs || \ + base_nca_fs_ctx->encryption_type == NcaEncryptionType_AesCtrEx || !update_nca_fs_ctx || !(update_nca_ctx = (NcaContext*)update_nca_fs_ctx->nca_ctx) || \ + update_nca_fs_ctx->section_type != NcaFsSectionType_PatchRomFs || update_nca_fs_ctx->encryption_type != NcaEncryptionType_AesCtrEx || + base_nca_ctx->header.program_id != update_nca_ctx->header.program_id) { LOGFILE("Invalid parameters!"); return false; } + /* Initialize base NCA RomFS context */ + if (!romfsInitializeContext(&(out->base_romfs_ctx), base_nca_fs_ctx)) + { + LOGFILE("Failed to initialize base NCA RomFS context!"); + return false; + } + + /* Initialize update NCA RomFS context */ + if (!romfsInitializeContext(&(out->patch_romfs_ctx), update_nca_fs_ctx)) + { + LOGFILE("Failed to initialize update NCA RomFS context!"); + romfsFreeContext(&(out->base_romfs_ctx)); + return false; + } + /* Fill context */ - out->nca_fs_ctx = nca_fs_ctx; - out->offset = 0; - out->size = 0; - out->dir_table_size = 0; - out->dir_table = NULL; - out->file_table_size = 0; - out->file_table = NULL; - out->body_offset = 0; - - if (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs) - { - if (!ncaValidateHierarchicalSha256Offsets(&(nca_fs_ctx->header->hash_info.hierarchical_sha256), nca_fs_ctx->section_size)) - { - LOGFILE("Invalid HierarchicalSha256 block!"); - return false; - } - - out->offset = nca_fs_ctx->header->hash_info.hierarchical_sha256.hash_target_layer_info.offset; - out->size = nca_fs_ctx->header->hash_info.hierarchical_sha256.hash_target_layer_info.size; - } else { - /* Don't verify offsets from Patch RomFS sections, because they reflect the full, patched RomFS image */ - if (nca_fs_ctx->encryption_type != NcaEncryptionType_AesCtrEx && !ncaValidateHierarchicalIntegrityOffsets(&(nca_fs_ctx->header->hash_info.hierarchical_integrity), nca_fs_ctx->section_size)) - { - LOGFILE("Invalid HierarchicalIntegrity block!"); - return false; - } - - out->offset = nca_fs_ctx->header->hash_info.hierarchical_integrity.hash_target_layer_info.offset; - out->size = nca_fs_ctx->header->hash_info.hierarchical_integrity.hash_target_layer_info.size; - } - - /* Read RomFS header */ - if (!ncaReadFsSection(nca_fs_ctx, &(out->header), sizeof(RomFileSystemHeader), out->offset)) - { - LOGFILE("Failed to read RomFS header!"); - return false; - } - - if ((nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs && out->header.old_format.header_size != ROMFS_OLD_HEADER_SIZE) || \ - (nca_fs_ctx->section_type == NcaFsSectionType_RomFs && out->header.cur_format.header_size != ROMFS_HEADER_SIZE)) - { - LOGFILE("Invalid RomFS header size!"); - return false; - } - - /* Read directory entries table */ - dir_table_offset = (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.directory_entry_offset : out->header.cur_format.directory_entry_offset); - out->dir_table_size = (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.directory_entry_size : out->header.cur_format.directory_entry_size); - - /* Don't verify offsets from Patch RomFS sections, because they reflect the full, patched RomFS image */ - if (!out->dir_table_size || (nca_fs_ctx->encryption_type != NcaEncryptionType_AesCtrEx && (dir_table_offset >= out->size || (dir_table_offset + out->dir_table_size) > out->size))) - { - LOGFILE("Invalid RomFS directory entries table!"); - return false; - } - - out->dir_table = malloc(out->dir_table_size); - if (!out->dir_table) - { - LOGFILE("Unable to allocate memory for RomFS directory entries table!"); - return false; - } - - if (!ncaReadFsSection(nca_fs_ctx, out->dir_table, out->dir_table_size, out->offset + dir_table_offset)) - { - LOGFILE("Failed to read RomFS directory entries table!"); - return false; - } - - /* Read file entries table */ - file_table_offset = (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.file_entry_offset : out->header.cur_format.file_entry_offset); - out->file_table_size = (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.file_entry_size : out->header.cur_format.file_entry_size); - - /* Don't verify offsets from Patch RomFS sections, because they reflect the full, patched RomFS image */ - if (!out->file_table_size || (nca_fs_ctx->encryption_type != NcaEncryptionType_AesCtrEx && (file_table_offset >= out->size || (file_table_offset + out->file_table_size) > out->size))) - { - LOGFILE("Invalid RomFS file entries table!"); - return false; - } - - out->file_table = malloc(out->file_table_size); - if (!out->file_table) - { - LOGFILE("Unable to allocate memory for RomFS file entries table!"); - return false; - } - - if (!ncaReadFsSection(nca_fs_ctx, out->file_table, out->file_table_size, out->offset + file_table_offset)) - { - LOGFILE("Failed to read RomFS file entries table!"); - return false; - } - - /* Get file data body offset */ - /* Don't verify offsets from Patch RomFS sections, because they reflect the full, patched RomFS image */ - out->body_offset = (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.body_offset : out->header.cur_format.body_offset); - if (nca_fs_ctx->encryption_type != NcaEncryptionType_AesCtrEx && out->body_offset >= out->size) - { - LOGFILE("Invalid RomFS file data body!"); - return false; - } - - return true; -} - -bool romfsReadFileSystemData(RomFileSystemContext *ctx, void *out, u64 read_size, u64 offset) -{ - if (!ctx || !ctx->nca_fs_ctx || !ctx->size || !out || !read_size || offset >= ctx->size || (offset + read_size) > ctx->size) - { - LOGFILE("Invalid parameters!"); - return false; - } - - /* Read filesystem data */ - if (!ncaReadFsSection(ctx->nca_fs_ctx, out, read_size, ctx->offset + offset)) - { - LOGFILE("Failed to read RomFS data!"); - return false; - } - - return true; -} - -bool romfsReadFileEntryData(RomFileSystemContext *ctx, RomFileSystemFileEntry *file_entry, void *out, u64 read_size, u64 offset) -{ - if (!ctx || !ctx->body_offset || !file_entry || !file_entry->size || file_entry->offset >= ctx->size || (file_entry->offset + file_entry->size) > ctx->size || \ - !out || !read_size || offset >= file_entry->size || (offset + read_size) > file_entry->size) - { - LOGFILE("Invalid parameters!"); - return false; - } - - /* Read entry data */ - if (!romfsReadFileSystemData(ctx, out, read_size, ctx->body_offset + file_entry->offset + offset)) - { - LOGFILE("Failed to read RomFS file entry data!"); - return false; - } - - return true; -} - -bool romfsGetTotalDataSize(RomFileSystemContext *ctx, u64 *out_size) -{ - if (!ctx || !ctx->file_table_size || !ctx->file_table || !out_size) - { - LOGFILE("Invalid parameters!"); - return false; - } - - u64 offset = 0, total_size = 0; - RomFileSystemFileEntry *file_entry = NULL; - - while(offset < ctx->file_table_size) - { - if (!(file_entry = romfsGetFileEntryByOffset(ctx, offset))) - { - LOGFILE("Failed to retrieve file entry!"); - return false; - } - - total_size += file_entry->size; - offset += ALIGN_UP(sizeof(RomFileSystemFileEntry) + file_entry->name_length, 4); - } - - *out_size = total_size; - - return true; -} - -bool romfsGetDirectoryDataSize(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, u64 *out_size) -{ - if (!ctx || !ctx->dir_table_size || !ctx->dir_table || !ctx->file_table_size || !ctx->file_table || !dir_entry || (dir_entry->file_offset == ROMFS_VOID_ENTRY && \ - dir_entry->directory_offset == ROMFS_VOID_ENTRY) || !out_size) - { - LOGFILE("Invalid parameters!"); - return false; - } - - u64 total_size = 0, child_dir_size = 0; - u32 cur_file_offset = 0, cur_dir_offset = 0; - RomFileSystemFileEntry *cur_file_entry = NULL; - RomFileSystemDirectoryEntry *cur_dir_entry = NULL; - - cur_file_offset = dir_entry->file_offset; - while(cur_file_offset != ROMFS_VOID_ENTRY) - { - if (!(cur_file_entry = romfsGetFileEntryByOffset(ctx, cur_file_offset))) - { - LOGFILE("Failed to retrieve file entry!"); - return false; - } - - total_size += cur_file_entry->size; - cur_file_offset = cur_file_entry->next_offset; - } - - cur_dir_offset = dir_entry->directory_offset; - while(cur_dir_offset != ROMFS_VOID_ENTRY) - { - if (!(cur_dir_entry = romfsGetDirectoryEntryByOffset(ctx, cur_dir_offset)) || !romfsGetDirectoryDataSize(ctx, cur_dir_entry, &child_dir_size)) - { - LOGFILE("Failed to retrieve directory entry/size!"); - return false; - } - - total_size += child_dir_size; - cur_dir_offset = cur_dir_entry->next_offset; - } - - *out_size = total_size; - - return true; -} - -RomFileSystemDirectoryEntry *romfsGetDirectoryEntryByPath(RomFileSystemContext *ctx, const char *path) -{ - size_t path_len = 0; - char *path_dup = NULL, *pch = NULL; - RomFileSystemDirectoryEntry *dir_entry = NULL; - - if (!ctx || !ctx->dir_table || !ctx->dir_table_size || !path || *path != '/' || !(path_len = strlen(path)) || !(dir_entry = romfsGetDirectoryEntryByOffset(ctx, 0))) - { - LOGFILE("Invalid parameters!"); - return NULL; - } - - /* Check if the root directory was requested */ - if (path_len == 1) return dir_entry; - - /* Duplicate path to avoid problems with strtok() */ - if (!(path_dup = strdup(path))) - { - LOGFILE("Unable to duplicate input path!"); - return NULL; - } - - pch = strtok(path_dup, "/"); - if (!pch) - { - LOGFILE("Failed to tokenize input path!"); - dir_entry = NULL; - goto out; - } - - while(pch) - { - if (!(dir_entry = romfsGetChildDirectoryEntryByName(ctx, dir_entry, pch))) - { - LOGFILE("Failed to retrieve directory entry by name!"); - break; - } - - pch = strtok(NULL, "/"); - } - -out: - if (path_dup) free(path_dup); - - return dir_entry; -} - -RomFileSystemFileEntry *romfsGetFileEntryByPath(RomFileSystemContext *ctx, const char *path) -{ - size_t path_len = 0; - char *path_dup = NULL, *filename = NULL; - RomFileSystemFileEntry *file_entry = NULL; - RomFileSystemDirectoryEntry *dir_entry = NULL; - - if (!ctx || !ctx->file_table || !ctx->file_table_size || !path || *path != '/' || (path_len = strlen(path)) <= 1) - { - LOGFILE("Invalid parameters!"); - return NULL; - } - - /* Duplicate path */ - if (!(path_dup = strdup(path))) - { - LOGFILE("Unable to duplicate input path!"); - return NULL; - } - - /* Remove any trailing slashes */ - while(path_dup[path_len - 1] == '/') - { - path_dup[path_len - 1] = '\0'; - path_len--; - } - - /* Safety check */ - if (!path_len || !(filename = strrchr(path_dup, '/'))) - { - LOGFILE("Invalid input path!"); - goto out; - } - - /* Remove leading slash and adjust filename string pointer */ - *filename++ = '\0'; - - /* Retrieve directory entry */ - /* If the first character is NULL, then just retrieve the root directory entry */ - if (!(dir_entry = (*path_dup ? romfsGetDirectoryEntryByPath(ctx, path_dup) : romfsGetDirectoryEntryByOffset(ctx, 0)))) - { - LOGFILE("Failed to retrieve directory entry!"); - goto out; - } - - /* Retrieve file entry */ - if (!(file_entry = romfsGetChildFileEntryByName(ctx, dir_entry, filename))) LOGFILE("Failed to retrieve file entry by name!"); - -out: - if (path_dup) free(path_dup); - - return file_entry; -} - -bool romfsGeneratePathFromDirectoryEntry(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, char *out_path, size_t out_path_size) -{ - size_t path_len = 0; - u32 dir_offset = ROMFS_VOID_ENTRY, dir_entries_count = 0; - RomFileSystemDirectoryEntry **dir_entries = NULL, **tmp_dir_entries = NULL; bool success = false; + out->patch_info = &(update_nca_fs_ctx->header->patch_info); + out->size = out->patch_romfs_ctx.size; + out->virtual_seek = out->base_seek = out->patch_seek = 0; - if (!ctx || !ctx->dir_table || !ctx->dir_table_size || !dir_entry || (!dir_entry->name_length && dir_entry->parent_offset) || !out_path || out_path_size < 2) - { - LOGFILE("Invalid parameters!"); - return false; - } - /* Check if we're dealing with the root directory entry */ - if (!dir_entry->name_length) - { - sprintf(out_path, "/"); - return true; - } - /* Allocate memory for our directory entries */ - dir_entries = calloc(1, sizeof(RomFileSystemDirectoryEntry*)); - if (!dir_entries) - { - LOGFILE("Unable to allocate memory for directory entries!"); - return false; - } - path_len = (1 + dir_entry->name_length); - *dir_entries = dir_entry; - dir_entries_count++; - while(true) - { - dir_offset = dir_entries[dir_entries_count - 1]->parent_offset; - if (!dir_offset) break; - - /* Reallocate directory entries */ - if (!(tmp_dir_entries = realloc(dir_entries, (dir_entries_count + 1) * sizeof(RomFileSystemDirectoryEntry*)))) - { - LOGFILE("Unable to reallocate directory entries buffer!"); - goto out; - } - - dir_entries = tmp_dir_entries; - tmp_dir_entries = NULL; - - if (!(dir_entries[dir_entries_count] = romfsGetDirectoryEntryByOffset(ctx, dir_offset)) || !dir_entries[dir_entries_count]->name_length) - { - LOGFILE("Failed to retrieve directory entry!"); - goto out; - } - - path_len += (1 + dir_entries[dir_entries_count]->name_length); - dir_entries_count++; - } - if (path_len >= out_path_size) - { - LOGFILE("Output path length exceeds output buffer size!"); - goto out; - } - - /* Generate output path */ - *out_path = '\0'; - for(u32 i = dir_entries_count; i > 0; i--) - { - strcat(out_path, "/"); - strncat(out_path, dir_entries[i - 1]->name, dir_entries[i - 1]->name_length); - } success = true; -out: - if (dir_entries) free(dir_entries); +exit: + if (!success) bktrFreeContext(out); return success; } -bool romfsGeneratePathFromFileEntry(RomFileSystemContext *ctx, RomFileSystemFileEntry *file_entry, char *out_path, size_t out_path_size) -{ - size_t path_len = 0; - RomFileSystemDirectoryEntry *dir_entry = NULL; - - if (!ctx || !ctx->file_table || !ctx->file_table_size || !file_entry || !file_entry->name_length || !out_path || out_path_size < 2 || \ - !(dir_entry = romfsGetDirectoryEntryByOffset(ctx, file_entry->parent_offset))) - { - LOGFILE("Invalid parameters!"); - return false; - } - - /* Retrieve full RomFS path up to the file entry name */ - if (!romfsGeneratePathFromDirectoryEntry(ctx, dir_entry, out_path, out_path_size)) - { - LOGFILE("Failed to retrieve RomFS directory path!"); - return false; - } - - /* Check path length */ - path_len = strlen(out_path); - if ((1 + file_entry->name_length) >= (out_path_size - path_len)) - { - LOGFILE("Output path length exceeds output buffer size!"); - return false; - } - - /* Concatenate file entry name */ - strcat(out_path, "/"); - strncat(out_path, file_entry->name, file_entry->name_length); - - return true; -} -bool romfsGenerateFileEntryPatch(RomFileSystemContext *ctx, RomFileSystemFileEntry *file_entry, const void *data, u64 data_size, u64 data_offset, RomFileSystemFileEntryPatch *out) -{ - if (!ctx || !ctx->nca_fs_ctx || !ctx->body_offset || (ctx->nca_fs_ctx->section_type != NcaFsSectionType_Nca0RomFs && ctx->nca_fs_ctx->section_type != NcaFsSectionType_RomFs) || !file_entry || \ - !file_entry->size || file_entry->offset >= ctx->size || (file_entry->offset + file_entry->size) > ctx->size || !data || !data_size || data_offset >= file_entry->size || \ - (data_offset + data_size) > file_entry->size || !out) - { - LOGFILE("Invalid parameters!"); - return false; - } - - bool success = false; - u64 fs_offset = (ctx->body_offset + file_entry->offset + data_offset); - - memset(&(out->old_format_patch), 0, sizeof(NcaHierarchicalSha256Patch)); - memset(&(out->cur_format_patch), 0, sizeof(NcaHierarchicalIntegrityPatch)); - - if (ctx->nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs) - { - out->use_old_format_patch = true; - success = ncaGenerateHierarchicalSha256Patch(ctx->nca_fs_ctx, data, data_size, fs_offset, &(out->old_format_patch)); - if (!success) LOGFILE("Failed to generate 0x%lX bytes HierarchicalSha256 patch at offset 0x%lX for RomFS file entry!", data_size, fs_offset); - } else { - out->use_old_format_patch = false; - success = ncaGenerateHierarchicalIntegrityPatch(ctx->nca_fs_ctx, data, data_size, fs_offset, &(out->cur_format_patch)); - if (!success) LOGFILE("Failed to generate 0x%lX bytes HierarchicalIntegrity patch at offset 0x%lX for RomFS file entry!", data_size, fs_offset); - } - - return success; -} -static RomFileSystemDirectoryEntry *romfsGetChildDirectoryEntryByName(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, const char *name) -{ - u64 dir_offset = 0; - size_t name_len = 0; - RomFileSystemDirectoryEntry *child_dir_entry = NULL; - - if (!ctx || !ctx->dir_table || !ctx->dir_table_size || !dir_entry || (dir_offset = dir_entry->directory_offset) == ROMFS_VOID_ENTRY || !name || !(name_len = strlen(name))) return NULL; - - while(dir_offset != ROMFS_VOID_ENTRY) - { - if (!(child_dir_entry = romfsGetDirectoryEntryByOffset(ctx, dir_offset)) || !child_dir_entry->name_length) return NULL; - if (!strncmp(child_dir_entry->name, name, name_len)) return child_dir_entry; - dir_offset = child_dir_entry->next_offset; - } - - return NULL; -} -static RomFileSystemFileEntry *romfsGetChildFileEntryByName(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, const char *name) -{ - u64 file_offset = 0; - size_t name_len = 0; - RomFileSystemFileEntry *child_file_entry = NULL; - - if (!ctx || !ctx->dir_table || !ctx->dir_table_size || !ctx->file_table || !ctx->file_table_size || !dir_entry || (file_offset = dir_entry->file_offset) == ROMFS_VOID_ENTRY || !name || \ - !(name_len = strlen(name))) return NULL; - - while(file_offset != ROMFS_VOID_ENTRY) - { - if (!(child_file_entry = romfsGetFileEntryByOffset(ctx, file_offset)) || !child_file_entry->name_length) return NULL; - if (!strncmp(child_file_entry->name, name, name_len)) return child_file_entry; - file_offset = child_file_entry->next_offset; - } - - return NULL; -} diff --git a/source/bktr.h b/source/bktr.h index 3a87218..6fdfd26 100644 --- a/source/bktr.h +++ b/source/bktr.h @@ -71,11 +71,16 @@ typedef struct { } BktrAesCtrExStorageBlock; typedef struct { - RomFileSystemContext base_romfs; ///< Base NCA RomFS context. - RomFileSystemContext patch_romfs; ///< Update NCA RomFS context. Must be used with RomFS directory/file entry functions, because it holds the updated directory/file tables. - NcaPatchInfo *patch_info; + RomFileSystemContext base_romfs_ctx; ///< Base NCA RomFS context. + RomFileSystemContext patch_romfs_ctx; ///< Update NCA RomFS context. Must be used with RomFS directory/file entry functions, because it holds the updated directory/file tables. + NcaPatchInfo *patch_info; ///< BKTR patch info block. + u64 size; ///< Patched RomFS image size. BktrIndirectStorageBlock *indirect_block; BktrAesCtrExStorageBlock *aes_ctr_ex_block; + + + + u64 virtual_seek; ///< Relative to the start of the NCA FS section. u64 base_seek; ///< Relative to the start of the NCA FS section (base NCA RomFS). u64 patch_seek; ///< Relative to the start of the NCA FS section (update NCA BKTR). @@ -88,32 +93,70 @@ bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ct NX_INLINE void bktrFreeContext(BktrContext *ctx) { if (!ctx) return; - romfsFreeContext(&(ctx->base_romfs)); - romfsFreeContext(&(ctx->update_romfs)); + romfsFreeContext(&(ctx->base_romfs_ctx)); + romfsFreeContext(&(ctx->patch_romfs_ctx)); if (ctx->indirect_block) free(ctx->indirect_block); if (ctx->aes_ctr_ex_block) free(ctx->aes_ctr_ex_block); memset(ctx, 0, sizeof(BktrContext)); } +/// Reads raw filesystem data using a BKTR context. +/// Input offset must be relative to the start of the patched RomFS image. +bool bktrReadFileSystemData(BktrContext *ctx, void *out, u64 read_size, u64 offset); - - - - - - -/// Reads raw filesystem data using a RomFS context. -/// Input offset must be relative to the start of the RomFS. -//bool romfsReadFileSystemData(RomFileSystemContext *ctx, void *out, u64 read_size, u64 offset); - -/// Reads data from a previously retrieved RomFileSystemFileEntry using a RomFS context. +/// Reads data from a previously retrieved RomFileSystemFileEntry using a BKTR context. /// Input offset must be relative to the start of the RomFS file entry data. -//bool romfsReadFileEntryData(RomFileSystemContext *ctx, RomFileSystemFileEntry *file_entry, void *out, u64 read_size, u64 offset); +bool bktrReadFileEntryData(BktrContext *ctx, RomFileSystemFileEntry *file_entry, void *out, u64 read_size, u64 offset); +/// Miscellaneous functions. +/// These are just wrappers for RomFS functions. +NX_INLINE RomFileSystemDirectoryEntry *bktrGetDirectoryEntryByOffset(BktrContext *ctx, u32 dir_entry_offset) +{ + if (!ctx) return NULL; + return romfsGetDirectoryEntryByOffset(&(ctx->patch_romfs_ctx), dir_entry_offset); +} +NX_INLINE RomFileSystemFileEntry *bktrGetFileEntryByOffset(BktrContext *ctx, u32 file_entry_offset) +{ + if (!ctx) return NULL; + return romfsGetFileEntryByOffset(&(ctx->patch_romfs_ctx), file_entry_offset); +} +NX_INLINE bool bktrGetTotalDataSize(BktrContext *ctx, u64 *out_size) +{ + if (!ctx) return false; + return romfsGetTotalDataSize(&(ctx->patch_romfs_ctx), out_size); +} +NX_INLINE bool bktrGetDirectoryDataSize(BktrContext *ctx, RomFileSystemDirectoryEntry *dir_entry, u64 *out_size) +{ + if (!ctx) return false; + return romfsGetDirectoryDataSize(&(ctx->patch_romfs_ctx), dir_entry, out_size); +} +NX_INLINE RomFileSystemDirectoryEntry *bktrGetDirectoryEntryByPath(BktrContext *ctx, const char *path) +{ + if (!ctx) return NULL; + return romfsGetDirectoryEntryByPath(&(ctx->patch_romfs_ctx), path); +} + +NX_INLINE RomFileSystemFileEntry *bktrGetFileEntryByPath(BktrContext *ctx, const char *path) +{ + if (!ctx) return NULL; + return romfsGetFileEntryByPath(&(ctx->patch_romfs_ctx), path); +} + +NX_INLINE bool bktrGeneratePathFromDirectoryEntry(BktrContext *ctx, RomFileSystemDirectoryEntry *dir_entry, char *out_path, size_t out_path_size) +{ + if (!ctx) return false; + return romfsGeneratePathFromDirectoryEntry(&(ctx->patch_romfs_ctx), dir_entry, out_path, out_path_size); +} + +NX_INLINE bool bktrGeneratePathFromFileEntry(BktrContext *ctx, RomFileSystemFileEntry *file_entry, char *out_path, size_t out_path_size) +{ + if (!ctx) return false; + return romfsGeneratePathFromFileEntry(&(ctx->patch_romfs_ctx), file_entry, out_path, out_path_size); +} #endif /* __BKTR_H__ */ diff --git a/source/cert.c b/source/cert.c index 86f14c7..e17712f 100644 --- a/source/cert.c +++ b/source/cert.c @@ -26,7 +26,7 @@ #define CERT_SAVEFILE_STORAGE_BASE_PATH "/certificate/" #define CERT_TYPE(sig) (pub_key_type == CertPubKeyType_Rsa4096 ? CertType_Sig##sig##_PubKeyRsa4096 : \ - (pub_key_type == CertPubKeyType_Rsa2048 ? CertType_Sig##sig##_PubKeyRsa2048 : CertType_Sig##sig##_PubKeyEcsda240)) + (pub_key_type == CertPubKeyType_Rsa2048 ? CertType_Sig##sig##_PubKeyRsa2048 : CertType_Sig##sig##_PubKeyEcc480)) /* Global variables. */ @@ -91,7 +91,7 @@ void certFreeCertificateChain(CertificateChain *chain) CertCommonBlock *certGetCommonBlockFromCertificate(Certificate *cert) { - if (!cert || cert->type == CertType_None || cert->type > CertType_SigEcsda240_PubKeyEcsda240 || cert->size < CERT_MIN_SIZE || cert->size > CERT_MAX_SIZE) + if (!cert || cert->type == CertType_None || cert->type > CertType_SigHmac160_PubKeyEcc480 || cert->size < CERT_MIN_SIZE || cert->size > CERT_MAX_SIZE) { LOGFILE("Invalid parameters!"); return NULL; @@ -107,8 +107,8 @@ CertCommonBlock *certGetCommonBlockFromCertificate(Certificate *cert) case CertType_SigRsa4096_PubKeyRsa2048: cert_common_blk = &(((CertSigRsa4096PubKeyRsa2048*)cert->data)->cert_common_blk); break; - case CertType_SigRsa4096_PubKeyEcsda240: - cert_common_blk = &(((CertSigRsa4096PubKeyEcsda240*)cert->data)->cert_common_blk); + case CertType_SigRsa4096_PubKeyEcc480: + cert_common_blk = &(((CertSigRsa4096PubKeyEcc480*)cert->data)->cert_common_blk); break; case CertType_SigRsa2048_PubKeyRsa4096: cert_common_blk = &(((CertSigRsa2048PubKeyRsa4096*)cert->data)->cert_common_blk); @@ -116,17 +116,26 @@ CertCommonBlock *certGetCommonBlockFromCertificate(Certificate *cert) case CertType_SigRsa2048_PubKeyRsa2048: cert_common_blk = &(((CertSigRsa2048PubKeyRsa2048*)cert->data)->cert_common_blk); break; - case CertType_SigRsa2048_PubKeyEcsda240: - cert_common_blk = &(((CertSigRsa2048PubKeyEcsda240*)cert->data)->cert_common_blk); + case CertType_SigRsa2048_PubKeyEcc480: + cert_common_blk = &(((CertSigRsa2048PubKeyEcc480*)cert->data)->cert_common_blk); break; - case CertType_SigEcsda240_PubKeyRsa4096: - cert_common_blk = &(((CertSigEcsda240PubKeyRsa4096*)cert->data)->cert_common_blk); + case CertType_SigEcc480_PubKeyRsa4096: + cert_common_blk = &(((CertSigEcc480PubKeyRsa4096*)cert->data)->cert_common_blk); break; - case CertType_SigEcsda240_PubKeyRsa2048: - cert_common_blk = &(((CertSigEcsda240PubKeyRsa2048*)cert->data)->cert_common_blk); + case CertType_SigEcc480_PubKeyRsa2048: + cert_common_blk = &(((CertSigEcc480PubKeyRsa2048*)cert->data)->cert_common_blk); break; - case CertType_SigEcsda240_PubKeyEcsda240: - cert_common_blk = &(((CertSigEcsda240PubKeyEcsda240*)cert->data)->cert_common_blk); + case CertType_SigEcc480_PubKeyEcc480: + cert_common_blk = &(((CertSigEcc480PubKeyEcc480*)cert->data)->cert_common_blk); + break; + case CertType_SigHmac160_PubKeyRsa4096: + cert_common_blk = &(((CertSigHmac160PubKeyRsa4096*)cert->data)->cert_common_blk); + break; + case CertType_SigHmac160_PubKeyRsa2048: + cert_common_blk = &(((CertSigHmac160PubKeyRsa2048*)cert->data)->cert_common_blk); + break; + case CertType_SigHmac160_PubKeyEcc480: + cert_common_blk = &(((CertSigHmac160PubKeyEcc480*)cert->data)->cert_common_blk); break; default: break; @@ -265,9 +274,12 @@ static u8 certGetCertificateType(const void *data, u64 data_size) case SignatureType_Rsa2048Sha256: offset += sizeof(SignatureBlockRsa2048); break; - case SignatureType_Ecsda240Sha1: - case SignatureType_Ecsda240Sha256: - offset += sizeof(SignatureBlockEcsda240); + case SignatureType_Ecc480Sha1: + case SignatureType_Ecc480Sha256: + offset += sizeof(SignatureBlockEcc480); + break; + case SignatureType_Hmac160Sha1: + offset += sizeof(SignatureBlockHmac160); break; default: LOGFILE("Invalid signature type value! (0x%08X)", sig_type); @@ -281,7 +293,7 @@ static u8 certGetCertificateType(const void *data, u64 data_size) offset += MEMBER_SIZE(CertCommonBlock, pub_key_type); offset += MEMBER_SIZE(CertCommonBlock, name); - offset += MEMBER_SIZE(CertCommonBlock, cert_id); + offset += MEMBER_SIZE(CertCommonBlock, date); switch(pub_key_type) { @@ -291,8 +303,8 @@ static u8 certGetCertificateType(const void *data, u64 data_size) case CertPubKeyType_Rsa2048: offset += sizeof(CertPublicKeyBlockRsa2048); break; - case CertPubKeyType_Ecsda240: - offset += sizeof(CertPublicKeyBlockEcsda240); + case CertPubKeyType_Ecc480: + offset += sizeof(CertPublicKeyBlockEcc480); break; default: LOGFILE("Invalid public key type value! (0x%08X)", pub_key_type); @@ -313,9 +325,13 @@ static u8 certGetCertificateType(const void *data, u64 data_size) { type = CERT_TYPE(Rsa2048); } else - if (sig_type == SignatureType_Ecsda240Sha1 || sig_type == SignatureType_Ecsda240Sha256) + if (sig_type == SignatureType_Ecc480Sha1 || sig_type == SignatureType_Ecc480Sha256) { - type = CERT_TYPE(Ecsda240); + type = CERT_TYPE(Ecc480); + } else + if (sig_type == SignatureType_Hmac160Sha1) + { + type = CERT_TYPE(Hmac160); } return type; diff --git a/source/cert.h b/source/cert.h index 4f2c3b2..971ac94 100644 --- a/source/cert.h +++ b/source/cert.h @@ -23,26 +23,29 @@ #include "signature.h" #define CERT_MAX_SIZE 0x500 /* Equivalent to sizeof(CertSigRsa4096PubKeyRsa4096) */ -#define CERT_MIN_SIZE 0x180 /* Equivalent to sizeof(CertSigEcsda240PubKeyEcsda240) */ +#define CERT_MIN_SIZE 0x140 /* Equivalent to sizeof(CertSigHmac160PubKeyEcc480) */ typedef enum { CertType_None = 0, CertType_SigRsa4096_PubKeyRsa4096 = 1, CertType_SigRsa4096_PubKeyRsa2048 = 2, - CertType_SigRsa4096_PubKeyEcsda240 = 3, + CertType_SigRsa4096_PubKeyEcc480 = 3, CertType_SigRsa2048_PubKeyRsa4096 = 4, CertType_SigRsa2048_PubKeyRsa2048 = 5, - CertType_SigRsa2048_PubKeyEcsda240 = 6, - CertType_SigEcsda240_PubKeyRsa4096 = 7, - CertType_SigEcsda240_PubKeyRsa2048 = 8, - CertType_SigEcsda240_PubKeyEcsda240 = 9 + CertType_SigRsa2048_PubKeyEcc480 = 6, + CertType_SigEcc480_PubKeyRsa4096 = 7, + CertType_SigEcc480_PubKeyRsa2048 = 8, + CertType_SigEcc480_PubKeyEcc480 = 9, + CertType_SigHmac160_PubKeyRsa4096 = 10, + CertType_SigHmac160_PubKeyRsa2048 = 11, + CertType_SigHmac160_PubKeyEcc480 = 12 } CertType; /// Always stored using big endian byte order. typedef enum { CertPubKeyType_Rsa4096 = 0, CertPubKeyType_Rsa2048 = 1, - CertPubKeyType_Ecsda240 = 2 + CertPubKeyType_Ecc480 = 2 } CertPubKeyType; typedef struct { @@ -60,69 +63,87 @@ typedef struct { typedef struct { u8 public_key[0x3C]; u8 padding[0x3C]; -} CertPublicKeyBlockEcsda240; +} CertPublicKeyBlockEcc480; /// Placed after the certificate signature block. typedef struct { char issuer[0x40]; - u32 pub_key_type; + u32 pub_key_type; ///< CertPubKeyType. char name[0x40]; - u32 cert_id; + u32 date; } CertCommonBlock; typedef struct { - SignatureBlockRsa4096 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Rsa4096. + SignatureBlockRsa4096 sig_block; ///< sig_type field is stored using big endian byte order. + CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Rsa4096. CertPublicKeyBlockRsa4096 pub_key_block; } CertSigRsa4096PubKeyRsa4096; typedef struct { - SignatureBlockRsa4096 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Rsa2048. + SignatureBlockRsa4096 sig_block; ///< sig_type field is stored using big endian byte order. + CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Rsa2048. CertPublicKeyBlockRsa2048 pub_key_block; } CertSigRsa4096PubKeyRsa2048; typedef struct { - SignatureBlockRsa4096 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Ecsda240. - CertPublicKeyBlockEcsda240 pub_key_block; -} CertSigRsa4096PubKeyEcsda240; + SignatureBlockRsa4096 sig_block; ///< sig_type field is stored using big endian byte order. + CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Ecc480. + CertPublicKeyBlockEcc480 pub_key_block; +} CertSigRsa4096PubKeyEcc480; typedef struct { - SignatureBlockRsa2048 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Rsa4096. + SignatureBlockRsa2048 sig_block; ///< sig_type field is stored using big endian byte order. + CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Rsa4096. CertPublicKeyBlockRsa4096 pub_key_block; } CertSigRsa2048PubKeyRsa4096; typedef struct { - SignatureBlockRsa2048 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Rsa2048. + SignatureBlockRsa2048 sig_block; ///< sig_type field is stored using big endian byte order. + CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Rsa2048. CertPublicKeyBlockRsa2048 pub_key_block; } CertSigRsa2048PubKeyRsa2048; typedef struct { - SignatureBlockRsa2048 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Ecsda240. - CertPublicKeyBlockEcsda240 pub_key_block; -} CertSigRsa2048PubKeyEcsda240; + SignatureBlockRsa2048 sig_block; ///< sig_type field is stored using big endian byte order. + CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Ecc480. + CertPublicKeyBlockEcc480 pub_key_block; +} CertSigRsa2048PubKeyEcc480; typedef struct { - SignatureBlockEcsda240 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Rsa4096. + SignatureBlockEcc480 sig_block; ///< sig_type field is stored using big endian byte order. + CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Rsa4096. CertPublicKeyBlockRsa4096 pub_key_block; -} CertSigEcsda240PubKeyRsa4096; +} CertSigEcc480PubKeyRsa4096; typedef struct { - SignatureBlockEcsda240 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Rsa2048. + SignatureBlockEcc480 sig_block; ///< sig_type field is stored using big endian byte order. + CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Rsa2048. CertPublicKeyBlockRsa2048 pub_key_block; -} CertSigEcsda240PubKeyRsa2048; +} CertSigEcc480PubKeyRsa2048; typedef struct { - SignatureBlockEcsda240 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Ecsda240. - CertPublicKeyBlockEcsda240 pub_key_block; -} CertSigEcsda240PubKeyEcsda240; + SignatureBlockEcc480 sig_block; ///< sig_type field is stored using big endian byte order. + CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Ecc480. + CertPublicKeyBlockEcc480 pub_key_block; +} CertSigEcc480PubKeyEcc480; + +typedef struct { + SignatureBlockHmac160 sig_block; ///< sig_type field is stored using big endian byte order. + CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Rsa4096. + CertPublicKeyBlockRsa4096 pub_key_block; +} CertSigHmac160PubKeyRsa4096; + +typedef struct { + SignatureBlockHmac160 sig_block; ///< sig_type field is stored using big endian byte order. + CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Rsa2048. + CertPublicKeyBlockRsa2048 pub_key_block; +} CertSigHmac160PubKeyRsa2048; + +typedef struct { + SignatureBlockHmac160 sig_block; ///< sig_type field is stored using big endian byte order. + CertCommonBlock cert_common_blk; ///< pub_key_type field must be CertPubKeyType_Ecc480. + CertPublicKeyBlockEcc480 pub_key_block; +} CertSigHmac160PubKeyEcc480; /// Used to store certificate type, size and raw data. typedef struct { diff --git a/source/nca.h b/source/nca.h index 15a5d36..0063739 100644 --- a/source/nca.h +++ b/source/nca.h @@ -321,7 +321,7 @@ bool ncaReadContentFile(NcaContext *ctx, void *out, u64 read_size, u64 offset); /// Reads decrypted data from a NCA FS section using an input context. /// Input offset must be relative to the start of the NCA FS section. -/// If dealing with Patch RomFS sections, this function should only be used when *not* reading BKTR subsections. +/// If dealing with Patch RomFS sections, this function should only be used when *not* reading the BKTR AesCtrEx storage. bool ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size, u64 offset); /// Returns a pointer to a heap-allocated buffer used to encrypt the input plaintext data, based on the encryption type used by the input NCA FS section, as well as its offset and size. diff --git a/source/pfs.c b/source/pfs.c index 96231c4..7e220e0 100644 --- a/source/pfs.c +++ b/source/pfs.c @@ -86,6 +86,7 @@ bool pfsInitializeContext(PartitionFileSystemContext *out, NcaFsSectionContext * if (!ncaReadFsSection(nca_fs_ctx, out->header, out->header_size, out->offset)) { LOGFILE("Failed to read full partition FS header!"); + pfsFreeContext(out); return false; } diff --git a/source/romfs.c b/source/romfs.c index bca0bf3..78695f6 100644 --- a/source/romfs.c +++ b/source/romfs.c @@ -31,9 +31,10 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_ NcaContext *nca_ctx = NULL; u64 dir_table_offset = 0, file_table_offset = 0; - if (!out || !nca_fs_ctx || nca_fs_ctx->section_type != NcaFsSectionType_RomFs || !nca_fs_ctx->header || !(nca_ctx = (NcaContext*)nca_fs_ctx->nca_ctx) || \ - (nca_ctx->format_version == NcaVersion_Nca0 && (nca_fs_ctx->section_type != NcaFsSectionType_Nca0RomFs || nca_fs_ctx->header->hash_type != NcaHashType_HierarchicalSha256)) || \ - (nca_ctx->format_version != NcaVersion_Nca0 && (nca_fs_ctx->section_type != NcaFsSectionType_RomFs || nca_fs_ctx->header->hash_type != NcaHashType_HierarchicalIntegrity))) + if (!out || !nca_fs_ctx || (nca_fs_ctx->section_type != NcaFsSectionType_RomFs && nca_fs_ctx->section_type != NcaFsSectionType_PatchRomFs) || !nca_fs_ctx->header || \ + !(nca_ctx = (NcaContext*)nca_fs_ctx->nca_ctx) || (nca_ctx->format_version == NcaVersion_Nca0 && (nca_fs_ctx->section_type != NcaFsSectionType_Nca0RomFs || \ + nca_fs_ctx->header->hash_type != NcaHashType_HierarchicalSha256)) || (nca_ctx->format_version != NcaVersion_Nca0 && (nca_fs_ctx->section_type != NcaFsSectionType_RomFs || \ + nca_fs_ctx->header->hash_type != NcaHashType_HierarchicalIntegrity))) { LOGFILE("Invalid parameters!"); return false; @@ -85,6 +86,8 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_ return false; } + bool success = false; + /* Read directory entries table */ dir_table_offset = (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.directory_entry_offset : out->header.cur_format.directory_entry_offset); out->dir_table_size = (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.directory_entry_size : out->header.cur_format.directory_entry_size); @@ -106,7 +109,7 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_ if (!ncaReadFsSection(nca_fs_ctx, out->dir_table, out->dir_table_size, out->offset + dir_table_offset)) { LOGFILE("Failed to read RomFS directory entries table!"); - return false; + goto exit; } /* Read file entries table */ @@ -117,20 +120,20 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_ if (!out->file_table_size || (nca_fs_ctx->encryption_type != NcaEncryptionType_AesCtrEx && (file_table_offset >= out->size || (file_table_offset + out->file_table_size) > out->size))) { LOGFILE("Invalid RomFS file entries table!"); - return false; + goto exit; } out->file_table = malloc(out->file_table_size); if (!out->file_table) { LOGFILE("Unable to allocate memory for RomFS file entries table!"); - return false; + goto exit; } if (!ncaReadFsSection(nca_fs_ctx, out->file_table, out->file_table_size, out->offset + file_table_offset)) { LOGFILE("Failed to read RomFS file entries table!"); - return false; + goto exit; } /* Get file data body offset */ @@ -139,10 +142,15 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_ if (nca_fs_ctx->encryption_type != NcaEncryptionType_AesCtrEx && out->body_offset >= out->size) { LOGFILE("Invalid RomFS file data body!"); - return false; + goto exit; } - return true; + success = true; + +exit: + if (!success) romfsFreeContext(out); + + return success; } bool romfsReadFileSystemData(RomFileSystemContext *ctx, void *out, u64 read_size, u64 offset) diff --git a/source/romfs.h b/source/romfs.h index cfcaf04..8e1451e 100644 --- a/source/romfs.h +++ b/source/romfs.h @@ -130,7 +130,7 @@ bool romfsReadFileEntryData(RomFileSystemContext *ctx, RomFileSystemFileEntry *f bool romfsGetTotalDataSize(RomFileSystemContext *ctx, u64 *out_size); /// Calculates the extracted size from a RomFS directory. -bool romfsGetDirectoryDataSize(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, u64 *out_size); +bool romfsGetDirectoryDataSize(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, u64 *out_size); /// Retrieves a RomFS directory entry by path. /// Input path must have a leading slash ('/'). If just a single slash is provided, a pointer to the root directory entry shall be returned. diff --git a/source/signature.h b/source/signature.h index 2c30c5c..e609cb6 100644 --- a/source/signature.h +++ b/source/signature.h @@ -20,12 +20,13 @@ #define __SIGNATURE_H__ typedef enum { - SignatureType_Rsa4096Sha1 = 0x10000, - SignatureType_Rsa2048Sha1 = 0x10001, - SignatureType_Ecsda240Sha1 = 0x10002, - SignatureType_Rsa4096Sha256 = 0x10003, - SignatureType_Rsa2048Sha256 = 0x10004, - SignatureType_Ecsda240Sha256 = 0x10005 + SignatureType_Rsa4096Sha1 = 0x10000, + SignatureType_Rsa2048Sha1 = 0x10001, + SignatureType_Ecc480Sha1 = 0x10002, + SignatureType_Rsa4096Sha256 = 0x10003, + SignatureType_Rsa2048Sha256 = 0x10004, + SignatureType_Ecc480Sha256 = 0x10005, + SignatureType_Hmac160Sha1 = 0x10006 } SignatureType; typedef struct { @@ -41,9 +42,15 @@ typedef struct { } SignatureBlockRsa2048; typedef struct { - u32 sig_type; ///< SignatureType_Ecsda240Sha1, SignatureType_Ecsda240Sha256. + u32 sig_type; ///< SignatureType_Ecc480Sha1, SignatureType_Ecc480Sha256. u8 signature[0x3C]; u8 padding[0x40]; -} SignatureBlockEcsda240; +} SignatureBlockEcc480; + +typedef struct { + u32 sig_type; ///< SignatureType_Hmac160Sha1. + u8 signature[0x14]; + u8 padding[0x28]; +} SignatureBlockHmac160; #endif /* __SIGNATURE_H__ */ diff --git a/source/tik.c b/source/tik.c index 38e9281..0232315 100644 --- a/source/tik.c +++ b/source/tik.c @@ -83,7 +83,7 @@ bool tikRetrieveTicketByRightsId(Ticket *dst, const FsRightsId *id, bool use_gam } /* Check if this ticket has already been retrieved */ - if (dst->type > TikType_None && dst->type <= TikType_SigEcsda240 && dst->size >= TIK_MIN_SIZE && dst->size <= TIK_MAX_SIZE) + if (dst->type > TikType_None && dst->type <= TikType_SigHmac160 && dst->size >= TIK_MIN_SIZE && dst->size <= TIK_MAX_SIZE) { TikCommonBlock *tik_common_blk = tikGetCommonBlockFromTicket(dst); if (tik_common_blk && !memcmp(tik_common_blk->rights_id.c, id->c, 0x10)) return true; @@ -115,7 +115,7 @@ bool tikRetrieveTicketByRightsId(Ticket *dst, const FsRightsId *id, bool use_gam TikCommonBlock *tikGetCommonBlockFromTicket(Ticket *tik) { - if (!tik || tik->type == TikType_None || tik->type > TikType_SigEcsda240 || tik->size < TIK_MIN_SIZE || tik->size > TIK_MAX_SIZE) + if (!tik || tik->type == TikType_None || tik->type > TikType_SigHmac160 || tik->size < TIK_MIN_SIZE || tik->size > TIK_MAX_SIZE) { LOGFILE("Invalid parameters!"); return NULL; @@ -131,8 +131,11 @@ TikCommonBlock *tikGetCommonBlockFromTicket(Ticket *tik) case TikType_SigRsa2048: tik_common_blk = &(((TikSigRsa2048*)tik->data)->tik_common_blk); break; - case TikType_SigEcsda240: - tik_common_blk = &(((TikSigEcsda240*)tik->data)->tik_common_blk); + case TikType_SigEcc480: + tik_common_blk = &(((TikSigEcc480*)tik->data)->tik_common_blk); + break; + case TikType_SigHmac160: + tik_common_blk = &(((TikSigHmac160*)tik->data)->tik_common_blk); break; default: break; @@ -143,7 +146,7 @@ TikCommonBlock *tikGetCommonBlockFromTicket(Ticket *tik) void tikConvertPersonalizedTicketToCommonTicket(Ticket *tik) { - if (!tik || tik->type == TikType_None || tik->type > TikType_SigEcsda240 || tik->size < TIK_MIN_SIZE || tik->size > TIK_MAX_SIZE) return; + if (!tik || tik->type == TikType_None || tik->type > TikType_SigHmac160 || tik->size < TIK_MIN_SIZE || tik->size > TIK_MAX_SIZE) return; bool dev_cert = false; TikCommonBlock *tik_common_blk = NULL; @@ -161,9 +164,13 @@ void tikConvertPersonalizedTicketToCommonTicket(Ticket *tik) tik->size = sizeof(TikSigRsa2048); memset(tik->data + 4, 0xFF, MEMBER_SIZE(SignatureBlockRsa2048, signature)); break; - case TikType_SigEcsda240: - tik->size = sizeof(TikSigEcsda240); - memset(tik->data + 4, 0xFF, MEMBER_SIZE(SignatureBlockEcsda240, signature)); + case TikType_SigEcc480: + tik->size = sizeof(TikSigEcc480); + memset(tik->data + 4, 0xFF, MEMBER_SIZE(SignatureBlockEcc480, signature)); + break; + case TikType_SigHmac160: + tik->size = sizeof(TikSigHmac160); + memset(tik->data + 4, 0xFF, MEMBER_SIZE(SignatureBlockHmac160, signature)); break; default: break; @@ -362,9 +369,12 @@ static TikCommonBlock *tikGetCommonBlockFromMemoryBuffer(void *data) case SignatureType_Rsa2048Sha256: tik_common_blk = (TikCommonBlock*)(data_u8 + sizeof(SignatureBlockRsa2048)); break; - case SignatureType_Ecsda240Sha1: - case SignatureType_Ecsda240Sha256: - tik_common_blk = (TikCommonBlock*)(data_u8 + sizeof(SignatureBlockEcsda240)); + case SignatureType_Ecc480Sha1: + case SignatureType_Ecc480Sha256: + tik_common_blk = (TikCommonBlock*)(data_u8 + sizeof(SignatureBlockEcc480)); + break; + case SignatureType_Hmac160Sha1: + tik_common_blk = (TikCommonBlock*)(data_u8 + sizeof(SignatureBlockHmac160)); break; default: LOGFILE("Invalid signature type value! (0x%08X)", sig_type); @@ -572,10 +582,14 @@ static bool tikGetTicketTypeAndSize(const void *data, u64 data_size, u8 *out_typ type = TikType_SigRsa2048; offset += sizeof(SignatureBlockRsa2048); break; - case SignatureType_Ecsda240Sha1: - case SignatureType_Ecsda240Sha256: - type = TikType_SigEcsda240; - offset += sizeof(SignatureBlockEcsda240); + case SignatureType_Ecc480Sha1: + case SignatureType_Ecc480Sha256: + type = TikType_SigEcc480; + offset += sizeof(SignatureBlockEcc480); + break; + case SignatureType_Hmac160Sha1: + type = TikType_SigHmac160; + offset += sizeof(SignatureBlockHmac160); break; default: LOGFILE("Invalid signature type value! (0x%08X)", sig_type); diff --git a/source/tik.h b/source/tik.h index 2240e95..3ae9e48 100644 --- a/source/tik.h +++ b/source/tik.h @@ -23,13 +23,14 @@ #include "signature.h" #define TIK_MAX_SIZE 0x400 /* Max ticket entry size in the ES ticket system savedata file */ -#define TIK_MIN_SIZE 0x200 /* Equivalent to sizeof(TikSigEcsda240) - assuming no ESv2 records are available */ +#define TIK_MIN_SIZE 0x1C0 /* Equivalent to sizeof(TikSigHmac160) - assuming no ESv2 records are available */ typedef enum { TikType_None = 0, TikType_SigRsa4096 = 1, TikType_SigRsa2048 = 2, - TikType_SigEcsda240 = 3 + TikType_SigEcc480 = 3, + TikType_SigHmac160 = 4 } TikType; typedef enum { @@ -96,9 +97,14 @@ typedef struct { } TikSigRsa2048; typedef struct { - SignatureBlockEcsda240 sig_block; + SignatureBlockEcc480 sig_block; TikCommonBlock tik_common_blk; -} TikSigEcsda240; +} TikSigEcc480; + +typedef struct { + SignatureBlockHmac160 sig_block; + TikCommonBlock tik_common_blk; +} TikSigHmac160; /// Section records are placed right after the ticket data. These aren't available in TikTitleKeyType_Common tickets. /// These are only used if the sect_* fields are non-zero (other than 'sect_hdr_offset'). diff --git a/source/utils.h b/source/utils.h index e2f5161..3e4dc64 100644 --- a/source/utils.h +++ b/source/utils.h @@ -34,8 +34,30 @@ #define BIS_SYSTEM_PARTITION_MOUNT_NAME "sys:" + + + + + #define NPDM_META_MAGIC 0x4D455441 /* "META" */ +#define TITLE_PATCH_BITMASK (u64)0x800 +#define TITLE_ADDON_BITMASK (u64)0xFFFFFFFFFFFF0000 + + +NX_INLINE u64 titleGetPatchIdFromApplicationId(u64 app_id) +{ + return (app_id | TITLE_PATCH_BITMASK); +} + +NX_INLINE u64 titleGetApplicationIdFromPatchId(u64 patch_id) +{ + return (patch_id & ~TITLE_PATCH_BITMASK); +} + + + + typedef enum { UtilsCustomFirmwareType_Unknown = 0, UtilsCustomFirmwareType_Atmosphere = 1,