Compare commits

..

No commits in common. "development-tip" and "v1.6.2" have entirely different histories.

56 changed files with 887 additions and 1094 deletions

View file

@ -1,10 +1,10 @@
name: Compile Project (Push/PR/Release)
name: Compile Master Branch
on:
push:
branches: [ development-tip, stable ]
branches: [ master ]
pull_request:
branches: [ development-tip, stable ]
branches: [ master ]
release:
types: [ created ]
@ -20,25 +20,22 @@ jobs:
- dist: ubuntu_x86_64
os: ubuntu-latest
arch: x86_64
bin_ext:
- dist: macos_x86_64
os: macos-latest
arch: x86_64
bin_ext:
- dist: macos_arm64
os: macos-latest
arch: arm64
bin_ext:
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v1
- name: Clone submodules
run: git submodule init && git submodule update
- name: Compile ${{ matrix.prog }}
run: make PROJECT_PLATFORM_ARCH=${{ matrix.arch }} deps all
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v2
with:
name: ${{ matrix.prog }}-${{ matrix.dist }}
path: ./bin/${{ matrix.prog }}${{ matrix.bin_ext }}
path: ./bin/${{ matrix.prog }}
build_visualstudio:
name: Compile ${{ matrix.prog }} for ${{ matrix.dist }}
runs-on: ${{ matrix.os }}
@ -52,22 +49,21 @@ jobs:
platform: x64
configuration: Release
build_path: x64\Release
bin_ext: .exe
- dist: win_x86
os: windows-latest
platform: x86
configuration: Release
build_path: Release
bin_ext: .exe
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v1
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v1.3
uses: microsoft/setup-msbuild@v1.1
- name: Clone submodules
run: git submodule init && git submodule update
- name: Compile ${{ matrix.prog }}
run: msbuild .\build\visualstudio\${{ matrix.prog }}.sln /p:configuration=${{ matrix.configuration }} /p:platform=${{ matrix.platform }}
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v2
with:
name: ${{ matrix.prog }}-${{ matrix.dist }}
path: .\build\visualstudio\${{ matrix.build_path }}\${{ matrix.prog }}${{ matrix.bin_ext }}
path: .\build\visualstudio\${{ matrix.build_path }}\${{ matrix.prog }}.exe

33
.gitmodules vendored
View file

@ -1,15 +1,24 @@
[submodule "deps/libmbedtls"]
path = deps/libmbedtls
url = https://github.com/jakcron/libmbedtls.git
[submodule "deps/libfmt"]
path = deps/libfmt
url = https://github.com/jakcron/libfmt.git
[submodule "deps/libtoolchain"]
path = deps/libtoolchain
url = https://github.com/jakcron/libtoolchain.git
[submodule "deps/liblz4"]
path = deps/liblz4
url = https://github.com/jakcron/liblz4.git
[submodule "deps/libpietendo"]
path = deps/libpietendo
url = https://github.com/jakcron/libpietendo.git
[submodule "deps/libmbedtls"]
path = deps/libmbedtls
url = https://github.com/jakcron/libmbedtls
[submodule "deps/libtoolchain"]
path = deps/libtoolchain
url = https://github.com/jakcron/libtoolchain.git
[submodule "deps/libfmt"]
path = deps/libfmt
url = https://github.com/jakcron/libfmt.git
[submodule "deps/libnintendo-pki"]
path = deps/libnintendo-pki
url = https://github.com/jakcron/libnintendo-pki.git
[submodule "deps/libnintendo-es"]
path = deps/libnintendo-es
url = https://github.com/jakcron/libnintendo-es.git
[submodule "deps/libnintendo-hac"]
path = deps/libnintendo-hac
url = https://github.com/jakcron/libnintendo-hac.git
[submodule "deps/libnintendo-hac-hb"]
path = deps/libnintendo-hac-hb
url = https://github.com/jakcron/libnintendo-hac-hb.git

View file

@ -1,13 +1,4 @@
# Building
## Git Submodules
This project makes use of git submodules to import dependencies into the source tree.
After cloning this repository using git, prior to building NSTool the dependencies need to be downloaded.
Run these two commands to initialise and download the dependencies:
```
git submodule init
git submodule update
```
## Linux (incl. Windows Subsystem for Linux) & MacOS - Makefile
### Requirements
* `make`

View file

@ -143,16 +143,6 @@ nstool -x /path/to/a/file.bin ./extract_dir/different_name.bin some_file.bin
* NSP
* XCI
## NCA Patches
Nintendo distributes game patches/updates in the style of a diff to keep file sizes down. This means extracting game patches requires the base version of the game to be able to process patch data. Typically this is only done for the Program NCA.
If `basegame_v0.nca` is the base Program NCA, and `gamepatch_v13219.nca` is the patch Program NCA, simply specify the base NCA using the base NCA option `--basenca` when processing the patch NCA.
```
nstool --basenca ./basegame_v0.nca -x ./patchdata gamepatch_v13219.nca
```
In the above example the patch NCA is being extracted to `./patchdata`
## Encrypted Files
Some Nintendo Switch files are partially or completely encrypted. These require the user to supply the encryption keys to NSTool so that it can process them.

View file

@ -203,18 +203,4 @@ nstool <32 char rightsid>.tik
##### Personalised Tickets
If the ticket is personalised (encrypted with console unique RSA key), NSTool will not support it. You will need to use extract the title key with another tool and pass the encrypted title key directly with the `--titlekey` option.
# Title Keys (title.keys)
In order for NSTool to decrypt NCA files that use external content keys, the ticket or key data be provided to NSTool. For convience NSTool supports the hactool `title.keys` format. This file can store a dictionary of title keys, so that specifying a ticket or key data manually is not required, provided it is present in `title.keys`. This file must be present in: ___$HOME/.switch/___ .
## Format
* This file is in the format of (rights_id = title_key) pairs, each on their own line.
* There is no limit on the number of pairs.
* The `;` is the comment indicator. When parsing a file, it is treated as a new line character.
* The format is case insensitive
### Example
For example if rights id `010003000e1468000000000000000008` had a title key `8fa820b219781d331cca08968e6e5b52`, the row would look like this:
```
010003000e1468000000000000000008 = 8fa820b219781d331cca08968e6e5b52
```
# Title

View file

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32616.157
# Visual Studio Version 16
VisualStudioVersion = 16.0.31229.75
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nstool", "nstool\nstool.vcxproj", "{775EF5EB-CA49-4994-8AC4-47B4A5385266}"
EndProject
@ -9,14 +9,23 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deps", "deps", "{05929EAE-4
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblz4", "..\..\deps\liblz4\build\visualstudio\liblz4\liblz4.vcxproj", "{E741ADED-7900-4E07-8DB0-D008C336C3FB}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnintendo-es", "..\..\deps\libnintendo-es\build\visualstudio\libnintendo-es\libnintendo-es.vcxproj", "{8616D6C9-C8DE-4C3F-AFC2-625636664C2B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnintendo-hac", "..\..\deps\libnintendo-hac\build\visualstudio\libnintendo-hac\libnintendo-hac.vcxproj", "{8885C125-83FB-4F73-A93A-C712B1434D54}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnintendo-hac-hb", "..\..\deps\libnintendo-hac-hb\build\visualstudio\libnintendo-hac-hb\libnintendo-hac-hb.vcxproj", "{24D001B4-D439-4967-9371-DC3E0523EB19}"
ProjectSection(ProjectDependencies) = postProject
{8885C125-83FB-4F73-A93A-C712B1434D54} = {8885C125-83FB-4F73-A93A-C712B1434D54}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnintendo-pki", "..\..\deps\libnintendo-pki\build\visualstudio\libnintendo-pki\libnintendo-pki.vcxproj", "{0BEF63A0-2801-4563-AB65-1E2FD881C3AF}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmbedtls", "..\..\deps\libmbedtls\build\visualstudio\libmbedtls\libmbedtls.vcxproj", "{7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtoolchain", "..\..\deps\libtoolchain\build\visualstudio\libtoolchain\libtoolchain.vcxproj", "{E194E4B8-1482-40A2-901B-75D4387822E9}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libfmt", "..\..\deps\libfmt\build\visualstudio\libfmt\libfmt.vcxproj", "{F4B0540E-0AAE-4006-944B-356944EF61FA}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpietendo", "..\..\deps\libpietendo\build\visualstudio\libpietendo\libpietendo.vcxproj", "{5ADDD009-9D25-40BE-B2A6-2F3AB4DCBBD2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@ -41,6 +50,38 @@ Global
{E741ADED-7900-4E07-8DB0-D008C336C3FB}.Release|x64.Build.0 = Release|x64
{E741ADED-7900-4E07-8DB0-D008C336C3FB}.Release|x86.ActiveCfg = Release|Win32
{E741ADED-7900-4E07-8DB0-D008C336C3FB}.Release|x86.Build.0 = Release|Win32
{8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Debug|x64.ActiveCfg = Debug|x64
{8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Debug|x64.Build.0 = Debug|x64
{8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Debug|x86.ActiveCfg = Debug|Win32
{8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Debug|x86.Build.0 = Debug|Win32
{8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Release|x64.ActiveCfg = Release|x64
{8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Release|x64.Build.0 = Release|x64
{8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Release|x86.ActiveCfg = Release|Win32
{8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Release|x86.Build.0 = Release|Win32
{8885C125-83FB-4F73-A93A-C712B1434D54}.Debug|x64.ActiveCfg = Debug|x64
{8885C125-83FB-4F73-A93A-C712B1434D54}.Debug|x64.Build.0 = Debug|x64
{8885C125-83FB-4F73-A93A-C712B1434D54}.Debug|x86.ActiveCfg = Debug|Win32
{8885C125-83FB-4F73-A93A-C712B1434D54}.Debug|x86.Build.0 = Debug|Win32
{8885C125-83FB-4F73-A93A-C712B1434D54}.Release|x64.ActiveCfg = Release|x64
{8885C125-83FB-4F73-A93A-C712B1434D54}.Release|x64.Build.0 = Release|x64
{8885C125-83FB-4F73-A93A-C712B1434D54}.Release|x86.ActiveCfg = Release|Win32
{8885C125-83FB-4F73-A93A-C712B1434D54}.Release|x86.Build.0 = Release|Win32
{24D001B4-D439-4967-9371-DC3E0523EB19}.Debug|x64.ActiveCfg = Debug|x64
{24D001B4-D439-4967-9371-DC3E0523EB19}.Debug|x64.Build.0 = Debug|x64
{24D001B4-D439-4967-9371-DC3E0523EB19}.Debug|x86.ActiveCfg = Debug|Win32
{24D001B4-D439-4967-9371-DC3E0523EB19}.Debug|x86.Build.0 = Debug|Win32
{24D001B4-D439-4967-9371-DC3E0523EB19}.Release|x64.ActiveCfg = Release|x64
{24D001B4-D439-4967-9371-DC3E0523EB19}.Release|x64.Build.0 = Release|x64
{24D001B4-D439-4967-9371-DC3E0523EB19}.Release|x86.ActiveCfg = Release|Win32
{24D001B4-D439-4967-9371-DC3E0523EB19}.Release|x86.Build.0 = Release|Win32
{0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Debug|x64.ActiveCfg = Debug|x64
{0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Debug|x64.Build.0 = Debug|x64
{0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Debug|x86.ActiveCfg = Debug|Win32
{0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Debug|x86.Build.0 = Debug|Win32
{0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Release|x64.ActiveCfg = Release|x64
{0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Release|x64.Build.0 = Release|x64
{0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Release|x86.ActiveCfg = Release|Win32
{0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Release|x86.Build.0 = Release|Win32
{7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x64.ActiveCfg = Debug|x64
{7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x64.Build.0 = Debug|x64
{7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x86.ActiveCfg = Debug|Win32
@ -65,24 +106,19 @@ Global
{F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x64.Build.0 = Release|x64
{F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x86.ActiveCfg = Release|Win32
{F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x86.Build.0 = Release|Win32
{5ADDD009-9D25-40BE-B2A6-2F3AB4DCBBD2}.Debug|x64.ActiveCfg = Debug|x64
{5ADDD009-9D25-40BE-B2A6-2F3AB4DCBBD2}.Debug|x64.Build.0 = Debug|x64
{5ADDD009-9D25-40BE-B2A6-2F3AB4DCBBD2}.Debug|x86.ActiveCfg = Debug|Win32
{5ADDD009-9D25-40BE-B2A6-2F3AB4DCBBD2}.Debug|x86.Build.0 = Debug|Win32
{5ADDD009-9D25-40BE-B2A6-2F3AB4DCBBD2}.Release|x64.ActiveCfg = Release|x64
{5ADDD009-9D25-40BE-B2A6-2F3AB4DCBBD2}.Release|x64.Build.0 = Release|x64
{5ADDD009-9D25-40BE-B2A6-2F3AB4DCBBD2}.Release|x86.ActiveCfg = Release|Win32
{5ADDD009-9D25-40BE-B2A6-2F3AB4DCBBD2}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{E741ADED-7900-4E07-8DB0-D008C336C3FB} = {05929EAE-4471-4E8E-A6F3-793A81623D7F}
{8616D6C9-C8DE-4C3F-AFC2-625636664C2B} = {05929EAE-4471-4E8E-A6F3-793A81623D7F}
{8885C125-83FB-4F73-A93A-C712B1434D54} = {05929EAE-4471-4E8E-A6F3-793A81623D7F}
{24D001B4-D439-4967-9371-DC3E0523EB19} = {05929EAE-4471-4E8E-A6F3-793A81623D7F}
{0BEF63A0-2801-4563-AB65-1E2FD881C3AF} = {05929EAE-4471-4E8E-A6F3-793A81623D7F}
{7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C} = {05929EAE-4471-4E8E-A6F3-793A81623D7F}
{E194E4B8-1482-40A2-901B-75D4387822E9} = {05929EAE-4471-4E8E-A6F3-793A81623D7F}
{F4B0540E-0AAE-4006-944B-356944EF61FA} = {05929EAE-4471-4E8E-A6F3-793A81623D7F}
{5ADDD009-9D25-40BE-B2A6-2F3AB4DCBBD2} = {05929EAE-4471-4E8E-A6F3-793A81623D7F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {ABDCFB40-D6B3-44A9-92B5-0D7AB38D9FB8}

View file

@ -76,7 +76,7 @@
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\include;$(SolutionDir)..\..\deps\liblz4\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libpietendo\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\include;$(SolutionDir)..\..\deps\libfnd\include;$(SolutionDir)..\..\deps\liblz4\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libnintendo-es\include;$(SolutionDir)..\..\deps\libnintendo-pki\include;$(SolutionDir)..\..\deps\libnintendo-hac\include;$(SolutionDir)..\..\deps\libnintendo-hac-hb\include</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
</ItemDefinitionGroup>
@ -86,7 +86,7 @@
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\include;$(SolutionDir)..\..\deps\liblz4\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libpietendo\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\include;$(SolutionDir)..\..\deps\libfnd\include;$(SolutionDir)..\..\deps\liblz4\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libnintendo-es\include;$(SolutionDir)..\..\deps\libnintendo-pki\include;$(SolutionDir)..\..\deps\libnintendo-hac\include;$(SolutionDir)..\..\deps\libnintendo-hac-hb\include</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
</ItemDefinitionGroup>
@ -98,7 +98,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\include;$(SolutionDir)..\..\deps\liblz4\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libpietendo\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\include;$(SolutionDir)..\..\deps\libfnd\include;$(SolutionDir)..\..\deps\liblz4\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libnintendo-es\include;$(SolutionDir)..\..\deps\libnintendo-pki\include;$(SolutionDir)..\..\deps\libnintendo-hac\include;$(SolutionDir)..\..\deps\libnintendo-hac-hb\include</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
@ -114,7 +114,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\include;$(SolutionDir)..\..\deps\liblz4\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libpietendo\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\include;$(SolutionDir)..\..\deps\libfnd\include;$(SolutionDir)..\..\deps\liblz4\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libnintendo-es\include;$(SolutionDir)..\..\deps\libnintendo-pki\include;$(SolutionDir)..\..\deps\libnintendo-hac\include;$(SolutionDir)..\..\deps\libnintendo-hac-hb\include</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
@ -129,15 +129,24 @@
<ProjectReference Include="$(SolutionDir)..\..\deps\liblz4\build\visualstudio\liblz4\liblz4.vcxproj">
<Project>{e741aded-7900-4e07-8db0-d008c336c3fb}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)..\..\deps\libnintendo-es\build\visualstudio\libnintendo-es\libnintendo-es.vcxproj">
<Project>{8616d6c9-c8de-4c3f-afc2-625636664c2b}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)..\..\deps\libnintendo-hac-hb\build\visualstudio\libnintendo-hac-hb\libnintendo-hac-hb.vcxproj">
<Project>{24d001b4-d439-4967-9371-dc3e0523eb19}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)..\..\deps\libnintendo-hac\build\visualstudio\libnintendo-hac\libnintendo-hac.vcxproj">
<Project>{8885c125-83fb-4f73-a93a-c712b1434d54}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)..\..\deps\libnintendo-pki\build\visualstudio\libnintendo-pki\libnintendo-pki.vcxproj">
<Project>{0bef63a0-2801-4563-ab65-1e2fd881c3af}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)..\..\deps\libmbedtls\build\visualstudio\libmbedtls\libmbedtls.vcxproj">
<Project>{7a7c66f3-2b5b-4e23-85d8-2a74fedad92c}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)..\..\deps\libtoolchain\build\visualstudio\libtoolchain\libtoolchain.vcxproj">
<Project>{e194e4b8-1482-40a2-901b-75d4387822e9}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)..\..\deps\libpietendo\build\visualstudio\libpietendo\libpietendo.vcxproj">
<Project>{5addd009-9d25-40be-b2a6-2f3ab4dcbbd2}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\AssetProcess.h" />

2
deps/libfmt vendored

@ -1 +1 @@
Subproject commit b03b081e026ceb1226b45de926babe629d6c0688
Subproject commit 53d084cc0c6ea61bbb535a873299b0ae5ff9a05d

2
deps/liblz4 vendored

@ -1 +1 @@
Subproject commit 561775a11e00cbd21a45031c64068cb5e1242608
Subproject commit b40b46406e87a753328abfda3b53dfabd2408da2

2
deps/libmbedtls vendored

@ -1 +1 @@
Subproject commit 74346376dd035e9fbc161cdb80afc646b72fde86
Subproject commit e9e56bb773111f831af8dd36ad74de73b0c31aa2

1
deps/libnintendo-es vendored Submodule

@ -0,0 +1 @@
Subproject commit 984c7e6d80729eb59035932815c00e1ad614ef77

1
deps/libnintendo-hac vendored Submodule

@ -0,0 +1 @@
Subproject commit 19d38735ba4eb393faefefc3c923144628456857

1
deps/libnintendo-hac-hb vendored Submodule

@ -0,0 +1 @@
Subproject commit 0635b0c532f4ef152506775c930b3d45f575a14c

1
deps/libnintendo-pki vendored Submodule

@ -0,0 +1 @@
Subproject commit 87fdd1be853013a95116c107520078ece7869881

1
deps/libpietendo vendored

@ -1 +0,0 @@
Subproject commit 5d50d02f8f3b8918bdfbbb599b8c4c1628660d89

2
deps/libtoolchain vendored

@ -1 +1 @@
Subproject commit 578d170f5b294e4a9feb3cc2d504896e846f204e
Subproject commit d7b48027a93ef69b9c6b0d78fe392abc0bce5e68

View file

@ -1,6 +1,6 @@
# C++/C Recursive Project Makefile
# (c) Jack
# Version 9 (20231231)
# Version 6 (20211110)
# Project Name
PROJECT_NAME = nstool
@ -23,9 +23,16 @@ ifeq ($(ROOT_PROJECT_NAME),)
export ROOT_PROJECT_DEPENDENCY_PATH = $(ROOT_PROJECT_PATH)/deps
endif
# Shared Library Definitions
PROJECT_SO_VER_MAJOR = 0
PROJECT_SO_VER_MINOR = 1
PROJECT_SO_VER_PATCH = 0
PROJECT_SONAME = $(PROJECT_NAME).so.$(PROJECT_SO_VER_MAJOR)
PROJECT_SO_FILENAME = $(PROJECT_SONAME).$(PROJECT_SO_VER_MINOR).$(PROJECT_SO_VER_PATCH)
# Project Dependencies
PROJECT_DEPEND = pietendo toolchain fmt lz4 mbedtls
PROJECT_DEPEND_LOCAL_DIR = libpietendo libtoolchain libfmt liblz4 libmbedtls
PROJECT_DEPEND = nintendo-hac-hb nintendo-hac nintendo-es nintendo-pki toolchain fmt lz4 mbedtls
PROJECT_DEPEND_LOCAL_DIR = libnintendo-hac-hb libnintendo-hac libnintendo-es libnintendo-pki libtoolchain libfmt liblz4 libmbedtls
# Generate compiler flags for including project include path
ifneq ($(PROJECT_INCLUDE_PATH),)
@ -75,47 +82,45 @@ ifeq ($(PROJECT_PLATFORM), WIN32)
# Windows Flags/Libs
CC = x86_64-w64-mingw32-gcc
CXX = x86_64-w64-mingw32-g++
DEFINEFLAGS =
WARNFLAGS = -Wall -Wno-unused-value -Wno-unused-but-set-variable
ARCHFLAGS =
INC +=
LIB += -static
ARFLAGS = cr
ARFLAGS = cr -o
else ifeq ($(PROJECT_PLATFORM), GNU)
# GNU/Linux Flags/Libs
#CC =
#CXX =
DEFINEFLAGS =
WARNFLAGS = -Wall -Wno-unused-value -Wno-unused-but-set-variable
ARCHFLAGS =
INC +=
LIB +=
ARFLAGS = cr
ARFLAGS = cr -o
else ifeq ($(PROJECT_PLATFORM), MACOS)
# MacOS Flags/Libs
#CC =
#CXX =
DEFINEFLAGS =
WARNFLAGS = -Wall -Wno-unused-value -Wno-unused-private-field
ARCHFLAGS = -arch $(PROJECT_PLATFORM_ARCH)
INC +=
LIB +=
ARFLAGS = rc
ARFLAGS = rc
endif
# Compiler Flags
CXXFLAGS = -std=c++11 $(INC) $(DEFINEFLAGS) $(WARNFLAGS) $(ARCHFLAGS) -fPIC
CFLAGS = -std=c11 $(INC) $(DEFINEFLAGS) $(WARNFLAGS) $(ARCHFLAGS) -fPIC
CXXFLAGS = -std=c++11 $(INC) $(WARNFLAGS) $(ARCHFLAGS) -fPIC
CFLAGS = -std=c11 $(INC) $(WARNFLAGS) $(ARCHFLAGS) -fPIC
# Object Files
SRC_OBJ = $(foreach dir,$(PROJECT_SRC_SUBDIRS),$(subst .cpp,.o,$(wildcard $(dir)/*.cpp))) $(foreach dir,$(PROJECT_SRC_SUBDIRS),$(subst .cc,.o,$(wildcard $(dir)/*.cc))) $(foreach dir,$(PROJECT_SRC_SUBDIRS),$(subst .c,.o,$(wildcard $(dir)/*.c)))
TESTSRC_OBJ = $(foreach dir,$(PROJECT_TESTSRC_SUBDIRS),$(subst .cpp,.o,$(wildcard $(dir)/*.cpp))) $(foreach dir,$(PROJECT_TESTSRC_SUBDIRS),$(subst .cc,.o,$(wildcard $(dir)/*.cc))) $(foreach dir,$(PROJECT_TESTSRC_SUBDIRS),$(subst .c,.o,$(wildcard $(dir)/*.c)))
# all is the default, user should specify what the default should do
# - 'static_lib' for building source as a static library
# - 'program' for building source as executable program
# - 'static_lib' for building static library
# - 'shared_lib' for building shared library
# - 'program' for building the program
# - 'test_program' for building the test program
# test_program can be used with program or static_lib, but program and static_lib cannot be used together
# These can typically be used together however *_lib and program should not be used together
all: program
clean: clean_object_files remove_binary_dir
@ -153,6 +158,10 @@ static_lib: $(SRC_OBJ) create_binary_dir
@echo LINK $(PROJECT_BIN_PATH)/$(PROJECT_NAME).a
@ar $(ARFLAGS) "$(PROJECT_BIN_PATH)/$(PROJECT_NAME).a" $(SRC_OBJ)
shared_lib: $(SRC_OBJ) create_binary_dir
@echo LINK $(PROJECT_BIN_PATH)/$(PROJECT_SO_FILENAME)
@gcc -shared -Wl,-soname,$(PROJECT_SONAME) -o "$(PROJECT_BIN_PATH)/$(PROJECT_SO_FILENAME)" $(SRC_OBJ)
# Build Program
program: $(SRC_OBJ) create_binary_dir
@echo LINK $(PROJECT_BIN_PATH)/$(PROJECT_NAME)

View file

@ -64,12 +64,12 @@ void nstool::AssetProcess::importHeader()
throw tc::NotSupportedException(mModuleName, "Input stream requires read/seek permissions.");
}
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(sizeof(pie::hac::sAssetHeader)))
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(sizeof(nn::hac::sAssetHeader)))
{
throw tc::Exception(mModuleName, "Corrupt ASET: file too small");
}
tc::ByteData scratch = tc::ByteData(sizeof(pie::hac::sAssetHeader));
tc::ByteData scratch = tc::ByteData(sizeof(nn::hac::sAssetHeader));
mFile->seek(0, tc::io::SeekOrigin::Begin);
mFile->read(scratch.data(), scratch.size());
@ -85,7 +85,10 @@ void nstool::AssetProcess::processSections()
if ((mHdr.getIconInfo().size + mHdr.getIconInfo().offset) > file_size)
throw tc::Exception(mModuleName, "ASET geometry for icon beyond file size");
fmt::print("Saving {:s}...", mIconExtractPath.get().to_string());
std::string icon_extract_path_str;
tc::io::PathUtil::pathToUnixUTF8(mIconExtractPath.get(), icon_extract_path_str);
fmt::print("Saving {:s}...", icon_extract_path_str);
writeSubStreamToFile(mFile, mHdr.getIconInfo().offset, mHdr.getIconInfo().size, mIconExtractPath.get());
}
@ -96,7 +99,6 @@ void nstool::AssetProcess::processSections()
if (mNacpExtractPath.isSet())
{
fmt::print("Saving {:s}...", mNacpExtractPath.get().to_string());
writeSubStreamToFile(mFile, mHdr.getNacpInfo().offset, mHdr.getNacpInfo().size, mNacpExtractPath.get());
}

View file

@ -3,7 +3,7 @@
#include "NacpProcess.h"
#include "RomfsProcess.h"
#include <pietendo/hac/AssetHeader.h>
#include <nn/hac/AssetHeader.h>
namespace nstool {
@ -33,7 +33,7 @@ private:
tc::Optional<tc::io::Path> mIconExtractPath;
tc::Optional<tc::io::Path> mNacpExtractPath;
pie::hac::AssetHeader mHdr;
nn::hac::AssetHeader mHdr;
NacpProcess mNacp;
RomfsProcess mRomfs;

View file

@ -1,6 +1,6 @@
#include "CnmtProcess.h"
#include <pietendo/hac/ContentMetaUtil.h>
#include <nn/hac/ContentMetaUtil.h>
nstool::CnmtProcess::CnmtProcess() :
mModuleName("nstool::CnmtProcess"),
@ -33,7 +33,7 @@ void nstool::CnmtProcess::setVerifyMode(bool verify)
mVerify = verify;
}
const pie::hac::ContentMeta& nstool::CnmtProcess::getContentMeta() const
const nn::hac::ContentMeta& nstool::CnmtProcess::getContentMeta() const
{
return mCnmt;
}
@ -67,11 +67,11 @@ void nstool::CnmtProcess::importCnmt()
void nstool::CnmtProcess::displayCnmt()
{
const pie::hac::sContentMetaHeader* cnmt_hdr = (const pie::hac::sContentMetaHeader*)mCnmt.getBytes().data();
const nn::hac::sContentMetaHeader* cnmt_hdr = (const nn::hac::sContentMetaHeader*)mCnmt.getBytes().data();
fmt::print("[ContentMeta]\n");
fmt::print(" TitleId: 0x{:016x}\n", mCnmt.getTitleId());
fmt::print(" Version: {:s} (v{:d})\n", pie::hac::ContentMetaUtil::getVersionAsString(mCnmt.getTitleVersion()), mCnmt.getTitleVersion());
fmt::print(" Type: {:s} ({:d})\n", pie::hac::ContentMetaUtil::getContentMetaTypeAsString(mCnmt.getContentMetaType()), (uint32_t)mCnmt.getContentMetaType());
fmt::print(" Version: {:s} (v{:d})\n", nn::hac::ContentMetaUtil::getVersionAsString(mCnmt.getTitleVersion()), mCnmt.getTitleVersion());
fmt::print(" Type: {:s} ({:d})\n", nn::hac::ContentMetaUtil::getContentMetaTypeAsString(mCnmt.getContentMetaType()), (uint32_t)mCnmt.getContentMetaType());
fmt::print(" Attributes: 0x{:x}", *((byte_t*)&cnmt_hdr->attributes));
if (mCnmt.getAttribute().size())
{
@ -79,7 +79,7 @@ void nstool::CnmtProcess::displayCnmt()
for (auto itr = mCnmt.getAttribute().begin(); itr != mCnmt.getAttribute().end(); itr++)
{
attribute_list.push_back(pie::hac::ContentMetaUtil::getContentMetaAttributeFlagAsString(pie::hac::cnmt::ContentMetaAttributeFlag(*itr)));
attribute_list.push_back(nn::hac::ContentMetaUtil::getContentMetaAttributeFlagAsString(nn::hac::cnmt::ContentMetaAttributeFlag(*itr)));
}
fmt::print(" [");
@ -95,28 +95,28 @@ void nstool::CnmtProcess::displayCnmt()
}
fmt::print("\n");
fmt::print(" StorageId: {:s} ({:d})\n", pie::hac::ContentMetaUtil::getStorageIdAsString(mCnmt.getStorageId()), (uint32_t)mCnmt.getStorageId());
fmt::print(" ContentInstallType: {:s} ({:d})\n", pie::hac::ContentMetaUtil::getContentInstallTypeAsString(mCnmt.getContentInstallType()),(uint32_t)mCnmt.getContentInstallType());
fmt::print(" RequiredDownloadSystemVersion: {:s} (v{:d})\n", pie::hac::ContentMetaUtil::getVersionAsString(mCnmt.getRequiredDownloadSystemVersion()), mCnmt.getRequiredDownloadSystemVersion());
fmt::print(" StorageId: {:s} ({:d})\n", nn::hac::ContentMetaUtil::getStorageIdAsString(mCnmt.getStorageId()), (uint32_t)mCnmt.getStorageId());
fmt::print(" ContentInstallType: {:s} ({:d})\n", nn::hac::ContentMetaUtil::getContentInstallTypeAsString(mCnmt.getContentInstallType()),(uint32_t)mCnmt.getContentInstallType());
fmt::print(" RequiredDownloadSystemVersion: {:s} (v{:d})\n", nn::hac::ContentMetaUtil::getVersionAsString(mCnmt.getRequiredDownloadSystemVersion()), mCnmt.getRequiredDownloadSystemVersion());
switch(mCnmt.getContentMetaType())
{
case (pie::hac::cnmt::ContentMetaType_Application):
case (nn::hac::cnmt::ContentMetaType::Application):
fmt::print(" ApplicationExtendedHeader:\n");
fmt::print(" RequiredApplicationVersion: {:s} (v{:d})\n", pie::hac::ContentMetaUtil::getVersionAsString(mCnmt.getApplicationMetaExtendedHeader().getRequiredApplicationVersion()), mCnmt.getApplicationMetaExtendedHeader().getRequiredApplicationVersion());
fmt::print(" RequiredSystemVersion: {:s} (v{:d})\n", pie::hac::ContentMetaUtil::getVersionAsString(mCnmt.getApplicationMetaExtendedHeader().getRequiredSystemVersion()), mCnmt.getApplicationMetaExtendedHeader().getRequiredSystemVersion());
fmt::print(" RequiredApplicationVersion: {:s} (v{:d})\n", nn::hac::ContentMetaUtil::getVersionAsString(mCnmt.getApplicationMetaExtendedHeader().getRequiredApplicationVersion()), mCnmt.getApplicationMetaExtendedHeader().getRequiredApplicationVersion());
fmt::print(" RequiredSystemVersion: {:s} (v{:d})\n", nn::hac::ContentMetaUtil::getVersionAsString(mCnmt.getApplicationMetaExtendedHeader().getRequiredSystemVersion()), mCnmt.getApplicationMetaExtendedHeader().getRequiredSystemVersion());
fmt::print(" PatchId: 0x{:016x}\n", mCnmt.getApplicationMetaExtendedHeader().getPatchId());
break;
case (pie::hac::cnmt::ContentMetaType_Patch):
case (nn::hac::cnmt::ContentMetaType::Patch):
fmt::print(" PatchMetaExtendedHeader:\n");
fmt::print(" RequiredSystemVersion: {:s} (v{:d})\n", pie::hac::ContentMetaUtil::getVersionAsString(mCnmt.getPatchMetaExtendedHeader().getRequiredSystemVersion()), mCnmt.getPatchMetaExtendedHeader().getRequiredSystemVersion());
fmt::print(" RequiredSystemVersion: {:s} (v{:d})\n", nn::hac::ContentMetaUtil::getVersionAsString(mCnmt.getPatchMetaExtendedHeader().getRequiredSystemVersion()), mCnmt.getPatchMetaExtendedHeader().getRequiredSystemVersion());
fmt::print(" ApplicationId: 0x{:016x}\n", mCnmt.getPatchMetaExtendedHeader().getApplicationId());
break;
case (pie::hac::cnmt::ContentMetaType_AddOnContent):
case (nn::hac::cnmt::ContentMetaType::AddOnContent):
fmt::print(" AddOnContentMetaExtendedHeader:\n");
fmt::print(" RequiredApplicationVersion: {:s} (v{:d})\n", pie::hac::ContentMetaUtil::getVersionAsString(mCnmt.getAddOnContentMetaExtendedHeader().getRequiredApplicationVersion()), mCnmt.getAddOnContentMetaExtendedHeader().getRequiredApplicationVersion());
fmt::print(" RequiredApplicationVersion: {:s} (v{:d})\n", nn::hac::ContentMetaUtil::getVersionAsString(mCnmt.getAddOnContentMetaExtendedHeader().getRequiredApplicationVersion()), mCnmt.getAddOnContentMetaExtendedHeader().getRequiredApplicationVersion());
fmt::print(" ApplicationId: 0x{:016x}\n", mCnmt.getAddOnContentMetaExtendedHeader().getApplicationId());
break;
case (pie::hac::cnmt::ContentMetaType_Delta):
case (nn::hac::cnmt::ContentMetaType::Delta):
fmt::print(" DeltaMetaExtendedHeader:\n");
fmt::print(" ApplicationId: 0x{:016x}\n", mCnmt.getDeltaMetaExtendedHeader().getApplicationId());
break;
@ -128,9 +128,9 @@ void nstool::CnmtProcess::displayCnmt()
fmt::print(" ContentInfo:\n");
for (size_t i = 0; i < mCnmt.getContentInfo().size(); i++)
{
const pie::hac::ContentInfo& info = mCnmt.getContentInfo()[i];
const nn::hac::ContentInfo& info = mCnmt.getContentInfo()[i];
fmt::print(" {:d}\n", i);
fmt::print(" Type: {:s} ({:d})\n", pie::hac::ContentMetaUtil::getContentTypeAsString(info.getContentType()), (uint32_t)info.getContentType());
fmt::print(" Type: {:s} ({:d})\n", nn::hac::ContentMetaUtil::getContentTypeAsString(info.getContentType()), (uint32_t)info.getContentType());
fmt::print(" Id: {:s}\n", tc::cli::FormatUtil::formatBytesAsString(info.getContentId().data(), info.getContentId().size(), false, ""));
fmt::print(" Size: 0x{:x}\n", info.getContentSize());
fmt::print(" Hash: {:s}\n", tc::cli::FormatUtil::formatBytesAsString(info.getContentHash().data(), info.getContentHash().size(), false, ""));
@ -143,19 +143,19 @@ void nstool::CnmtProcess::displayCnmt()
}
// print extended data
if (mCnmt.getContentMetaType() == pie::hac::cnmt::ContentMetaType_Patch && mCnmt.getPatchMetaExtendedHeader().getExtendedDataSize() != 0)
if (mCnmt.getContentMetaType() == nn::hac::cnmt::ContentMetaType::Patch && mCnmt.getPatchMetaExtendedHeader().getExtendedDataSize() != 0)
{
// this is stubbed as the raw output is for development purposes
//fmt::print(" PatchMetaExtendedData:\n");
//tc::cli::FormatUtil::formatBytesAsHxdHexString(mCnmt.getPatchMetaExtendedData().data(), mCnmt.getPatchMetaExtendedData().size());
}
else if (mCnmt.getContentMetaType() == pie::hac::cnmt::ContentMetaType_Delta && mCnmt.getDeltaMetaExtendedHeader().getExtendedDataSize() != 0)
else if (mCnmt.getContentMetaType() == nn::hac::cnmt::ContentMetaType::Delta && mCnmt.getDeltaMetaExtendedHeader().getExtendedDataSize() != 0)
{
// this is stubbed as the raw output is for development purposes
//fmt::print(" DeltaMetaExtendedData:\n");
//tc::cli::FormatUtil::formatBytesAsHxdHexString(mCnmt.getDeltaMetaExtendedData().data(), mCnmt.getDeltaMetaExtendedData().size());
}
else if (mCnmt.getContentMetaType() == pie::hac::cnmt::ContentMetaType_SystemUpdate && mCnmt.getSystemUpdateMetaExtendedHeader().getExtendedDataSize() != 0)
else if (mCnmt.getContentMetaType() == nn::hac::cnmt::ContentMetaType::SystemUpdate && mCnmt.getSystemUpdateMetaExtendedHeader().getExtendedDataSize() != 0)
{
fmt::print(" SystemUpdateMetaExtendedData:\n");
fmt::print(" FormatVersion: {:d}\n", mCnmt.getSystemUpdateMetaExtendedData().getFormatVersion());
@ -180,12 +180,12 @@ void nstool::CnmtProcess::displayCnmt()
fmt::print(" Digest: {:s}\n", tc::cli::FormatUtil::formatBytesAsString(mCnmt.getDigest().data(), mCnmt.getDigest().size(), false, ""));
}
void nstool::CnmtProcess::displayContentMetaInfo(const pie::hac::ContentMetaInfo& content_meta_info, const std::string& prefix)
void nstool::CnmtProcess::displayContentMetaInfo(const nn::hac::ContentMetaInfo& content_meta_info, const std::string& prefix)
{
const pie::hac::sContentMetaInfo* content_meta_info_raw = (const pie::hac::sContentMetaInfo*)content_meta_info.getBytes().data();
const nn::hac::sContentMetaInfo* content_meta_info_raw = (const nn::hac::sContentMetaInfo*)content_meta_info.getBytes().data();
fmt::print("{:s}Id: 0x{:016x}\n", prefix, content_meta_info.getTitleId());
fmt::print("{:s}Version: {:s} (v{:d})\n", prefix, pie::hac::ContentMetaUtil::getVersionAsString(content_meta_info.getTitleVersion()), content_meta_info.getTitleVersion());
fmt::print("{:s}Type: {:s} ({:d})\n", prefix, pie::hac::ContentMetaUtil::getContentMetaTypeAsString(content_meta_info.getContentMetaType()), (uint32_t)content_meta_info.getContentMetaType());
fmt::print("{:s}Version: {:s} (v{:d})\n", prefix, nn::hac::ContentMetaUtil::getVersionAsString(content_meta_info.getTitleVersion()), content_meta_info.getTitleVersion());
fmt::print("{:s}Type: {:s} ({:d})\n", prefix, nn::hac::ContentMetaUtil::getContentMetaTypeAsString(content_meta_info.getContentMetaType()), (uint32_t)content_meta_info.getContentMetaType());
fmt::print("{:s}Attributes: 0x{:x}", prefix, *((byte_t*)&content_meta_info_raw->attributes) );
if (content_meta_info.getAttribute().size())
{
@ -193,7 +193,7 @@ void nstool::CnmtProcess::displayContentMetaInfo(const pie::hac::ContentMetaInfo
for (auto itr = content_meta_info.getAttribute().begin(); itr != content_meta_info.getAttribute().end(); itr++)
{
attribute_list.push_back(pie::hac::ContentMetaUtil::getContentMetaAttributeFlagAsString(pie::hac::cnmt::ContentMetaAttributeFlag(*itr)));
attribute_list.push_back(nn::hac::ContentMetaUtil::getContentMetaAttributeFlagAsString(nn::hac::cnmt::ContentMetaAttributeFlag(*itr)));
}
fmt::print(" [");
@ -210,11 +210,11 @@ void nstool::CnmtProcess::displayContentMetaInfo(const pie::hac::ContentMetaInfo
fmt::print("\n");
}
void nstool::CnmtProcess::displayContentMetaInfoList(const std::vector<pie::hac::ContentMetaInfo>& content_meta_info_list, const std::string& prefix)
void nstool::CnmtProcess::displayContentMetaInfoList(const std::vector<nn::hac::ContentMetaInfo>& content_meta_info_list, const std::string& prefix)
{
for (size_t i = 0; i < content_meta_info_list.size(); i++)
{
const pie::hac::ContentMetaInfo& info = mCnmt.getContentMetaInfo()[i];
const nn::hac::ContentMetaInfo& info = mCnmt.getContentMetaInfo()[i];
fmt::print("{:s}{:d}\n", i);
displayContentMetaInfo(info, prefix + " ");
}

View file

@ -1,7 +1,7 @@
#pragma once
#include "types.h"
#include <pietendo/hac/ContentMeta.h>
#include <nn/hac/ContentMeta.h>
namespace nstool {
@ -16,7 +16,7 @@ public:
void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify);
const pie::hac::ContentMeta& getContentMeta() const;
const nn::hac::ContentMeta& getContentMeta() const;
private:
std::string mModuleName;
@ -24,13 +24,13 @@ private:
CliOutputMode mCliOutputMode;
bool mVerify;
pie::hac::ContentMeta mCnmt;
nn::hac::ContentMeta mCnmt;
void importCnmt();
void displayCnmt();
void displayContentMetaInfo(const pie::hac::ContentMetaInfo& content_meta_info, const std::string& prefix);
void displayContentMetaInfoList(const std::vector<pie::hac::ContentMetaInfo>& content_meta_info_list, const std::string& prefix);
void displayContentMetaInfo(const nn::hac::ContentMetaInfo& content_meta_info, const std::string& prefix);
void displayContentMetaInfoList(const std::vector<nn::hac::ContentMetaInfo>& content_meta_info_list, const std::string& prefix);
};
}

View file

@ -2,7 +2,7 @@
#include "PkiValidator.h"
#include "util.h"
#include <pietendo/hac/es/SignUtils.h>
#include <nn/pki/SignUtils.h>
nstool::EsCertProcess::EsCertProcess() :
mModuleName("nstool::EsCertProcess"),
@ -66,7 +66,7 @@ void nstool::EsCertProcess::importCerts()
mFile->seek(0, tc::io::SeekOrigin::Begin);
mFile->read(scratch.data(), scratch.size());
pie::hac::es::SignedData<pie::hac::es::CertificateBody> cert;
nn::pki::SignedData<nn::pki::CertificateBody> cert;
for (size_t f_pos = 0; f_pos < scratch.size(); f_pos += cert.getBytes().size())
{
cert.fromBytes(scratch.data() + f_pos, scratch.size() - f_pos);
@ -98,24 +98,24 @@ void nstool::EsCertProcess::displayCerts()
}
}
void nstool::EsCertProcess::displayCert(const pie::hac::es::SignedData<pie::hac::es::CertificateBody>& cert)
void nstool::EsCertProcess::displayCert(const nn::pki::SignedData<nn::pki::CertificateBody>& cert)
{
fmt::print("[ES Certificate]\n");
fmt::print(" SignType {:s}", getSignTypeStr(cert.getSignature().getSignType()));
if (mCliOutputMode.show_extended_info)
fmt::print(" (0x{:x}) ({:s})", (uint32_t)cert.getSignature().getSignType(), getEndiannessStr(cert.getSignature().isLittleEndian()));
fmt::print(" (0x{:x}) ({:s})", cert.getSignature().getSignType(), getEndiannessStr(cert.getSignature().isLittleEndian()));
fmt::print("\n");
fmt::print(" Issuer: {:s}\n", cert.getBody().getIssuer());
fmt::print(" Subject: {:s}\n", cert.getBody().getSubject());
fmt::print(" PublicKeyType: {:s}", getPublicKeyTypeStr(cert.getBody().getPublicKeyType()));
if (mCliOutputMode.show_extended_info)
fmt::print(" ({:d})", (uint32_t)cert.getBody().getPublicKeyType());
fmt::print(" ({:d})", cert.getBody().getPublicKeyType());
fmt::print("\n");
fmt::print(" CertID: 0x{:x}\n", cert.getBody().getCertId());
if (cert.getBody().getPublicKeyType() == pie::hac::es::cert::RSA4096)
if (cert.getBody().getPublicKeyType() == nn::pki::cert::RSA4096)
{
fmt::print(" PublicKey:\n");
if (mCliOutputMode.show_extended_info)
@ -133,7 +133,7 @@ void nstool::EsCertProcess::displayCert(const pie::hac::es::SignedData<pie::hac:
fmt::print(" {:s}\n", getTruncatedBytesString(cert.getBody().getRsa4096PublicKey().e.data(), cert.getBody().getRsa4096PublicKey().e.size()));
}
}
else if (cert.getBody().getPublicKeyType() == pie::hac::es::cert::RSA2048)
else if (cert.getBody().getPublicKeyType() == nn::pki::cert::RSA2048)
{
fmt::print(" PublicKey:\n");
if (mCliOutputMode.show_extended_info)
@ -151,7 +151,7 @@ void nstool::EsCertProcess::displayCert(const pie::hac::es::SignedData<pie::hac:
fmt::print(" {:s}\n", getTruncatedBytesString(cert.getBody().getRsa2048PublicKey().e.data(), cert.getBody().getRsa2048PublicKey().e.size()));
}
}
else if (cert.getBody().getPublicKeyType() == pie::hac::es::cert::ECDSA240)
else if (cert.getBody().getPublicKeyType() == nn::pki::cert::ECDSA240)
{
fmt::print(" PublicKey:\n");
if (mCliOutputMode.show_extended_info)
@ -171,27 +171,27 @@ void nstool::EsCertProcess::displayCert(const pie::hac::es::SignedData<pie::hac:
}
}
std::string nstool::EsCertProcess::getSignTypeStr(pie::hac::es::sign::SignatureId type) const
std::string nstool::EsCertProcess::getSignTypeStr(nn::pki::sign::SignatureId type) const
{
std::string str;
switch (type)
{
case (pie::hac::es::sign::SIGN_ID_RSA4096_SHA1):
case (nn::pki::sign::SIGN_ID_RSA4096_SHA1):
str = "RSA4096-SHA1";
break;
case (pie::hac::es::sign::SIGN_ID_RSA2048_SHA1):
case (nn::pki::sign::SIGN_ID_RSA2048_SHA1):
str = "RSA2048-SHA1";
break;
case (pie::hac::es::sign::SIGN_ID_ECDSA240_SHA1):
case (nn::pki::sign::SIGN_ID_ECDSA240_SHA1):
str = "ECDSA240-SHA1";
break;
case (pie::hac::es::sign::SIGN_ID_RSA4096_SHA256):
case (nn::pki::sign::SIGN_ID_RSA4096_SHA256):
str = "RSA4096-SHA256";
break;
case (pie::hac::es::sign::SIGN_ID_RSA2048_SHA256):
case (nn::pki::sign::SIGN_ID_RSA2048_SHA256):
str = "RSA2048-SHA256";
break;
case (pie::hac::es::sign::SIGN_ID_ECDSA240_SHA256):
case (nn::pki::sign::SIGN_ID_ECDSA240_SHA256):
str = "ECDSA240-SHA256";
break;
default:
@ -206,18 +206,18 @@ std::string nstool::EsCertProcess::getEndiannessStr(bool isLittleEndian) const
return isLittleEndian ? "LittleEndian" : "BigEndian";
}
std::string nstool::EsCertProcess::getPublicKeyTypeStr(pie::hac::es::cert::PublicKeyType type) const
std::string nstool::EsCertProcess::getPublicKeyTypeStr(nn::pki::cert::PublicKeyType type) const
{
std::string str;
switch (type)
{
case (pie::hac::es::cert::RSA4096):
case (nn::pki::cert::RSA4096):
str = "RSA4096";
break;
case (pie::hac::es::cert::RSA2048):
case (nn::pki::cert::RSA2048):
str = "RSA2048";
break;
case (pie::hac::es::cert::ECDSA240):
case (nn::pki::cert::ECDSA240):
str = "ECDSA240";
break;
default:

View file

@ -2,8 +2,8 @@
#include "types.h"
#include "KeyBag.h"
#include <pietendo/hac/es/SignedData.h>
#include <pietendo/hac/es/CertificateBody.h>
#include <nn/pki/SignedData.h>
#include <nn/pki/CertificateBody.h>
namespace nstool {
@ -27,16 +27,16 @@ private:
CliOutputMode mCliOutputMode;
bool mVerify;
std::vector<pie::hac::es::SignedData<pie::hac::es::CertificateBody>> mCert;
std::vector<nn::pki::SignedData<nn::pki::CertificateBody>> mCert;
void importCerts();
void validateCerts();
void displayCerts();
void displayCert(const pie::hac::es::SignedData<pie::hac::es::CertificateBody>& cert);
void displayCert(const nn::pki::SignedData<nn::pki::CertificateBody>& cert);
std::string getSignTypeStr(pie::hac::es::sign::SignatureId type) const;
std::string getSignTypeStr(nn::pki::sign::SignatureId type) const;
std::string getEndiannessStr(bool isLittleEndian) const;
std::string getPublicKeyTypeStr(pie::hac::es::cert::PublicKeyType type) const;
std::string getPublicKeyTypeStr(nn::pki::cert::PublicKeyType type) const;
};
}

View file

@ -1,7 +1,7 @@
#include "EsTikProcess.h"
#include "PkiValidator.h"
#include <pietendo/hac/es/SignUtils.h>
#include <nn/pki/SignUtils.h>
nstool::EsTikProcess::EsTikProcess() :
mModuleName("nstool::EsTikProcess"),
@ -32,7 +32,7 @@ void nstool::EsTikProcess::setKeyCfg(const KeyBag& keycfg)
mKeyCfg = keycfg;
}
void nstool::EsTikProcess::setCertificateChain(const std::vector<pie::hac::es::SignedData<pie::hac::es::CertificateBody>>& certs)
void nstool::EsTikProcess::setCertificateChain(const std::vector<nn::pki::SignedData<nn::pki::CertificateBody>>& certs)
{
mCerts = certs;
}
@ -78,15 +78,15 @@ void nstool::EsTikProcess::verifyTicket()
PkiValidator pki_validator;
tc::ByteData tik_hash;
switch (pie::hac::es::sign::getHashAlgo(mTik.getSignature().getSignType()))
switch (nn::pki::sign::getHashAlgo(mTik.getSignature().getSignType()))
{
case (pie::hac::es::sign::HASH_ALGO_SHA1):
case (nn::pki::sign::HASH_ALGO_SHA1):
tik_hash = tc::ByteData(tc::crypto::Sha1Generator::kHashSize);
tc::crypto::GenerateSha1Hash(tik_hash.data(), mTik.getBody().getBytes().data(), mTik.getBody().getBytes().size());
break;
case (pie::hac::es::sign::HASH_ALGO_SHA256):
tik_hash = tc::ByteData(tc::crypto::Sha2256Generator::kHashSize);
tc::crypto::GenerateSha2256Hash(tik_hash.data(), mTik.getBody().getBytes().data(), mTik.getBody().getBytes().size());
case (nn::pki::sign::HASH_ALGO_SHA256):
tik_hash = tc::ByteData(tc::crypto::Sha256Generator::kHashSize);
tc::crypto::GenerateSha256Hash(tik_hash.data(), mTik.getBody().getBytes().data(), mTik.getBody().getBytes().size());
break;
}
@ -104,24 +104,24 @@ void nstool::EsTikProcess::verifyTicket()
void nstool::EsTikProcess::displayTicket()
{
const pie::hac::es::TicketBody_V2& body = mTik.getBody();
const nn::es::TicketBody_V2& body = mTik.getBody();
fmt::print("[ES Ticket]\n");
fmt::print(" SignType: {:s}", getSignTypeStr(mTik.getSignature().getSignType()));
if (mCliOutputMode.show_extended_info)
fmt::print(" (0x{:x})", (uint32_t)mTik.getSignature().getSignType());
fmt::print(" (0x{:x})", mTik.getSignature().getSignType());
fmt::print("\n");
fmt::print(" Issuer: {:s}\n", body.getIssuer());
fmt::print(" Title Key:\n");
fmt::print(" EncMode: {:s}\n", getTitleKeyPersonalisationStr(body.getTitleKeyEncType()));
fmt::print(" KeyGeneration: {:d}\n", (uint32_t)body.getCommonKeyId());
if (body.getTitleKeyEncType() == pie::hac::es::ticket::RSA2048)
if (body.getTitleKeyEncType() == nn::es::ticket::RSA2048)
{
fmt::print(" Data:\n");
fmt::print(" {:s}", tc::cli::FormatUtil::formatBytesAsStringWithLineLimit(body.getEncTitleKey(), 0x100, true, "", 0x10, 6, false));
}
else if (body.getTitleKeyEncType() == pie::hac::es::ticket::AES128_CBC)
else if (body.getTitleKeyEncType() == nn::es::ticket::AES128_CBC)
{
fmt::print(" Data:\n");
fmt::print(" {:s}\n", tc::cli::FormatUtil::formatBytesAsString(body.getEncTitleKey(), 0x10, true, ""));
@ -134,7 +134,7 @@ void nstool::EsTikProcess::displayTicket()
fmt::print(" License Type: {:s}\n", getLicenseTypeStr(body.getLicenseType()));
if (body.getPropertyFlags().size() > 0 || mCliOutputMode.show_extended_info)
{
pie::hac::es::sTicketBody_v2* raw_body = (pie::hac::es::sTicketBody_v2*)body.getBytes().data();
nn::es::sTicketBody_v2* raw_body = (nn::es::sTicketBody_v2*)body.getBytes().data();
fmt::print(" PropertyMask: 0x{:04x}\n", ((tc::bn::le16<uint16_t>*)&raw_body->property_mask)->unwrap());
for (size_t i = 0; i < body.getPropertyFlags().size(); i++)
{
@ -167,22 +167,22 @@ std::string nstool::EsTikProcess::getSignTypeStr(uint32_t type) const
std::string str;
switch(type)
{
case (pie::hac::es::sign::SIGN_ID_RSA4096_SHA1):
case (nn::pki::sign::SIGN_ID_RSA4096_SHA1):
str = "RSA4096-SHA1";
break;
case (pie::hac::es::sign::SIGN_ID_RSA2048_SHA1):
case (nn::pki::sign::SIGN_ID_RSA2048_SHA1):
str = "RSA2048-SHA1";
break;
case (pie::hac::es::sign::SIGN_ID_ECDSA240_SHA1):
case (nn::pki::sign::SIGN_ID_ECDSA240_SHA1):
str = "ECDSA240-SHA1";
break;
case (pie::hac::es::sign::SIGN_ID_RSA4096_SHA256):
case (nn::pki::sign::SIGN_ID_RSA4096_SHA256):
str = "RSA4096-SHA256";
break;
case (pie::hac::es::sign::SIGN_ID_RSA2048_SHA256):
case (nn::pki::sign::SIGN_ID_RSA2048_SHA256):
str = "RSA2048-SHA256";
break;
case (pie::hac::es::sign::SIGN_ID_ECDSA240_SHA256):
case (nn::pki::sign::SIGN_ID_ECDSA240_SHA256):
str = "ECDSA240-SHA256";
break;
default:
@ -197,10 +197,10 @@ std::string nstool::EsTikProcess::getTitleKeyPersonalisationStr(byte_t flag) con
std::string str;
switch(flag)
{
case (pie::hac::es::ticket::AES128_CBC):
case (nn::es::ticket::AES128_CBC):
str = "Generic (AESCBC)";
break;
case (pie::hac::es::ticket::RSA2048):
case (nn::es::ticket::RSA2048):
str = "Personalised (RSA2048)";
break;
default:
@ -215,22 +215,22 @@ std::string nstool::EsTikProcess::getLicenseTypeStr(byte_t flag) const
std::string str;
switch(flag)
{
case (pie::hac::es::ticket::LICENSE_PERMANENT):
case (nn::es::ticket::LICENSE_PERMANENT):
str = "Permanent";
break;
case (pie::hac::es::ticket::LICENSE_DEMO):
case (nn::es::ticket::LICENSE_DEMO):
str = "Demo";
break;
case (pie::hac::es::ticket::LICENSE_TRIAL):
case (nn::es::ticket::LICENSE_TRIAL):
str = "Trial";
break;
case (pie::hac::es::ticket::LICENSE_RENTAL):
case (nn::es::ticket::LICENSE_RENTAL):
str = "Rental";
break;
case (pie::hac::es::ticket::LICENSE_SUBSCRIPTION):
case (nn::es::ticket::LICENSE_SUBSCRIPTION):
str = "Subscription";
break;
case (pie::hac::es::ticket::LICENSE_SERVICE):
case (nn::es::ticket::LICENSE_SERVICE):
str = "Service";
break;
default:
@ -245,22 +245,22 @@ std::string nstool::EsTikProcess::getPropertyFlagStr(byte_t flag) const
std::string str;
switch(flag)
{
case (pie::hac::es::ticket::FLAG_PRE_INSTALL):
case (nn::es::ticket::FLAG_PRE_INSTALL):
str = "PreInstall";
break;
case (pie::hac::es::ticket::FLAG_SHARED_TITLE):
case (nn::es::ticket::FLAG_SHARED_TITLE):
str = "SharedTitle";
break;
case (pie::hac::es::ticket::FLAG_ALLOW_ALL_CONTENT):
case (nn::es::ticket::FLAG_ALLOW_ALL_CONTENT):
str = "AllContent";
break;
case (pie::hac::es::ticket::FLAG_DEVICE_LINK_INDEPENDENT):
case (nn::es::ticket::FLAG_DEVICE_LINK_INDEPENDENT):
str = "DeviceLinkIndependent";
break;
case (pie::hac::es::ticket::FLAG_VOLATILE):
case (nn::es::ticket::FLAG_VOLATILE):
str = "Volatile";
break;
case (pie::hac::es::ticket::FLAG_ELICENSE_REQUIRED):
case (nn::es::ticket::FLAG_ELICENSE_REQUIRED):
str = "ELicenseRequired";
break;
default:

View file

@ -2,9 +2,9 @@
#include "types.h"
#include "KeyBag.h"
#include <pietendo/hac/es/SignedData.h>
#include <pietendo/hac/es/CertificateBody.h>
#include <pietendo/hac/es/TicketBody_V2.h>
#include <nn/pki/SignedData.h>
#include <nn/pki/CertificateBody.h>
#include <nn/es/TicketBody_V2.h>
namespace nstool {
@ -17,7 +17,7 @@ public:
void setInputFile(const std::shared_ptr<tc::io::IStream>& file);
void setKeyCfg(const KeyBag& keycfg);
void setCertificateChain(const std::vector<pie::hac::es::SignedData<pie::hac::es::CertificateBody>>& certs);
void setCertificateChain(const std::vector<nn::pki::SignedData<nn::pki::CertificateBody>>& certs);
void setCliOutputMode(CliOutputMode mode);
void setVerifyMode(bool verify);
private:
@ -28,9 +28,9 @@ private:
CliOutputMode mCliOutputMode;
bool mVerify;
std::vector<pie::hac::es::SignedData<pie::hac::es::CertificateBody>> mCerts;
std::vector<nn::pki::SignedData<nn::pki::CertificateBody>> mCerts;
pie::hac::es::SignedData<pie::hac::es::TicketBody_V2> mTik;
nn::pki::SignedData<nn::es::TicketBody_V2> mTik;
void importTicket();
void verifyTicket();

View file

@ -46,7 +46,7 @@ void nstool::FsProcess::process()
}
}
void nstool::FsProcess::setInputFileSystem(const std::shared_ptr<tc::io::IFileSystem>& input_fs)
void nstool::FsProcess::setInputFileSystem(const std::shared_ptr<tc::io::IStorage>& input_fs)
{
mInputFs = input_fs;
}
@ -93,12 +93,15 @@ void nstool::FsProcess::extractFs()
for (auto itr = mExtractJobs.begin(); itr != mExtractJobs.end(); itr++)
{
std::string path_str;
tc::io::PathUtil::pathToUnixUTF8(itr->virtual_path, path_str);
// check if root path (legacy case)
if (itr->virtual_path == tc::io::Path("/"))
{
visitDir(tc::io::Path("/"), itr->extract_path, true, false);
//fmt::print("Root Dir Virtual Path: \"{:s}\"\n", itr->virtual_path.to_string());
//fmt::print("Root Dir Virtual Path: \"{:s}\"\n", path_str);
// root directory extract successful, continue to next job
continue;
@ -109,10 +112,10 @@ void nstool::FsProcess::extractFs()
std::shared_ptr<tc::io::IStream> file_stream;
mInputFs->openFile(itr->virtual_path, tc::io::FileMode::Open, tc::io::FileAccess::Read, file_stream);
//fmt::print("Valid File Path: \"{:s}\"\n", itr->virtual_path.to_string());
//fmt::print("Valid File Path: \"{:s}\"\n", path_str);
// the output path for this file will depend on the user specified extract path
std::shared_ptr<tc::io::IFileSystem> local_fs = std::make_shared<tc::io::LocalFileSystem>(tc::io::LocalFileSystem());
std::shared_ptr<tc::io::IStorage> local_fs = std::make_shared<tc::io::LocalStorage>(tc::io::LocalStorage());
// case: the extract_path is a valid path to an existing directory
// behaviour: extract the file, preserving the original filename, to the specified directory
@ -124,7 +127,10 @@ void nstool::FsProcess::extractFs()
tc::io::Path file_extract_path = itr->extract_path + itr->virtual_path.back();
fmt::print("Saving {:s}...\n", file_extract_path.to_string());
std::string file_extract_path_str;
tc::io::PathUtil::pathToUnixUTF8(file_extract_path, file_extract_path_str);
fmt::print("Saving {:s}...\n", file_extract_path_str);
writeStreamToFile(file_stream, itr->extract_path + itr->virtual_path.back(), mDataCache);
@ -139,18 +145,24 @@ void nstool::FsProcess::extractFs()
// method: since this checks n-1 elements, it implies a path with more than one element, so that must be accounted for, as relative paths are valid and single element paths aren't always root
try {
std::string test_path_str;
// get path to parent directory
tc::io::Path parent_dir_path = itr->extract_path;
// replace final path element with the current directory alias
parent_dir_path.pop_back(); // remove filename
parent_dir_path.push_back("."); // replace with the current dir name alias
tc::io::PathUtil::pathToUnixUTF8(parent_dir_path, test_path_str);
// test parent directory exists
tc::io::sDirectoryListing dir_listing;
local_fs->getDirectoryListing(parent_dir_path, dir_listing);
fmt::print("Saving {:s} as {:s}...\n", itr->virtual_path.to_string(), itr->extract_path.to_string());
std::string file_extract_path_str;
tc::io::PathUtil::pathToUnixUTF8(itr->extract_path, file_extract_path_str);
fmt::print("Saving {:s} as {:s}...\n", path_str, file_extract_path_str);
writeStreamToFile(file_stream, itr->extract_path, mDataCache);
@ -161,7 +173,9 @@ void nstool::FsProcess::extractFs()
// extract path could not be determined, inform the user and skip this job
fmt::print("[WARNING] Extract path was invalid, and was skipped: {:s}\n", itr->extract_path.to_string());
std::string literal_extract_path_str;
tc::io::PathUtil::pathToUnixUTF8(itr->extract_path, literal_extract_path_str);
fmt::print("[WARNING] Extract path was invalid, and was skipped: {:s}\n", literal_extract_path_str);
continue;
} catch (tc::io::FileNotFoundException&) {
// acceptable exception, just means file didn't exist
@ -172,9 +186,10 @@ void nstool::FsProcess::extractFs()
tc::io::sDirectoryListing dir_listing;
mInputFs->getDirectoryListing(itr->virtual_path, dir_listing);
visitDir(itr->virtual_path, itr->extract_path, true, false);
//fmt::print("Valid Directory Path: \"{:s}\"\n", itr->virtual_path.to_string());
//fmt::print("Valid Directory Path: \"{:s}\"\n", path_str);
// directory extract successful, continue to next job
continue;
@ -183,14 +198,14 @@ void nstool::FsProcess::extractFs()
// acceptable exception, just means directory didn't exist
}
fmt::print("[WARNING] Failed to extract virtual path: \"{:s}\"\n", itr->virtual_path.to_string());
fmt::print("[WARNING] Failed to extract virtual path: \"{:s}\"\n", path_str);
}
}
void nstool::FsProcess::visitDir(const tc::io::Path& v_path, const tc::io::Path& l_path, bool extract_fs, bool print_fs)
{
tc::io::LocalFileSystem local_fs;
tc::io::LocalStorage local_fs;
// get listing for directory
tc::io::sDirectoryListing info;
@ -212,6 +227,7 @@ void nstool::FsProcess::visitDir(const tc::io::Path& v_path, const tc::io::Path&
// iterate thru child files
size_t cache_read_len;
tc::io::Path out_path;
std::string out_path_str;
std::shared_ptr<tc::io::IStream> in_stream;
std::shared_ptr<tc::io::IStream> out_stream;
for (auto itr = info.file_list.begin(); itr != info.file_list.end(); itr++)
@ -226,8 +242,9 @@ void nstool::FsProcess::visitDir(const tc::io::Path& v_path, const tc::io::Path&
{
// build out path
out_path = l_path + *itr;
tc::io::PathUtil::pathToUnixUTF8(out_path, out_path_str);
fmt::print("Saving {:s}...\n", out_path.to_string());
fmt::print("Saving {:s}...\n", out_path_str);
// begin export
mInputFs->openFile(v_path + *itr, tc::io::FileMode::Open, tc::io::FileAccess::Read, in_stream);

View file

@ -14,7 +14,7 @@ public:
void process();
void setInputFileSystem(const std::shared_ptr<tc::io::IFileSystem>& input_fs);
void setInputFileSystem(const std::shared_ptr<tc::io::IStorage>& input_fs);
void setFsFormatName(const std::string& fs_format_name);
void setFsProperties(const std::vector<std::string>& properties);
void setShowFsInfo(bool show_fs_info);
@ -24,7 +24,7 @@ public:
private:
std::string mModuleLabel;
std::shared_ptr<tc::io::IFileSystem> mInputFs;
std::shared_ptr<tc::io::IStorage> mInputFs;
// fs info
tc::Optional<std::string> mFsFormatName;

View file

@ -3,11 +3,11 @@
#include <tc/crypto.h>
#include <tc/io/IOUtil.h>
#include <pietendo/hac/GameCardUtil.h>
#include <pietendo/hac/ContentMetaUtil.h>
#include <pietendo/hac/ContentArchiveUtil.h>
#include <nn/hac/GameCardUtil.h>
#include <nn/hac/ContentMetaUtil.h>
#include <nn/hac/ContentArchiveUtil.h>
#include <pietendo/hac/GameCardFsSnapshotGenerator.h>
#include <nn/hac/GameCardFsMetaGenerator.h>
#include "FsProcess.h"
@ -16,12 +16,10 @@ nstool::GameCardProcess::GameCardProcess() :
mFile(),
mCliOutputMode(true, false, false, false),
mVerify(false),
mIsTrueSdkXci(false),
mIsSdkXciEncrypted(false),
mGcHeaderOffset(0),
mListFs(false),
mProccessExtendedHeader(false),
mFileSystem(),
mFsProcess()
mRootPfs(),
mExtractJobs()
{
}
@ -61,14 +59,14 @@ void nstool::GameCardProcess::setVerifyMode(bool verify)
mVerify = verify;
}
void nstool::GameCardProcess::setShowFsTree(bool show_fs_tree)
{
mFsProcess.setShowFsTree(show_fs_tree);
}
void nstool::GameCardProcess::setExtractJobs(const std::vector<nstool::ExtractJob> extract_jobs)
{
mFsProcess.setExtractJobs(extract_jobs);
mExtractJobs = extract_jobs;
}
void nstool::GameCardProcess::setShowFsTree(bool show_fs_tree)
{
mListFs = show_fs_tree;
}
void nstool::GameCardProcess::importHeader()
@ -83,25 +81,25 @@ void nstool::GameCardProcess::importHeader()
}
// check stream is large enough for header
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(sizeof(pie::hac::sSdkGcHeader)))
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(sizeof(nn::hac::sSdkGcHeader)))
{
throw tc::Exception(mModuleName, "Corrupt GameCard Image: File too small.");
}
// allocate memory for header
tc::ByteData scratch = tc::ByteData(sizeof(pie::hac::sSdkGcHeader));
tc::ByteData scratch = tc::ByteData(sizeof(nn::hac::sSdkGcHeader));
// read header region
mFile->seek(0, tc::io::SeekOrigin::Begin);
mFile->read(scratch.data(), scratch.size());
// determine if this is a SDK XCI or a "Community" XCI
if (((pie::hac::sSdkGcHeader*)scratch.data())->signed_header.header.st_magic.unwrap() == pie::hac::gc::kGcHeaderStructMagic)
if (((nn::hac::sSdkGcHeader*)scratch.data())->signed_header.header.st_magic.unwrap() == nn::hac::gc::kGcHeaderStructMagic)
{
mIsTrueSdkXci = true;
mGcHeaderOffset = sizeof(pie::hac::sGcKeyDataRegion);
mGcHeaderOffset = sizeof(nn::hac::sGcKeyDataRegion);
}
else if (((pie::hac::sGcHeader_Rsa2048Signed*)scratch.data())->header.st_magic.unwrap() == pie::hac::gc::kGcHeaderStructMagic)
else if (((nn::hac::sGcHeader_Rsa2048Signed*)scratch.data())->header.st_magic.unwrap() == nn::hac::gc::kGcHeaderStructMagic)
{
mIsTrueSdkXci = false;
mGcHeaderOffset = 0;
@ -111,33 +109,33 @@ void nstool::GameCardProcess::importHeader()
throw tc::Exception(mModuleName, "Corrupt GameCard Image: Unexpected magic bytes.");
}
pie::hac::sGcHeader_Rsa2048Signed* hdr_ptr = (pie::hac::sGcHeader_Rsa2048Signed*)(scratch.data() + mGcHeaderOffset);
nn::hac::sGcHeader_Rsa2048Signed* hdr_ptr = (nn::hac::sGcHeader_Rsa2048Signed*)(scratch.data() + mGcHeaderOffset);
// generate hash of raw header
tc::crypto::GenerateSha2256Hash(mHdrHash.data(), (byte_t*)&hdr_ptr->header, sizeof(pie::hac::sGcHeader));
tc::crypto::GenerateSha256Hash(mHdrHash.data(), (byte_t*)&hdr_ptr->header, sizeof(nn::hac::sGcHeader));
// save the signature
memcpy(mHdrSignature.data(), hdr_ptr->signature.data(), mHdrSignature.size());
// decrypt extended header
byte_t xci_header_key_index = hdr_ptr->header.key_flag & 0xf;
byte_t xci_header_key_index = hdr_ptr->header.key_flag & 7;
if (mKeyCfg.xci_header_key.find(xci_header_key_index) != mKeyCfg.xci_header_key.end())
{
pie::hac::GameCardUtil::decryptXciHeader(&hdr_ptr->header, mKeyCfg.xci_header_key[xci_header_key_index].data());
nn::hac::GameCardUtil::decryptXciHeader(&hdr_ptr->header, mKeyCfg.xci_header_key[xci_header_key_index].data());
mProccessExtendedHeader = true;
}
// deserialise header
mHdr.fromBytes((byte_t*)&hdr_ptr->header, sizeof(pie::hac::sGcHeader));
mHdr.fromBytes((byte_t*)&hdr_ptr->header, sizeof(nn::hac::sGcHeader));
}
void nstool::GameCardProcess::displayHeader()
{
const pie::hac::sGcHeader* raw_hdr = (const pie::hac::sGcHeader*)mHdr.getBytes().data();
const nn::hac::sGcHeader* raw_hdr = (const nn::hac::sGcHeader*)mHdr.getBytes().data();
fmt::print("[GameCard/Header]\n");
fmt::print(" CardHeaderVersion: {:d}\n", mHdr.getCardHeaderVersion());
fmt::print(" RomSize: {:s}", pie::hac::GameCardUtil::getRomSizeAsString((pie::hac::gc::RomSize)mHdr.getRomSizeType()));
fmt::print(" RomSize: {:s}", nn::hac::GameCardUtil::getRomSizeAsString((nn::hac::gc::RomSize)mHdr.getRomSizeType()));
if (mCliOutputMode.show_extended_info)
fmt::print(" (0x{:x})", mHdr.getRomSizeType());
fmt::print("\n");
@ -145,13 +143,13 @@ void nstool::GameCardProcess::displayHeader()
fmt::print(" Flags: 0x{:02x}\n", *((byte_t*)&raw_hdr->flags));
for (auto itr = mHdr.getFlags().begin(); itr != mHdr.getFlags().end(); itr++)
{
fmt::print(" {:s}\n", pie::hac::GameCardUtil::getHeaderFlagsAsString((pie::hac::gc::HeaderFlags)*itr));
fmt::print(" {:s}\n", nn::hac::GameCardUtil::getHeaderFlagsAsString((nn::hac::gc::HeaderFlags)*itr));
}
if (mCliOutputMode.show_extended_info)
{
fmt::print(" KekIndex: {:s} ({:d})\n", pie::hac::GameCardUtil::getKekIndexAsString((pie::hac::gc::KekIndex)mHdr.getKekIndex()), mHdr.getKekIndex());
fmt::print(" KekIndex: {:s} ({:d})\n", nn::hac::GameCardUtil::getKekIndexAsString((nn::hac::gc::KekIndex)mHdr.getKekIndex()), mHdr.getKekIndex());
fmt::print(" TitleKeyDecIndex: {:d}\n", mHdr.getTitleKeyDecIndex());
fmt::print(" InitialData:\n");
fmt::print(" Hash:\n");
@ -169,22 +167,22 @@ void nstool::GameCardProcess::displayHeader()
{
fmt::print(" RomAreaStartPage: 0x{:x}", mHdr.getRomAreaStartPage());
if (mHdr.getRomAreaStartPage() != (uint32_t)(-1))
fmt::print(" (0x{:x})", pie::hac::GameCardUtil::blockToAddr(mHdr.getRomAreaStartPage()));
fmt::print(" (0x{:x})", nn::hac::GameCardUtil::blockToAddr(mHdr.getRomAreaStartPage()));
fmt::print("\n");
fmt::print(" BackupAreaStartPage: 0x{:x}", mHdr.getBackupAreaStartPage());
if (mHdr.getBackupAreaStartPage() != (uint32_t)(-1))
fmt::print(" (0x{:x})", pie::hac::GameCardUtil::blockToAddr(mHdr.getBackupAreaStartPage()));
fmt::print(" (0x{:x})", nn::hac::GameCardUtil::blockToAddr(mHdr.getBackupAreaStartPage()));
fmt::print("\n");
fmt::print(" ValidDataEndPage: 0x{:x}", mHdr.getValidDataEndPage());
if (mHdr.getValidDataEndPage() != (uint32_t)(-1))
fmt::print(" (0x{:x})", pie::hac::GameCardUtil::blockToAddr(mHdr.getValidDataEndPage()));
fmt::print(" (0x{:x})", nn::hac::GameCardUtil::blockToAddr(mHdr.getValidDataEndPage()));
fmt::print("\n");
fmt::print(" LimArea: 0x{:x}", mHdr.getLimAreaPage());
if (mHdr.getLimAreaPage() != (uint32_t)(-1))
fmt::print(" (0x{:x})", pie::hac::GameCardUtil::blockToAddr(mHdr.getLimAreaPage()));
fmt::print(" (0x{:x})", nn::hac::GameCardUtil::blockToAddr(mHdr.getLimAreaPage()));
fmt::print("\n");
fmt::print(" PartitionFs Header:\n");
@ -201,17 +199,17 @@ void nstool::GameCardProcess::displayHeader()
if (mProccessExtendedHeader)
{
fmt::print("[GameCard/ExtendedHeader]\n");
fmt::print(" FwVersion: v{:d} ({:s})\n", mHdr.getFwVersion(), pie::hac::GameCardUtil::getCardFwVersionDescriptionAsString((pie::hac::gc::FwVersion)mHdr.getFwVersion()));
fmt::print(" FwVersion: v{:d} ({:s})\n", mHdr.getFwVersion(), nn::hac::GameCardUtil::getCardFwVersionDescriptionAsString((nn::hac::gc::FwVersion)mHdr.getFwVersion()));
fmt::print(" AccCtrl1: 0x{:x}\n", mHdr.getAccCtrl1());
fmt::print(" CardClockRate: {:s}\n", pie::hac::GameCardUtil::getCardClockRateAsString((pie::hac::gc::CardClockRate)mHdr.getAccCtrl1()));
fmt::print(" CardClockRate: {:s}\n", nn::hac::GameCardUtil::getCardClockRateAsString((nn::hac::gc::CardClockRate)mHdr.getAccCtrl1()));
fmt::print(" Wait1TimeRead: 0x{:x}\n", mHdr.getWait1TimeRead());
fmt::print(" Wait2TimeRead: 0x{:x}\n", mHdr.getWait2TimeRead());
fmt::print(" Wait1TimeWrite: 0x{:x}\n", mHdr.getWait1TimeWrite());
fmt::print(" Wait2TimeWrite: 0x{:x}\n", mHdr.getWait2TimeWrite());
fmt::print(" SdkAddon Version: {:s} (v{:d})\n", pie::hac::ContentArchiveUtil::getSdkAddonVersionAsString(mHdr.getFwMode()), mHdr.getFwMode());
fmt::print(" CompatibilityType: {:s} ({:d})\n", pie::hac::GameCardUtil::getCompatibilityTypeAsString((pie::hac::gc::CompatibilityType)mHdr.getCompatibilityType()), mHdr.getCompatibilityType());
fmt::print(" SdkAddon Version: {:s} (v{:d})\n", nn::hac::ContentArchiveUtil::getSdkAddonVersionAsString(mHdr.getFwMode()), mHdr.getFwMode());
fmt::print(" CompatibilityType: {:s} ({:d})\n", nn::hac::GameCardUtil::getCompatibilityTypeAsString((nn::hac::gc::CompatibilityType)mHdr.getCompatibilityType()), mHdr.getCompatibilityType());
fmt::print(" Update Partition Info:\n");
fmt::print(" CUP Version: {:s} (v{:d})\n", pie::hac::ContentMetaUtil::getVersionAsString(mHdr.getUppVersion()), mHdr.getUppVersion());
fmt::print(" CUP Version: {:s} (v{:d})\n", nn::hac::ContentMetaUtil::getVersionAsString(mHdr.getUppVersion()), mHdr.getUppVersion());
fmt::print(" CUP TitleId: 0x{:016x}\n", mHdr.getUppId());
fmt::print(" CUP Digest: {:s}\n", tc::cli::FormatUtil::formatBytesAsString(mHdr.getUppHash().data(), mHdr.getUppHash().size(), true, ""));
}
@ -225,14 +223,14 @@ bool nstool::GameCardProcess::validateRegionOfFile(int64_t offset, int64_t len,
mFile->read(scratch.data(), scratch.size());
// update hash
tc::crypto::Sha2256Generator sha256_gen;
tc::crypto::Sha256Generator sha256_gen;
sha256_gen.initialize();
sha256_gen.update(scratch.data(), scratch.size());
if (use_salt)
sha256_gen.update(&salt, sizeof(salt));
// calculate hash
pie::hac::detail::sha256_hash_t calc_hash;
nn::hac::detail::sha256_hash_t calc_hash;
sha256_gen.getHash(calc_hash.data());
return memcmp(calc_hash.data(), test_hash, calc_hash.size()) == 0;
@ -247,7 +245,7 @@ void nstool::GameCardProcess::validateXciSignature()
{
if (mKeyCfg.xci_header_sign_key.isSet())
{
if (tc::crypto::VerifyRsa2048Pkcs1Sha2256(mHdrSignature.data(), mHdrHash.data(), mKeyCfg.xci_header_sign_key.get()) == false)
if (tc::crypto::VerifyRsa2048Pkcs1Sha256(mHdrSignature.data(), mHdrHash.data(), mKeyCfg.xci_header_sign_key.get()) == false)
{
fmt::print("[WARNING] GameCard Header Signature: FAIL\n");
}
@ -260,24 +258,29 @@ void nstool::GameCardProcess::validateXciSignature()
void nstool::GameCardProcess::processRootPfs()
{
if (mVerify && validateRegionOfFile(mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize(), mHdr.getPartitionFsHash().data(), mHdr.getCompatibilityType() != pie::hac::gc::CompatibilityType_Global, mHdr.getCompatibilityType()) == false)
if (mVerify && validateRegionOfFile(mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize(), mHdr.getPartitionFsHash().data(), mHdr.getCompatibilityType() != nn::hac::gc::COMPAT_GLOBAL, mHdr.getCompatibilityType()) == false)
{
fmt::print("[WARNING] GameCard Root HFS0: FAIL (bad hash)\n");
}
std::shared_ptr<tc::io::IStream> gc_fs_raw = std::make_shared<tc::io::SubStream>(tc::io::SubStream(mFile, mHdr.getPartitionFsAddress(), pie::hac::GameCardUtil::blockToAddr(mHdr.getValidDataEndPage()+1) - mHdr.getPartitionFsAddress()));
std::shared_ptr<tc::io::IStream> gc_fs_raw = std::make_shared<tc::io::SubStream>(tc::io::SubStream(mFile, mHdr.getPartitionFsAddress(), nn::hac::GameCardUtil::blockToAddr(mHdr.getValidDataEndPage()+1) - mHdr.getPartitionFsAddress()));
auto gc_vfs_snapshot = pie::hac::GameCardFsSnapshotGenerator(gc_fs_raw, mHdr.getPartitionFsSize(), mVerify ? pie::hac::GameCardFsSnapshotGenerator::ValidationMode_Warn : pie::hac::GameCardFsSnapshotGenerator::ValidationMode_None);
mFileSystem = std::make_shared<tc::io::VirtualFileSystem>(tc::io::VirtualFileSystem(gc_vfs_snapshot) );
auto gc_vfs_meta = nn::hac::GameCardFsMetaGenerator(gc_fs_raw, mHdr.getPartitionFsSize(), mVerify ? nn::hac::GameCardFsMetaGenerator::ValidationMode_Warn : nn::hac::GameCardFsMetaGenerator::ValidationMode_None);
std::shared_ptr<tc::io::IStorage> gc_vfs = std::make_shared<tc::io::VirtualFileSystem>(tc::io::VirtualFileSystem(gc_vfs_meta) );
mFsProcess.setInputFileSystem(mFileSystem);
mFsProcess.setFsFormatName("PartitionFs");
mFsProcess.setFsProperties({
FsProcess fs_proc;
fs_proc.setInputFileSystem(gc_vfs);
fs_proc.setFsFormatName("PartitionFs");
fs_proc.setFsProperties({
fmt::format("Type: Nested HFS0"),
fmt::format("DirNum: {:d}", gc_vfs_snapshot.dir_entries.empty() ? 0 : gc_vfs_snapshot.dir_entries.size() - 1), // -1 to not include root directory
fmt::format("FileNum: {:d}", gc_vfs_snapshot.file_entries.size())
fmt::format("DirNum: {:d}", gc_vfs_meta.dir_entries.empty() ? 0 : gc_vfs_meta.dir_entries.size() - 1), // -1 to not include root directory
fmt::format("FileNum: {:d}", gc_vfs_meta.file_entries.size())
});
mFsProcess.setShowFsInfo(mCliOutputMode.show_basic_info);
mFsProcess.setFsRootLabel(kXciMountPointName);
mFsProcess.process();
fs_proc.setShowFsInfo(mCliOutputMode.show_basic_info);
fs_proc.setShowFsTree(mListFs);
fs_proc.setFsRootLabel(kXciMountPointName);
fs_proc.setExtractJobs(mExtractJobs);
fs_proc.process();
}

View file

@ -3,7 +3,7 @@
#include "KeyBag.h"
#include "PfsProcess.h"
#include <pietendo/hac/GameCardHeader.h>
#include <nn/hac/GameCardHeader.h>
namespace nstool {
@ -32,18 +32,18 @@ private:
KeyBag mKeyCfg;
CliOutputMode mCliOutputMode;
bool mVerify;
bool mListFs;
bool mIsTrueSdkXci;
bool mIsSdkXciEncrypted;
size_t mGcHeaderOffset;
bool mProccessExtendedHeader;
pie::hac::detail::rsa2048_signature_t mHdrSignature;
pie::hac::detail::sha256_hash_t mHdrHash;
pie::hac::GameCardHeader mHdr;
nn::hac::detail::rsa2048_signature_t mHdrSignature;
nn::hac::detail::sha256_hash_t mHdrHash;
nn::hac::GameCardHeader mHdr;
// fs processing
std::shared_ptr<tc::io::IFileSystem> mFileSystem;
FsProcess mFsProcess;
PfsProcess mRootPfs;
std::vector<nstool::ExtractJob> mExtractJobs;
void importHeader();
void displayHeader();

View file

@ -59,13 +59,13 @@ void nstool::IniProcess::importHeader()
}
// check if file_size is smaller than INI header size
if (tc::io::IOUtil::castInt64ToSize(mFile->length()) < sizeof(pie::hac::sIniHeader))
if (tc::io::IOUtil::castInt64ToSize(mFile->length()) < sizeof(nn::hac::sIniHeader))
{
throw tc::Exception(mModuleName, "Corrupt INI: file too small.");
}
// read ini
tc::ByteData scratch = tc::ByteData(sizeof(pie::hac::sIniHeader));
tc::ByteData scratch = tc::ByteData(sizeof(nn::hac::sIniHeader));
mFile->seek(0, tc::io::SeekOrigin::Begin);
mFile->read(scratch.data(), scratch.size());
@ -76,12 +76,12 @@ void nstool::IniProcess::importHeader()
void nstool::IniProcess::importKipList()
{
// kip pos info
int64_t kip_pos = tc::io::IOUtil::castSizeToInt64(sizeof(pie::hac::sIniHeader));
int64_t kip_pos = tc::io::IOUtil::castSizeToInt64(sizeof(nn::hac::sIniHeader));
int64_t kip_size = 0;
// tmp data to determine size
pie::hac::sKipHeader hdr_raw;
pie::hac::KernelInitialProcessHeader hdr;
nn::hac::sKipHeader hdr_raw;
nn::hac::KernelInitialProcessHeader hdr;
for (size_t i = 0; i < mHdr.getKipNum(); i++)
{
@ -121,11 +121,12 @@ void nstool::IniProcess::extractKipList()
tc::ByteData cache = tc::ByteData(kCacheSize);
// make extract dir
tc::io::LocalFileSystem local_fs;
tc::io::LocalStorage local_fs;
local_fs.createDirectory(mKipExtractPath.get());
// out path for extracted KIP
tc::io::Path out_path;
std::string out_path_str;
// extract KIPs
for (auto itr = mKipList.begin(); itr != mKipList.end(); itr++)
@ -133,15 +134,17 @@ void nstool::IniProcess::extractKipList()
out_path = mKipExtractPath.get();
out_path += fmt::format("{:s}.kip", itr->hdr.getName());
tc::io::PathUtil::pathToUnixUTF8(out_path, out_path_str);
if (mCliOutputMode.show_basic_info)
fmt::print("Saving {:s}...\n", out_path.to_string());
fmt::print("Saving {:s}...\n", out_path_str);
writeStreamToFile(itr->stream, out_path, cache);
}
}
int64_t nstool::IniProcess::getKipSizeFromHeader(const pie::hac::KernelInitialProcessHeader& hdr) const
int64_t nstool::IniProcess::getKipSizeFromHeader(const nn::hac::KernelInitialProcessHeader& hdr) const
{
// the order of elements in a KIP are sequential, there are no file offsets
return int64_t(sizeof(pie::hac::sKipHeader)) + int64_t(hdr.getTextSegmentInfo().file_layout.size + hdr.getRoSegmentInfo().file_layout.size + hdr.getDataSegmentInfo().file_layout.size);
return int64_t(sizeof(nn::hac::sKipHeader)) + int64_t(hdr.getTextSegmentInfo().file_layout.size + hdr.getRoSegmentInfo().file_layout.size + hdr.getDataSegmentInfo().file_layout.size);
}

View file

@ -1,8 +1,8 @@
#pragma once
#include "types.h"
#include <pietendo/hac/IniHeader.h>
#include <pietendo/hac/KernelInitialProcessHeader.h>
#include <nn/hac/IniHeader.h>
#include <nn/hac/KernelInitialProcessHeader.h>
namespace nstool {
@ -29,10 +29,10 @@ private:
tc::Optional<tc::io::Path> mKipExtractPath;
pie::hac::IniHeader mHdr;
nn::hac::IniHeader mHdr;
struct InnerKipInfo
{
pie::hac::KernelInitialProcessHeader hdr;
nn::hac::KernelInitialProcessHeader hdr;
std::shared_ptr<tc::io::IStream> stream;
};
std::vector<InnerKipInfo> mKipList;
@ -43,7 +43,7 @@ private:
void displayKipList();
void extractKipList();
int64_t getKipSizeFromHeader(const pie::hac::KernelInitialProcessHeader& hdr) const;
int64_t getKipSizeFromHeader(const nn::hac::KernelInitialProcessHeader& hdr) const;
};
}

View file

@ -3,33 +3,28 @@
#include "util.h"
#include <tc/cli/FormatUtil.h>
#include <pietendo/hac/define/types.h>
#include <pietendo/hac/define/gc.h>
#include <pietendo/hac/AesKeygen.h>
#include <nn/hac/define/types.h>
#include <nn/hac/define/gc.h>
#include <nn/hac/AesKeygen.h>
#include <pietendo/hac/es/SignUtils.h>
#include <pietendo/hac/es/SignedData.h>
#include <pietendo/hac/es/CertificateBody.h>
#include <pietendo/hac/es/TicketBody_V2.h>
#include <nn/pki/SignUtils.h>
#include <nn/pki/SignedData.h>
#include <nn/pki/CertificateBody.h>
#include <nn/es/TicketBody_V2.h>
nstool::KeyBagInitializer::KeyBagInitializer(bool isDev, const tc::Optional<tc::io::Path>& keyfile_path, const tc::Optional<tc::io::Path>& titlekeyfile_path, const std::vector<tc::io::Path>& tik_path_list, const tc::Optional<tc::io::Path>& cert_path)
nstool::KeyBagInitializer::KeyBagInitializer(bool isDev, const tc::Optional<tc::io::Path>& keyfile_path, const tc::Optional<tc::io::Path>& tik_path, const tc::Optional<tc::io::Path>& cert_path)
{
if (keyfile_path.isSet())
{
importBaseKeyFile(keyfile_path.get(), isDev);
}
if (titlekeyfile_path.isSet())
{
importTitleKeyFile(titlekeyfile_path.get());
}
if (cert_path.isSet())
{
importCertificateChain(cert_path.get());
}
if (!tik_path_list.empty())
if (tik_path.isSet())
{
for (auto itr = tik_path_list.begin(); itr != tik_path_list.end(); itr++)
importTicket(*itr);
importTicket(tik_path.get());
}
// this will populate known keys if they aren't supplied by the user provided keyfiles.
@ -357,7 +352,7 @@ void nstool::KeyBagInitializer::importBaseKeyFile(const tc::io::Path& keyfile_pa
}
// xci header key (old label, prod/dev keys are actually a fake distinction, the are different key indexes available to both?, so select correct index when importing)
//fmt::print("{:s}_{:s}\n", kXciHeaderBase[name_idx], kKeyStr);
_SAVE_AES128KEY(fmt::format("{:s}_{:s}", kXciHeaderBase[name_idx], kKeyStr), xci_header_key[isDev ? pie::hac::gc::KekIndex_Dev : pie::hac::gc::KekIndex_Prod]);
_SAVE_AES128KEY(fmt::format("{:s}_{:s}", kXciHeaderBase[name_idx], kKeyStr), xci_header_key[isDev ? nn::hac::gc::KEK_DEV : nn::hac::gc::KEK_PROD]);
// xci header sign key
//fmt::print("{:s}_{:s}_{:s}\n", kXciHeaderBase[name_idx], kSignKey, kPrivateStr);
@ -409,22 +404,22 @@ void nstool::KeyBagInitializer::importBaseKeyFile(const tc::io::Path& keyfile_pa
if (nca_header_key.isNull())
{
aes128_key_t nca_header_kek_tmp;
pie::hac::AesKeygen::generateKey(nca_header_kek_tmp.data(), aes_kek_generation_source.get().data(), nca_header_kek_source.get().data(), aes_key_generation_source.get().data(), itr->second.data());
nn::hac::AesKeygen::generateKey(nca_header_kek_tmp.data(), aes_kek_generation_source.get().data(), nca_header_kek_source.get().data(), aes_key_generation_source.get().data(), itr->second.data());
aes128_xtskey_t nca_header_key_tmp;
pie::hac::AesKeygen::generateKey(nca_header_key_tmp[0].data(), nca_header_key_source.get()[0].data(), nca_header_kek_tmp.data());
pie::hac::AesKeygen::generateKey(nca_header_key_tmp[1].data(), nca_header_key_source.get()[1].data(), nca_header_kek_tmp.data());
nn::hac::AesKeygen::generateKey(nca_header_key_tmp[0].data(), nca_header_key_source.get()[0].data(), nca_header_kek_tmp.data());
nn::hac::AesKeygen::generateKey(nca_header_key_tmp[1].data(), nca_header_key_source.get()[1].data(), nca_header_kek_tmp.data());
nca_header_key = nca_header_key_tmp;
}
}
for (size_t keak_idx = 0; keak_idx < pie::hac::nca::kKeyAreaEncryptionKeyNum; keak_idx++)
for (size_t keak_idx = 0; keak_idx < nn::hac::nca::kKeyAreaEncryptionKeyNum; keak_idx++)
{
if (key_area_key_source[keak_idx].isSet() && nca_key_area_encryption_key[keak_idx].find(itr->first) == nca_key_area_encryption_key[keak_idx].end())
if (key_area_key_source[keak_idx].isSet() && nca_key_area_encryption_key[keak_idx].find(itr->first) != nca_key_area_encryption_key[keak_idx].end())
{
aes128_key_t nca_key_area_encryption_key_tmp;
pie::hac::AesKeygen::generateKey(nca_key_area_encryption_key_tmp.data(), aes_kek_generation_source.get().data(), key_area_key_source[keak_idx].get().data(), aes_key_generation_source.get().data(), itr->second.data());
nn::hac::AesKeygen::generateKey(nca_key_area_encryption_key_tmp.data(), aes_kek_generation_source.get().data(), key_area_key_source[keak_idx].get().data(), aes_key_generation_source.get().data(), itr->second.data());
nca_key_area_encryption_key[keak_idx][itr->first] = nca_key_area_encryption_key_tmp;
}
}
@ -432,13 +427,13 @@ void nstool::KeyBagInitializer::importBaseKeyFile(const tc::io::Path& keyfile_pa
if (ticket_titlekek_source.isSet() && etik_common_key.find(itr->first) == etik_common_key.end())
{
aes128_key_t etik_common_key_tmp;
pie::hac::AesKeygen::generateKey(etik_common_key_tmp.data(), ticket_titlekek_source.get().data(), itr->second.data());
nn::hac::AesKeygen::generateKey(etik_common_key_tmp.data(), ticket_titlekek_source.get().data(), itr->second.data());
etik_common_key[itr->first] = etik_common_key_tmp;
}
if (package2_key_source.isSet() && pkg2_key.find(itr->first) == pkg2_key.end())
{
aes128_key_t pkg2_key_tmp;
pie::hac::AesKeygen::generateKey(pkg2_key_tmp.data(), package2_key_source.get().data(), itr->second.data());
nn::hac::AesKeygen::generateKey(pkg2_key_tmp.data(), package2_key_source.get().data(), itr->second.data());
pkg2_key[itr->first] = pkg2_key_tmp;
}
}
@ -446,58 +441,28 @@ void nstool::KeyBagInitializer::importBaseKeyFile(const tc::io::Path& keyfile_pa
// Save PKI Root Key
if (pki_root_sign_key.isSet())
{
broadon_signer["Root"] = { tc::ByteData(), pie::hac::es::sign::SIGN_ALGO_RSA4096, pki_root_sign_key.get() };
broadon_signer["Root"] = { tc::ByteData(), nn::pki::sign::SIGN_ALGO_RSA4096, pki_root_sign_key.get() };
}
}
void nstool::KeyBagInitializer::importTitleKeyFile(const tc::io::Path& keyfile_path)
{
std::shared_ptr<tc::io::FileStream> keyfile_stream = std::make_shared<tc::io::FileStream>(tc::io::FileStream(keyfile_path, tc::io::FileMode::Open, tc::io::FileAccess::Read));
// import keyfile into a dictionary
std::map<std::string, std::string> keyfile_dict;
processResFile(keyfile_stream, keyfile_dict);
// process title keys
tc::ByteData tmp;
KeyBag::rights_id_t rights_id_tmp;
KeyBag::aes128_key_t title_key_tmp;
for (auto itr = keyfile_dict.begin(); itr != keyfile_dict.end(); itr++)
{
//fmt::print("RightsID[{:s}] = TitleKey[{:s}]\n", itr->first, itr->second);
// parse the rights id
tmp = tc::cli::FormatUtil::hexStringToBytes(itr->first);
if (tmp.size() != rights_id_tmp.size())
{
fmt::print("[nstool::KeyBagInitializer WARNING] RightsID: \"{}\" has incorrect length. Skipping...\n", itr->first);
continue;
}
memcpy(rights_id_tmp.data(), tmp.data(), rights_id_tmp.size());
// parse the title key
tmp = tc::cli::FormatUtil::hexStringToBytes(itr->second);
if (tmp.size() != title_key_tmp.size())
{
fmt::print("[nstool::KeyBagInitializer WARNING] TitleKey for \"{}\": \"{}\" has incorrect length. Skipping...\n", itr->first, itr->second);
continue;
}
memcpy(title_key_tmp.data(), tmp.data(), title_key_tmp.size());
// save to encrypted key dict
external_enc_content_keys[rights_id_tmp] = title_key_tmp;
}
}
void nstool::KeyBagInitializer::importCertificateChain(const tc::io::Path& cert_path)
{
// save file path string for error messages
std::string cert_path_str;
tc::io::PathUtil::pathToUnixUTF8(cert_path, cert_path_str);
// open cert file
std::shared_ptr<tc::io::FileStream> certfile_stream;
try {
certfile_stream = std::make_shared<tc::io::FileStream>(tc::io::FileStream(cert_path, tc::io::FileMode::Open, tc::io::FileAccess::Read));
}
catch (tc::io::FileNotFoundException& e) {
fmt::print("[WARNING] Failed to open certificate file \"{:s}\" ({:s}).\n", cert_path.to_string(), e.error());
fmt::print("[WARNING] Failed to open certificate file \"{:s}\" ({:s}).\n", cert_path_str, e.error());
return;
}
@ -505,7 +470,7 @@ void nstool::KeyBagInitializer::importCertificateChain(const tc::io::Path& cert_
size_t cert_raw_size = tc::io::IOUtil::castInt64ToSize(certfile_stream->length());
if (cert_raw_size > 0x10000)
{
fmt::print("[WARNING] Certificate file \"{:s}\" was too large.\n", cert_path.to_string());
fmt::print("[WARNING] Certificate file \"{:s}\" was too large.\n", cert_path_str);
return;
}
@ -514,7 +479,7 @@ void nstool::KeyBagInitializer::importCertificateChain(const tc::io::Path& cert_
certfile_stream->seek(0, tc::io::SeekOrigin::Begin);
certfile_stream->read(cert_raw.data(), cert_raw.size());
pie::hac::es::SignedData<pie::hac::es::CertificateBody> cert;
nn::pki::SignedData<nn::pki::CertificateBody> cert;
try {
for (size_t f_pos = 0; f_pos < cert_raw.size(); f_pos += cert.getBytes().size())
{
@ -523,14 +488,14 @@ void nstool::KeyBagInitializer::importCertificateChain(const tc::io::Path& cert_
std::string cert_identity = fmt::format("{:s}-{:s}", cert.getBody().getIssuer(), cert.getBody().getSubject());
switch (cert.getBody().getPublicKeyType()) {
case pie::hac::es::cert::PublicKeyType::RSA2048:
broadon_signer[cert_identity] = { cert.getBytes(), pie::hac::es::sign::SIGN_ALGO_RSA2048, cert.getBody().getRsa2048PublicKey() };
case nn::pki::cert::PublicKeyType::RSA2048:
broadon_signer[cert_identity] = { cert.getBytes(), nn::pki::sign::SIGN_ALGO_RSA2048, cert.getBody().getRsa2048PublicKey() };
break;
case pie::hac::es::cert::PublicKeyType::RSA4096:
broadon_signer[cert_identity] = { cert.getBytes(), pie::hac::es::sign::SIGN_ALGO_RSA4096, cert.getBody().getRsa4096PublicKey() };
case nn::pki::cert::PublicKeyType::RSA4096:
broadon_signer[cert_identity] = { cert.getBytes(), nn::pki::sign::SIGN_ALGO_RSA4096, cert.getBody().getRsa4096PublicKey() };
break;
case pie::hac::es::cert::PublicKeyType::ECDSA240:
// broadon_signer[cert_identity] = { cert.getBytes(), pie::hac::es::sign::SIGN_ALGO_ECDSA240, cert.getBody().getRsa4096PublicKey() };
case nn::pki::cert::PublicKeyType::ECDSA240:
// broadon_signer[cert_identity] = { cert.getBytes(), nn::pki::sign::SIGN_ALGO_ECDSA240, cert.getBody().getRsa4096PublicKey() };
fmt::print("[WARNING] Certificate {:s} will not be imported. ecc233 public keys are not supported yet.\n", cert_identity);
break;
default:
@ -539,20 +504,24 @@ void nstool::KeyBagInitializer::importCertificateChain(const tc::io::Path& cert_
}
}
catch (tc::Exception& e) {
fmt::print("[WARNING] Certificate file \"{:s}\" is corrupted ({:s}).\n", cert_path.to_string(), e.error());
fmt::print("[WARNING] Certificate file \"{:s}\" is corrupted ({:s}).\n", cert_path_str, e.error());
return;
}
}
void nstool::KeyBagInitializer::importTicket(const tc::io::Path& tik_path)
{
// save file path string for error messages
std::string tik_path_str;
tc::io::PathUtil::pathToUnixUTF8(tik_path, tik_path_str);
// open cert file
std::shared_ptr<tc::io::FileStream> tik_stream;
try {
tik_stream = std::make_shared<tc::io::FileStream>(tc::io::FileStream(tik_path, tc::io::FileMode::Open, tc::io::FileAccess::Read));
}
catch (tc::io::FileNotFoundException& e) {
fmt::print("[WARNING] Failed to open ticket \"{:s}\" ({:s}).\n", tik_path.to_string(), e.error());
fmt::print("[WARNING] Failed to open ticket \"{:s}\" ({:s}).\n", tik_path_str, e.error());
return;
}
@ -560,7 +529,7 @@ void nstool::KeyBagInitializer::importTicket(const tc::io::Path& tik_path)
size_t tik_raw_size = tc::io::IOUtil::castInt64ToSize(tik_stream->length());
if (tik_raw_size > 0x10000)
{
fmt::print("[WARNING] Ticket \"{:s}\" was too large.\n", tik_path.to_string());
fmt::print("[WARNING] Ticket \"{:s}\" was too large.\n", tik_path_str);
return;
}
@ -569,7 +538,7 @@ void nstool::KeyBagInitializer::importTicket(const tc::io::Path& tik_path)
tik_stream->seek(0, tc::io::SeekOrigin::Begin);
tik_stream->read(tik_raw.data(), tik_raw.size());
pie::hac::es::SignedData<pie::hac::es::TicketBody_V2> tik;
nn::pki::SignedData<nn::es::TicketBody_V2> tik;
try {
// de serialise ticket
tik.fromBytes(tik_raw.data(), tik_raw.size());
@ -579,7 +548,7 @@ void nstool::KeyBagInitializer::importTicket(const tc::io::Path& tik_path)
memcpy(rights_id.data(), tik.getBody().getRightsId(), rights_id.size());
// check ticket is not personalised
if (tik.getBody().getTitleKeyEncType() != pie::hac::es::ticket::AES128_CBC)
if (tik.getBody().getTitleKeyEncType() != nn::es::ticket::AES128_CBC)
{
fmt::print("[WARNING] Ticket \"{:s}\" will not be imported. Personalised tickets are not supported.\n", tc::cli::FormatUtil::formatBytesAsString(rights_id.data(), rights_id.size(), true, ""));
return;
@ -590,7 +559,10 @@ void nstool::KeyBagInitializer::importTicket(const tc::io::Path& tik_path)
memcpy(enc_title_key.data(), tik.getBody().getEncTitleKey(), enc_title_key.size());
// save the encrypted title key as the fallback enc content key incase the ticket was malformed and workarounds to decrypt it in isolation fail
external_enc_content_keys[rights_id] = enc_title_key;
if (fallback_enc_content_key.isNull())
{
fallback_enc_content_key = enc_title_key;
}
// determine key to decrypt title key
byte_t common_key_index = tik.getBody().getCommonKeyId();
@ -605,7 +577,7 @@ void nstool::KeyBagInitializer::importTicket(const tc::io::Path& tik_path)
}
// convert key_generation
common_key_index = pie::hac::AesKeygen::getMasterKeyRevisionFromKeyGeneration(common_key_index);
common_key_index = nn::hac::AesKeygen::getMasterKeyRevisionFromKeyGeneration(common_key_index);
if (etik_common_key.find(common_key_index) == etik_common_key.end())
{
@ -617,19 +589,19 @@ void nstool::KeyBagInitializer::importTicket(const tc::io::Path& tik_path)
aes128_key_t dec_title_key;
tc::crypto::DecryptAes128Ecb(dec_title_key.data(), enc_title_key.data(), sizeof(aes128_key_t), etik_common_key[common_key_index].data(), sizeof(aes128_key_t));
// add to decrypted key dict
// add to key dict
external_content_keys[rights_id] = dec_title_key;
}
catch (tc::Exception& e) {
fmt::print("[WARNING] Ticket \"{:s}\" is corrupted ({:s}).\n", tik_path.to_string(), e.error());
fmt::print("[WARNING] Ticket \"{:s}\" is corrupted ({:s}).\n", tik_path_str, e.error());
return;
}
}
void nstool::KeyBagInitializer::importKnownKeys(bool isDev)
{
static const pie::hac::detail::rsa2048_block_t kXciHeaderSignModulus = {
static const nn::hac::detail::rsa2048_block_t kXciHeaderSignModulus = {
0x98, 0xC7, 0x26, 0xB6, 0x0D, 0x0A, 0x50, 0xA7, 0x39, 0x21, 0x0A, 0xE3, 0x2F, 0xE4, 0x3E, 0x2E,
0x5B, 0xA2, 0x86, 0x75, 0xAA, 0x5C, 0xEE, 0x34, 0xF1, 0xA3, 0x3A, 0x7E, 0xBD, 0x90, 0x4E, 0xF7,
0x8D, 0xFA, 0x17, 0xAA, 0x6B, 0xC6, 0x36, 0x6D, 0x4C, 0x9A, 0x6D, 0x57, 0x2F, 0x80, 0xA2, 0xBC,
@ -648,7 +620,7 @@ void nstool::KeyBagInitializer::importKnownKeys(bool isDev)
0x9A, 0xC1, 0xDD, 0x62, 0x86, 0x9C, 0x2E, 0xE1, 0x2D, 0x6F, 0x62, 0x67, 0x51, 0x08, 0x0E, 0xCF
};
static const pie::hac::detail::rsa2048_block_t kXciCertSignModulus = {
static const nn::hac::detail::rsa2048_block_t kXciCertSignModulus = {
0xCD, 0xF3, 0x2C, 0xB0, 0xF5, 0x14, 0x78, 0x34, 0xE5, 0x02, 0xD0, 0x29, 0x6A, 0xA5, 0xFD, 0x97,
0x6A, 0xE0, 0xB0, 0xBB, 0xB0, 0x3B, 0x1A, 0x80, 0xB7, 0xD7, 0x58, 0x92, 0x79, 0x84, 0xC0, 0x36,
0xB1, 0x55, 0x23, 0xD8, 0xA5, 0x60, 0x91, 0x26, 0x48, 0x1A, 0x80, 0x4A, 0xEA, 0x00, 0x98, 0x2A,
@ -669,7 +641,7 @@ void nstool::KeyBagInitializer::importKnownKeys(bool isDev)
/* Keydata for very early beta NCA0 archives' RSA-OAEP. */
/*
static const pie::hac::detail::rsa2048_block_t beta_nca0_modulus = {
static const nn::hac::detail::rsa2048_block_t beta_nca0_modulus = {
0xAD, 0x58, 0xEE, 0x97, 0xF9, 0x47, 0x90, 0x7D, 0xF9, 0x29, 0x5F, 0x1F, 0x39, 0x68, 0xEE, 0x49,
0x4C, 0x1E, 0x8D, 0x84, 0x91, 0x31, 0x5D, 0xE5, 0x96, 0x27, 0xB2, 0xB3, 0x59, 0x7B, 0xDE, 0xFD,
0xB7, 0xEB, 0x40, 0xA1, 0xE7, 0xEB, 0xDC, 0x60, 0xD0, 0x3D, 0xC5, 0x50, 0x92, 0xAD, 0x3D, 0xC4,
@ -688,7 +660,7 @@ void nstool::KeyBagInitializer::importKnownKeys(bool isDev)
0xB0, 0xB4, 0xD0, 0x17, 0xA1, 0x0F, 0x73, 0x98, 0x5A, 0xF6, 0xEE, 0xC0, 0x2F, 0x9E, 0xCE, 0xC5
};
static const pie::hac::detail::sha256_hash_t beta_nca0_label_hash = {
static const nn::hac::detail::sha256_hash_t beta_nca0_label_hash = {
0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24,
0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55
};
@ -696,10 +668,10 @@ void nstool::KeyBagInitializer::importKnownKeys(bool isDev)
struct sRsaKeyForGeneration {
byte_t generation;
pie::hac::detail::rsa2048_block_t modulus;
nn::hac::detail::rsa2048_block_t modulus;
};
static const pie::hac::detail::rsa2048_block_t kProdPackage2HeaderModulus = {
static const nn::hac::detail::rsa2048_block_t kProdPackage2HeaderModulus = {
0x8D, 0x13, 0xA7, 0x77, 0x6A, 0xE5, 0xDC, 0xC0, 0x3B, 0x25, 0xD0, 0x58, 0xE4, 0x20, 0x69, 0x59,
0x55, 0x4B, 0xAB, 0x70, 0x40, 0x08, 0x28, 0x07, 0xA8, 0xA7, 0xFD, 0x0F, 0x31, 0x2E, 0x11, 0xFE,
0x47, 0xA0, 0xF9, 0x9D, 0xDF, 0x80, 0xDB, 0x86, 0x5A, 0x27, 0x89, 0xCD, 0x97, 0x6C, 0x85, 0xC5,
@ -802,7 +774,7 @@ void nstool::KeyBagInitializer::importKnownKeys(bool isDev)
},
};
static const pie::hac::detail::rsa2048_block_t kDevPackage2HeaderModulus = {
static const nn::hac::detail::rsa2048_block_t kDevPackage2HeaderModulus = {
0xB3, 0x65, 0x54, 0xFB, 0x0A, 0xB0, 0x1E, 0x85, 0xA7, 0xF6, 0xCF, 0x91, 0x8E, 0xBA, 0x96, 0x99,
0x0D, 0x8B, 0x91, 0x69, 0x2A, 0xEE, 0x01, 0x20, 0x4F, 0x34, 0x5C, 0x2C, 0x4F, 0x4E, 0x37, 0xC7,
0xF1, 0x0B, 0xD4, 0xCD, 0xA1, 0x7F, 0x93, 0xF1, 0x33, 0x59, 0xCE, 0xB1, 0xE9, 0xDD, 0x26, 0xE6,
@ -908,7 +880,7 @@ void nstool::KeyBagInitializer::importKnownKeys(bool isDev)
struct sBroadOnRsaKeyAndCert
{
std::string issuer;
pie::hac::es::sign::SignatureAlgo key_type;
nn::pki::sign::SignatureAlgo key_type;
tc::ByteData modulus;
tc::ByteData certificate;
};
@ -917,31 +889,31 @@ void nstool::KeyBagInitializer::importKnownKeys(bool isDev)
{
{
"Root",
pie::hac::es::sign::SIGN_ALGO_RSA4096,
nn::pki::sign::SIGN_ALGO_RSA4096,
tc::cli::FormatUtil::hexStringToBytes("F8246C58BAE7500301FBB7C2EBE0010571DA922378F0514EC0031DD0D21ED3D07EFC852069B5DE9BB951A8BC90A244926D379295AE9436AAA6A302510C7B1DEDD5FB20869D7F3016F6BE65D383A16DB3321B95351890B17002937EE193F57E99A2474E9D3824C7AEE38541F567E7518C7A0E38E7EBAF41191BCFF17B42A6B4EDE6CE8DE7318F7F5204B3990E226745AFD485B24493008B08C7F6B7E56B02B3E8FE0C9D859CB8B68223B8AB27EE5F6538078B2DB91E2A153E85818072A23B6DD93281054F6FB0F6F5AD283ECA0B7AF35455E03DA7B68326F3EC834AF314048AC6DF20D28508673CAB62A2C7BC131A533E0B66806B1C30664B372331BDC4B0CAD8D11EE7BBD9285548AAEC1F66E821B3C8A0476900C5E688E80CCE3C61D69CBBA137C6604F7A72DD8C7B3E3D51290DAA6A597B081F9D3633A3467A356109ACA7DD7D2E2FB2C1AEB8E20F4892D8B9F8B46F4E3C11F4F47D8B757DFEFEA3899C33595C5EFDEBCBABE8413E3A9A803C69356EB2B2AD5CC4C858455EF5F7B30644B47C64068CDF809F76025A2DB446E03D7CF62F34E702457B02A4CF5D9DD53CA53A7CA629788C67CA08BFECCA43A957AD16C94E1CD875CA107DCE7E0118F0DF6BFEE51DDBD991C26E60CD4858AA592C820075F29F526C917C6FE5403EA7D4A50CEC3B7384DE886E82D2EB4D4E42B5F2B149A81EA7CE7144DC2994CFC44E1F91CBD495"),
tc::ByteData()
},
{
"Root-CA00000003",
pie::hac::es::sign::SIGN_ALGO_RSA2048,
nn::pki::sign::SIGN_ALGO_RSA2048,
tc::cli::FormatUtil::hexStringToBytes("B279C9E2EEE121C6EAF44FF639F88F078B4B77ED9F9560B0358281B50E55AB721115A177703C7A30FE3AE9EF1C60BC1D974676B23A68CC04B198525BC968F11DE2DB50E4D9E7F071E562DAE2092233E9D363F61DD7C19FF3A4A91E8F6553D471DD7B84B9F1B8CE7335F0F5540563A1EAB83963E09BE901011F99546361287020E9CC0DAB487F140D6626A1836D27111F2068DE4772149151CF69C61BA60EF9D949A0F71F5499F2D39AD28C7005348293C431FFBD33F6BCA60DC7195EA2BCC56D200BAF6D06D09C41DB8DE9C720154CA4832B69C08C69CD3B073A0063602F462D338061A5EA6C915CD5623579C3EB64CE44EF586D14BAAA8834019B3EEBEED379"),
tc::cli::FormatUtil::hexStringToBytes("00010003704138EFBBBDA16A987DD901326D1C9459484C88A2861B91A312587AE70EF6237EC50E1032DC39DDE89A96A8E859D76A98A6E7E36A0CFE352CA893058234FF833FCB3B03811E9F0DC0D9A52F8045B4B2F9411B67A51C44B5EF8CE77BD6D56BA75734A1856DE6D4BED6D3A242C7C8791B3422375E5C779ABF072F7695EFA0F75BCB83789FC30E3FE4CC8392207840638949C7F688565F649B74D63D8D58FFADDA571E9554426B1318FC468983D4C8A5628B06B6FC5D507C13E7A18AC1511EB6D62EA5448F83501447A9AFB3ECC2903C9DD52F922AC9ACDBEF58C6021848D96E208732D3D1D9D9EA440D91621C7A99DB8843C59C1F2E2C7D9B577D512C166D6F7E1AAD4A774A37447E78FE2021E14A95D112A068ADA019F463C7A55685AABB6888B9246483D18B9C806F474918331782344A4B8531334B26303263D9D2EB4F4BB99602B352F6AE4046C69A5E7E8E4A18EF9BC0A2DED61310417012FD824CC116CFB7C4C1F7EC7177A17446CBDE96F3EDD88FCD052F0B888A45FDAF2B631354F40D16E5FA9C2C4EDA98E798D15E6046DC5363F3096B2C607A9D8DD55B1502A6AC7D3CC8D8C575998E7D796910C804C495235057E91ECD2637C9C1845151AC6B9A0490AE3EC6F47740A0DB0BA36D075956CEE7354EA3E9A4F2720B26550C7D394324BC0CB7E9317D8A8661F42191FF10B08256CE3FD25B745E5194906B4D61CB4C2E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000526F6F7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001434130303030303030330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007BE8EF6CB279C9E2EEE121C6EAF44FF639F88F078B4B77ED9F9560B0358281B50E55AB721115A177703C7A30FE3AE9EF1C60BC1D974676B23A68CC04B198525BC968F11DE2DB50E4D9E7F071E562DAE2092233E9D363F61DD7C19FF3A4A91E8F6553D471DD7B84B9F1B8CE7335F0F5540563A1EAB83963E09BE901011F99546361287020E9CC0DAB487F140D6626A1836D27111F2068DE4772149151CF69C61BA60EF9D949A0F71F5499F2D39AD28C7005348293C431FFBD33F6BCA60DC7195EA2BCC56D200BAF6D06D09C41DB8DE9C720154CA4832B69C08C69CD3B073A0063602F462D338061A5EA6C915CD5623579C3EB64CE44EF586D14BAAA8834019B3EEBEED3790001000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
},
{
"Root-CA00000003-XS00000020",
pie::hac::es::sign::SIGN_ALGO_RSA2048,
nn::pki::sign::SIGN_ALGO_RSA2048,
tc::cli::FormatUtil::hexStringToBytes("D21D3CE67C1069DA049D5E5310E76B907E18EEC80B337C4723E339573F4C664907DB2F0832D03DF5EA5F160A4AF24100D71AFAC2E3AE75AFA1228012A9A21616597DF71EAFCB65941470D1B40F5EF83A597E179FCB5B57C2EE17DA3BC3769864CB47856767229D67328141FC9AB1DF149E0C5C15AEB80BC58FC71BE18966642D68308B506934B8EF779F78E4DDF30A0DCF93FCAFBFA131A8839FD641949F47EE25CEECF814D55B0BE6E5677C1EFFEC6F29871EF29AA3ED9197B0D83852E050908031EF1ABBB5AFC8B3DD937A076FF6761AB362405C3F7D86A3B17A6170A659C16008950F7F5E06A5DE3E5998895EFA7DEEA060BE9575668F78AB1907B3BA1B7D"),
tc::cli::FormatUtil::hexStringToBytes("00010004969FE8288DA6B9DD52C7BD63642A4A9AE5F053ECCB93613FDA37992087BD9199DA5E6797618D77098133FD5B05CD8288139E2E975CD2608003878CDAF020F51A0E5B7692780845561B31C61808E8A47C3462224D94F736E9A14E56ACBF71B7F11BBDEE38DDB846D6BD8F0AB4E4948C5434EAF9BF26529B7EB83671D3CE60A6D7A850DBE6801EC52A7B7A3E5A27BC675BA3C53377CFC372EBCE02062F59F37003AA23AE35D4880E0E4B69F982FB1BAC806C2F75BA29587F2815FD7783998C354D52B19E3FAD9FBEF444C48579288DB0978116AFC82CE54DACB9ED7E1BFD50938F22F85EECF3A4F426AE5FEB15B72F022FB36ECCE9314DAD131429BFC9675F58EE000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000526F6F742D4341303030303030303300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015853303030303030323000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000D21D3CE67C1069DA049D5E5310E76B907E18EEC80B337C4723E339573F4C664907DB2F0832D03DF5EA5F160A4AF24100D71AFAC2E3AE75AFA1228012A9A21616597DF71EAFCB65941470D1B40F5EF83A597E179FCB5B57C2EE17DA3BC3769864CB47856767229D67328141FC9AB1DF149E0C5C15AEB80BC58FC71BE18966642D68308B506934B8EF779F78E4DDF30A0DCF93FCAFBFA131A8839FD641949F47EE25CEECF814D55B0BE6E5677C1EFFEC6F29871EF29AA3ED9197B0D83852E050908031EF1ABBB5AFC8B3DD937A076FF6761AB362405C3F7D86A3B17A6170A659C16008950F7F5E06A5DE3E5998895EFA7DEEA060BE9575668F78AB1907B3BA1B7D0001000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
},
{
"Root-CA00000003-XS00000022",
pie::hac::es::sign::SIGN_ALGO_RSA2048,
nn::pki::sign::SIGN_ALGO_RSA2048,
tc::cli::FormatUtil::hexStringToBytes("E29775264ADC30C0FDE2DEFCFBBAC406A3B1C2ADDC2644C4C3E46DAD11E4F1ED7BC8B6E8CDBBE87E01020DF807520CE8A8F88BB53BE82CAFF4A1AF7FC5CD69EB34E24BEA74781203B611D09EBF56F82E3F21A494549F407FABA948545B34B64F487E1F27B031A83D337CE40496A3034AC6A2DB9E9353A1967EC7A07A4B3672B5B3F7934FF166D90EC131D8A75DC925ED629F8381A586589A82790489D4BF170F29F8E4BE50811ECBA9564D5517362D8DE777B01FC0A0AD8DED692CEAFD028A468CD6A6BF18A2767801AF8BB954EDB4DA3CED78337F3E9B6A1602B94752C85A53993678FDFA0300A4200CA752FA0D94E5A4B74B726FB61876146E49EC148508F5"),
tc::cli::FormatUtil::hexStringToBytes("0001000458C7FFCDB0A1758925286C3C5029942683A8ED614A4E5C24EECE90548F99A0E59429C3D7D9CA37910CC1F5974E3AA2D7438627FBE456C9C830E5BF5B4440013CD41AA6F0AE02307E3EDEF3EDE0E6404A87234786FED37878F4BF4D964C2290C66AF167AC94869DC2F8378FA3FE0B764F776F9CE479B9E7A4EAE77FCA924B84035C9C06075F5F23BBF3A202AC1AF6A640C62BEEE4603925534783642663238A803D5FC87C5BEA58E09B0669CE9273509A87FACEDA94333FC6264D095708C18F9A50963F0E02A0771AEBC7174D4A89BE158C6CF407BD11658363E924F2808B15C7FE00267565CBD386E576540C906F9B2FFB3AFC64BA1198FA711A48F107E6A9AD000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000526F6F742D4341303030303030303300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015853303030303030323200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E29775264ADC30C0FDE2DEFCFBBAC406A3B1C2ADDC2644C4C3E46DAD11E4F1ED7BC8B6E8CDBBE87E01020DF807520CE8A8F88BB53BE82CAFF4A1AF7FC5CD69EB34E24BEA74781203B611D09EBF56F82E3F21A494549F407FABA948545B34B64F487E1F27B031A83D337CE40496A3034AC6A2DB9E9353A1967EC7A07A4B3672B5B3F7934FF166D90EC131D8A75DC925ED629F8381A586589A82790489D4BF170F29F8E4BE50811ECBA9564D5517362D8DE777B01FC0A0AD8DED692CEAFD028A468CD6A6BF18A2767801AF8BB954EDB4DA3CED78337F3E9B6A1602B94752C85A53993678FDFA0300A4200CA752FA0D94E5A4B74B726FB61876146E49EC148508F50001000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
},
{
"Root-CA00000003-XS00000024",
pie::hac::es::sign::SIGN_ALGO_RSA2048,
nn::pki::sign::SIGN_ALGO_RSA2048,
tc::cli::FormatUtil::hexStringToBytes("C694562BBDC74E83069876608EAD1EE7B1BC715036E9A6BDF58A6D22FD660ABD9CF360AA893D7746C92C5B9D20E480EAD1387786739956E060EBA79BD6ED7C06B2FCC6DBC1734ED12999AFEE5396FEE722FE3B96846D903F00A32671AC0CEDAAAB0C933C950304650A76152ED1B69547031793755599939B42F075CDF137F8C16D35870DE90D1BACBDB4B746F814AED0D3CB7F7C1B789A1FDF9947717B641BA972A6460D3258F5561CAA1D8E20085E8E3B9EBC92C9B6DCBB872A2AE02D74577F65EFA5AAFF29FD52EAA400D1408B2815C5C96CD2B54DF0F6708A755FB1DFA694A7794C4A0422F1BF8FAFE9E6870578133D50FD3D5356506CFCEC94EF79D6B639"),
tc::cli::FormatUtil::hexStringToBytes("000100046EEED0424FF97D659DA43F85DF01E0997BA1FD1593997145BDE95703AABBDB7EFDE315F8CFE8AEC0F710FFF002938AEF8CEF7EBF90F725B6AC4EDA66DCF85132435E974DDBBE8F8C725CD114CE38C83404DFC0123BB4137C676C5C86EB4E211B7C35A03AB0C7E7637F1BF2486FDF0A5CCE5B047483841B5EA6BDC09AE770951ACA79EFB5497C46750585CF6C3FE4159ACE1CDFAB1BA8C00AB2446B57383F2F063344052E48E1557BD60BF973B252AC5AB4F5A12323AFCC1B06718775F3EDA4DD580A47A04D8063844235DC35D21A4FDED5A44EA401519920B73D15C66FDDF9F8286CF9122795EB9D5EA95C6E51603F6E62AA1631549EBE9E272B4BC3AEBC0D89000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000526F6F742D4341303030303030303300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015853303030303030323400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C694562BBDC74E83069876608EAD1EE7B1BC715036E9A6BDF58A6D22FD660ABD9CF360AA893D7746C92C5B9D20E480EAD1387786739956E060EBA79BD6ED7C06B2FCC6DBC1734ED12999AFEE5396FEE722FE3B96846D903F00A32671AC0CEDAAAB0C933C950304650A76152ED1B69547031793755599939B42F075CDF137F8C16D35870DE90D1BACBDB4B746F814AED0D3CB7F7C1B789A1FDF9947717B641BA972A6460D3258F5561CAA1D8E20085E8E3B9EBC92C9B6DCBB872A2AE02D74577F65EFA5AAFF29FD52EAA400D1408B2815C5C96CD2B54DF0F6708A755FB1DFA694A7794C4A0422F1BF8FAFE9E6870578133D50FD3D5356506CFCEC94EF79D6B6390001000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
}
@ -951,31 +923,31 @@ void nstool::KeyBagInitializer::importKnownKeys(bool isDev)
{
{
"Root",
pie::hac::es::sign::SIGN_ALGO_RSA4096,
nn::pki::sign::SIGN_ALGO_RSA4096,
tc::cli::FormatUtil::hexStringToBytes("D01FE100D43556B24B56DAE971B5A5D384B93003BE1BBF28A2305B060645467D5B0251D2561A274F9E9F9CEC646150AB3D2AE3366866ACA4BAE81AE3D79AA6B04A8BCBA7E6FB648945EBDFDB85BA091FD7D114B5A3A780E3A22E6ECD87B5A4C6F910E4032208814B0CEEA1A17DF739695F617EF63528DB949637A056037F7B32413895C0A8F1982E1565E38EEDC22E590EE2677B8609F48C2E303FBC405CAC18042F822084E4936803DA7F41349248562B8EE12F78F803246330BC7BE7EE724AF458A472E7AB46A1A7C10C2F18FA07C3DDD89806A11C9CC130B247A33C8D47DE67F29E5577B11C43493D5BBA7634A7E4E71531B7DF5981FE24A114554CBD8F005CE1DB35085CCFC77806B6DE254068A26CB5492D4580438FE1E5A9ED75C5ED451DCE789439CCC3BA28A2312A1B8719EF0F73B713950C02591A7462A607F37C0AA7A18FA943A36D752A5F4192F0136100AA9CB41BBE14BEB1F9FC692FDFA09446DE5A9DDE2CA5F68C1C0C21429287CB2DAAA3D263752F73E09FAF4479D2817429F69800AFDE6B592DC19882BDF581CCABF2CB91029EF35C4CFDBBFF49C1FA1B2FE31DE7A560ECB47EBCFE32425B956F81B69917487E3B789151DB2E78B1FD2EBE7E626B3EA165B4FB00CCB751AF507329C4A3939EA6DD9C50A0E7386B0145796B41AF61F78555944F3BC22DC3BD0D00F8798A42B1AAA08320659AC7395AB4F329"),
tc::ByteData()
},
{
"Root-CA00000004",
pie::hac::es::sign::SIGN_ALGO_RSA2048,
nn::pki::sign::SIGN_ALGO_RSA2048,
tc::cli::FormatUtil::hexStringToBytes("C9CC2DC4DF2930E4DF3F8C70A078948775AD5E9AA604C5B4D8EAFF2AA1D214676564EFCA28CC00154554A1A3EA1379E9E6CAACED1593FE88D89AC6B8ACCCAB6E207CEB7CCA29809E2980440662B7D4382A15DA43085745A9AAE59AA05BDB32F66869A2DD4295386C87ECDD3508A2CF60D01E23EC2FE698F470D6001549A2F06759131E534C7006057DEF1D18A83F0AC79CFE80FF5A91F2BED4A0837061190A0329902165403C9A908FB615739F3CE33BF1BAEA16C25BCED7963FACC9D24D9C0AD76FC020B2C4B84C10A741A2CC7D9BAC3AACCCA3529BAC316A9AA75D2A26C7D7D288CBA466C5FE5F454AE679744A90A15772DB3B0E47A49AF031D16DBEAB332B"),
tc::cli::FormatUtil::hexStringToBytes("000100031949429D1E58A62E7E8B56D1B76AE302FD8B97491F778745F75388C4DD0BEB1DF122FB9642151497764A53CF78151845E42CA8FDE486FD2A4F53F8A1BA008A7485FF73B3BF7E3C980729D0656B693219ADE835EB5FFFFCCB7CBB5E307FE0688B888EF2D2053FB7E791E985FD15EF10D79CCA88D6BB15E8E4714A98EE09BF7B8AF053232B6450E6D5FDFFC20A6D1EA6A23812E1014525D56D4082703B86986959A73CD1A14364D2C2DAEA96B095F76C46E4FF4155465E70EF1ED31053D97011E010CC93E7914013687FA3A802996D1E557B1CCC7A7E8F5865C1742E28E26DEF38A93AB5D82D43ECCCBF0BEF22E1FD57E2864333582FEDEABC012F986DDFC3E9447973470308455BDC57AA170B84427F73A29B48F6DA135F66C745C142A84AFB0E6A5EED85D7B9719936F8CE2B621F395F40DC03BEF8854C1117FF0C128641CC7843B97B4346DB226F6026ACB56C278B8E0EA79A2D65EF798E1078AD80ED4B9604D2F08B2CD64A23A3DB270833B402F80851F35BED3EE4577C6660FBF16D9413E09C917A49D42C6DA375BC27F0230DB98F8973AB027B522CD57EC03D25E8B3FC3494C97FB108FE18C68A4336E46C26B6F280D27E34BE287C3E4687BC9D776B76D928D1B6352EC0347D7294AA9360268D26F5F652064AF240D7D00C7C5EA3C32DE62D9B5C4B4CAB6FD7BD371D57C2166095910E4AD8E9ED181EF761936153892D77000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000526F6F74000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014341303030303030303400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000081122A46C9CC2DC4DF2930E4DF3F8C70A078948775AD5E9AA604C5B4D8EAFF2AA1D214676564EFCA28CC00154554A1A3EA1379E9E6CAACED1593FE88D89AC6B8ACCCAB6E207CEB7CCA29809E2980440662B7D4382A15DA43085745A9AAE59AA05BDB32F66869A2DD4295386C87ECDD3508A2CF60D01E23EC2FE698F470D6001549A2F06759131E534C7006057DEF1D18A83F0AC79CFE80FF5A91F2BED4A0837061190A0329902165403C9A908FB615739F3CE33BF1BAEA16C25BCED7963FACC9D24D9C0AD76FC020B2C4B84C10A741A2CC7D9BAC3AACCCA3529BAC316A9AA75D2A26C7D7D288CBA466C5FE5F454AE679744A90A15772DB3B0E47A49AF031D16DBEAB332B0001000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
},
{
"Root-CA00000004-XS00000020",
pie::hac::es::sign::SIGN_ALGO_RSA2048,
nn::pki::sign::SIGN_ALGO_RSA2048,
tc::cli::FormatUtil::hexStringToBytes("BA278428765D879A7F215404C6EE4E0A0D3F66C33BC7F8A32FD898E52CB7B63443CED8B00527D89DEDC6BBF60AD1C5C9923021DD555F9BAD4BE0C0C406D3702915E5B34AC2D2ABE503C32A3A23B43834C9157B9A0AF2E4E9C03BEDE2B4C115F5353DFC66BD04A6C079970E38CBDD5A50A2B98FF2D765FCF83381E9E0E849C3573578378FF65951613E95F75EE8EF26183A40AAE4A76D7384EA478D2CDCE80FBA0321A6BF8D69983C3AA7AE5443B72BFE410BF1323CBD88C3560EA13D17D38A2E34041DE7AAF389DE4375225CA87EE349C760C7D99BE7E737C6261CC74E25AE46527AC9619F939057088D7435A6DE7B25AB82DD5410F2579CAEF1491A909D302B"),
tc::cli::FormatUtil::hexStringToBytes("00010004603483F7F4EF3C863FF7B46821E9D83983EFB0BA29C45B10DFB2E8A268AE06084DFEB0B9680B6D40D6DF82CAE7D651E28F31364F5AB567DD9DCCFCBB5EFF8F1CEA92489C046E8BED2AF0D7F9CA0BD50F683633D681B08D1AF417D7B7F8762AD88E3AF0D1C45DAC5407B9D8F24F167AEDC7C5DBCF4E0E176EC341D4F9BA8ADFE749CF37F45688653886566A9045ED89AD353DD289E32631867BDFD7FC67738BDF0E1E858F3BF9DEE25B02206F0B7FFB61F866DA4D862D77DDBDA9668BB61CBDEFACB2583CE5C9FAB22FC90EF8EB06954743E5A32A37A3513C6C795BC8E0C65E2F170B435A8C447765381C4050427F88E9828E6E94144D28441C7F9C7F6D92FE5B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000526F6F742D4341303030303030303400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015853303030303030323000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000BA278428765D879A7F215404C6EE4E0A0D3F66C33BC7F8A32FD898E52CB7B63443CED8B00527D89DEDC6BBF60AD1C5C9923021DD555F9BAD4BE0C0C406D3702915E5B34AC2D2ABE503C32A3A23B43834C9157B9A0AF2E4E9C03BEDE2B4C115F5353DFC66BD04A6C079970E38CBDD5A50A2B98FF2D765FCF83381E9E0E849C3573578378FF65951613E95F75EE8EF26183A40AAE4A76D7384EA478D2CDCE80FBA0321A6BF8D69983C3AA7AE5443B72BFE410BF1323CBD88C3560EA13D17D38A2E34041DE7AAF389DE4375225CA87EE349C760C7D99BE7E737C6261CC74E25AE46527AC9619F939057088D7435A6DE7B25AB82DD5410F2579CAEF1491A909D302B0001000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
},
{
"Root-CA00000004-XS00000021",
pie::hac::es::sign::SIGN_ALGO_RSA2048,
nn::pki::sign::SIGN_ALGO_RSA2048,
tc::cli::FormatUtil::hexStringToBytes("CA303087732E88FB2736A4644B6A84DF02393786EBE3DBE914F92224126AB3C38D7CA67322B7D3107B9AC0E00AED9AF13DEDDC62BCB8AC889A47B07196B45BC97AC5DD333CC63E872E30CDB52BD35E055FBA56C2521AFC8BBFC8B06390522E99699750B457C8647A42D6318BE5EAA192ADA35DA7023FC348215613141919821FD5599B93497893CA58E7A88C8D6E6E9EB0A57567BF8C12EB25241BB6082BED7A696658A58DDB66E7CC2562F2EA061E5373E6A5397BF6299F7EA9065B0047AA408F24A5D6F6E4050B99DA86831F663792E08D96F182400182D9BECB917AE315A238CA89741B6AEAF52E238590CDA60FC5B74DC638F9D6FCAF95D2CA7AE005A7B1"),
tc::cli::FormatUtil::hexStringToBytes("000100041282394569ED63B5C4E54747B31E3B32C68B0EB90712E3C04662101CA77A551A0394CC36CB28E369DFBBB9FD78C9C503C3B1F184729C2B05B4D1691581A877AF82F8EC3D70E95B27F459039B65D8221D4864CCB282FF721EBDD6C46863F8C95591C1BF36D0AC118C0027FA3E2D434821A5FEF123C65F17885321F9A520C22B9EE6FC533EEF582706A95DD0CEABACE87B0169E136336E2E9CC0399637CE4CC77B6DA418671A277614F80A0A909569018F624DE0C5E1A67DB134C63F1FFE30BB64C201FDD8DAD42F4C88B247C1C6133CC554DE6B15684320D6AA1E09CB59EAD15F37140C9DD4BE69D87CC90DD8F733C946FBA6C576C70533601AF4E8294A3B5DD4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000526F6F742D4341303030303030303400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015853303030303030323100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000CA303087732E88FB2736A4644B6A84DF02393786EBE3DBE914F92224126AB3C38D7CA67322B7D3107B9AC0E00AED9AF13DEDDC62BCB8AC889A47B07196B45BC97AC5DD333CC63E872E30CDB52BD35E055FBA56C2521AFC8BBFC8B06390522E99699750B457C8647A42D6318BE5EAA192ADA35DA7023FC348215613141919821FD5599B93497893CA58E7A88C8D6E6E9EB0A57567BF8C12EB25241BB6082BED7A696658A58DDB66E7CC2562F2EA061E5373E6A5397BF6299F7EA9065B0047AA408F24A5D6F6E4050B99DA86831F663792E08D96F182400182D9BECB917AE315A238CA89741B6AEAF52E238590CDA60FC5B74DC638F9D6FCAF95D2CA7AE005A7B10001000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
},
{
"Root-CA00000004-XS00000024",
pie::hac::es::sign::SIGN_ALGO_RSA2048,
nn::pki::sign::SIGN_ALGO_RSA2048,
tc::cli::FormatUtil::hexStringToBytes("E5E262EA591EEB885DE5A3CA451CE9E4FEA0E89DAA9BBCD9EC6C23E3FEFCE31BE7C7217DAC3E1F5A8331EF3F0C738E9310E765E71AAAB92C6E18D36071E7F93446E06E2581A28483AE9EB9C8217C1D68A21FD098E186C71B6A1E1E2626C80B69FFD562EAD515C77D616554F6B74B34DEEB0DE905F44631F56A6FF12B47AC0190578267559592FAB173146071ECFBB014951512E45299A21C0B8B3377E55DCD95625130E533877BF11157585D43DB00F61DFE77CFA44F5F29F44945DBF4214F37214921C16ED7D74455B2AE7C8CA15DFBD20A4D5E6501965B78C2C542727D7A91C071C56403738F07E858239CD150DB304BA5ACD8751145A9A91D3E97085AD217"),
tc::cli::FormatUtil::hexStringToBytes("000100049EA82934BD64EDCED4D506BB68BF1F217BAD912BEF134B687C8E590F2A9355D8EDD9BE00D85735A83820F69978B3E2876FE07BBB7F356B25CDCC98EEEA17BFA9EF649769E921BFDA7867D0570D2F0A7A223E7ACD8D9AE1F304F8EEC6C96B11805436CF686FBD05969E4C0D19A63EF89DA00899222D2CF006776FF027118E96CB027114AABBA268CB1775022B25EAF045C9E4A328A55FF85CFFFFFEAEFB78F1CD184ED9042D23A06F0161E5FBADE92638A483A1A3680DC9994A03D02F1D76EB0EE793843D31CCC172A3993C7344B2C5E634F2B89C47F85FD8B74D21745AEBCFD55E32FC03F6BCD40421499261F8AB93AC8A07E6EF5436036283A3B86192890A78000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000526F6F742D4341303030303030303400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015853303030303030323400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E5E262EA591EEB885DE5A3CA451CE9E4FEA0E89DAA9BBCD9EC6C23E3FEFCE31BE7C7217DAC3E1F5A8331EF3F0C738E9310E765E71AAAB92C6E18D36071E7F93446E06E2581A28483AE9EB9C8217C1D68A21FD098E186C71B6A1E1E2626C80B69FFD562EAD515C77D616554F6B74B34DEEB0DE905F44631F56A6FF12B47AC0190578267559592FAB173146071ECFBB014951512E45299A21C0B8B3377E55DCD95625130E533877BF11157585D43DB00F61DFE77CFA44F5F29F44945DBF4214F37214921C16ED7D74455B2AE7C8CA15DFBD20A4D5E6501965B78C2C542727D7A91C071C56403738F07E858239CD150DB304BA5ACD8751145A9A91D3E97085AD2170001000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
}

View file

@ -5,22 +5,22 @@
#include <map>
#include <tc/Optional.h>
#include <tc/io.h>
#include <pietendo/hac/es/SignUtils.h>
#include <pietendo/hac/define/types.h>
#include <pietendo/hac/define/nca.h>
#include <nn/pki/SignUtils.h>
#include <nn/hac/define/types.h>
#include <nn/hac/define/nca.h>
namespace nstool {
struct KeyBag
{
using aes128_key_t = pie::hac::detail::aes128_key_t;
using aes128_xtskey_t = pie::hac::detail::aes128_xtskey_t;
using aes128_key_t = nn::hac::detail::aes128_key_t;
using aes128_xtskey_t = nn::hac::detail::aes128_xtskey_t;
using rsa_key_t = tc::crypto::RsaKey;
//using ecc_key_t = tc::crypto::EccKey;
using rights_id_t = pie::hac::detail::rights_id_t;
using rights_id_t = nn::hac::detail::rights_id_t;
using key_generation_t = byte_t;
using broadon_issuer_t = std::string;
static const size_t kNcaKeakNum = pie::hac::nca::kKeyAreaEncryptionKeyNum;
static const size_t kNcaKeakNum = nn::hac::nca::kKeyAreaEncryptionKeyNum;
// acid
@ -39,7 +39,6 @@ struct KeyBag
// external content keys (nca<->ticket)
std::map<rights_id_t, aes128_key_t> external_content_keys;
std::map<rights_id_t, aes128_key_t> external_enc_content_keys; // encrypted content key list to be used when external_content_keys does not have the required content key (usually taken raw from ticket)
tc::Optional<aes128_key_t> fallback_enc_content_key; // encrypted content key to be used when external_content_keys does not have the required content key (usually taken raw from ticket)
tc::Optional<aes128_key_t> fallback_content_key; // content key to be used when external_content_keys does not have the required content key (usually already decrypted from ticket)
@ -61,7 +60,7 @@ struct KeyBag
{
tc::ByteData certificate;
pie::hac::es::sign::SignatureAlgo key_type;
nn::pki::sign::SignatureAlgo key_type;
rsa_key_t rsa_key;
// ecc_key_t ecc_key;
};
@ -71,7 +70,7 @@ struct KeyBag
class KeyBagInitializer : public KeyBag
{
public:
KeyBagInitializer(bool isDev, const tc::Optional<tc::io::Path>& keyfile_path, const tc::Optional<tc::io::Path>& titlekeyfile_path, const std::vector<tc::io::Path>& tik_path_list, const tc::Optional<tc::io::Path>& cert_path);
KeyBagInitializer(bool isDev, const tc::Optional<tc::io::Path>& keyfile_path, const tc::Optional<tc::io::Path>& tik_path, const tc::Optional<tc::io::Path>& cert_path);
private:
KeyBagInitializer();

View file

@ -1,6 +1,6 @@
#include "KipProcess.h"
#include <pietendo/hac/KernelCapabilityUtil.h>
#include <nn/hac/KernelCapabilityUtil.h>
#include <tc/NotImplementedException.h>
@ -50,13 +50,13 @@ void nstool::KipProcess::importHeader()
}
// check if file_size is smaller than KIP header size
if (tc::io::IOUtil::castInt64ToSize(mFile->length()) < sizeof(pie::hac::sKipHeader))
if (tc::io::IOUtil::castInt64ToSize(mFile->length()) < sizeof(nn::hac::sKipHeader))
{
throw tc::Exception(mModuleName, "Corrupt KIP: file too small.");
}
// read kip
tc::ByteData scratch = tc::ByteData(sizeof(pie::hac::sKipHeader));
tc::ByteData scratch = tc::ByteData(sizeof(nn::hac::sKipHeader));
mFile->seek(0, tc::io::SeekOrigin::Begin);
mFile->read(scratch.data(), scratch.size());
@ -189,12 +189,12 @@ void nstool::KipProcess::displayHeader()
}
void nstool::KipProcess::displayKernelCap(const pie::hac::KernelCapabilityControl& kern)
void nstool::KipProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern)
{
fmt::print("[Kernel Capabilities]\n");
if (kern.getThreadInfo().isSet())
{
pie::hac::ThreadInfoHandler threadInfo = kern.getThreadInfo();
nn::hac::ThreadInfoHandler threadInfo = kern.getThreadInfo();
fmt::print(" Thread Priority:\n");
fmt::print(" Min: {:d}\n", threadInfo.getMinPriority());
fmt::print(" Max: {:d}\n", threadInfo.getMaxPriority());
@ -211,7 +211,7 @@ void nstool::KipProcess::displayKernelCap(const pie::hac::KernelCapabilityContro
for (size_t syscall_id = 0; syscall_id < syscall_ids.size(); syscall_id++)
{
if (syscall_ids.test(syscall_id))
syscall_names.push_back(pie::hac::KernelCapabilityUtil::getSystemCallIdAsString(pie::hac::kc::SystemCallId(syscall_id)));
syscall_names.push_back(nn::hac::KernelCapabilityUtil::getSystemCallIdAsString(nn::hac::kc::SystemCallId(syscall_id)));
}
fmt::print("{:s}", tc::cli::FormatUtil::formatListWithLineLimit(syscall_names, 60, 4));
}
@ -243,7 +243,7 @@ void nstool::KipProcess::displayKernelCap(const pie::hac::KernelCapabilityContro
}
if (kern.getMiscParams().isSet())
{
fmt::print(" ProgramType: {:s} ({:d})\n", pie::hac::KernelCapabilityUtil::getProgramTypeAsString(kern.getMiscParams().getProgramType()), (uint32_t)kern.getMiscParams().getProgramType());
fmt::print(" ProgramType: {:s} ({:d})\n", nn::hac::KernelCapabilityUtil::getProgramTypeAsString(kern.getMiscParams().getProgramType()), kern.getMiscParams().getProgramType());
}
if (kern.getKernelVersion().isSet())
{
@ -261,13 +261,13 @@ void nstool::KipProcess::displayKernelCap(const pie::hac::KernelCapabilityContro
for (size_t misc_flags_bit = 0; misc_flags_bit < misc_flags.size(); misc_flags_bit++)
{
if (misc_flags.test(misc_flags_bit))
misc_flags_names.push_back(pie::hac::KernelCapabilityUtil::getMiscFlagsBitAsString(pie::hac::kc::MiscFlagsBit(misc_flags_bit)));
misc_flags_names.push_back(nn::hac::KernelCapabilityUtil::getMiscFlagsBitAsString(nn::hac::kc::MiscFlagsBit(misc_flags_bit)));
}
fmt::print("{:s}", tc::cli::FormatUtil::formatListWithLineLimit(misc_flags_names, 60, 4));
}
}
std::string nstool::KipProcess::formatMappingAsString(const pie::hac::MemoryMappingHandler::sMemoryMapping& map) const
std::string nstool::KipProcess::formatMappingAsString(const nn::hac::MemoryMappingHandler::sMemoryMapping& map) const
{
return fmt::format("0x{:016x} - 0x{:016x} (perm={:s}) (type={:s})", ((uint64_t)map.addr << 12), (((uint64_t)(map.addr + map.size) << 12) - 1), pie::hac::KernelCapabilityUtil::getMemoryPermissionAsString(map.perm), pie::hac::KernelCapabilityUtil::getMappingTypeAsString(map.type));
return fmt::format("0x{:016x} - 0x{:016x} (perm={:s}) (type={:s})", ((uint64_t)map.addr << 12), (((uint64_t)(map.addr + map.size) << 12) - 1), nn::hac::KernelCapabilityUtil::getMemoryPermissionAsString(map.perm), nn::hac::KernelCapabilityUtil::getMappingTypeAsString(map.type));
}

View file

@ -1,7 +1,7 @@
#pragma once
#include "types.h"
#include <pietendo/hac/KernelInitialProcessHeader.h>
#include <nn/hac/KernelInitialProcessHeader.h>
namespace nstool {
@ -22,16 +22,16 @@ private:
CliOutputMode mCliOutputMode;
bool mVerify;
pie::hac::KernelInitialProcessHeader mHdr;
nn::hac::KernelInitialProcessHeader mHdr;
tc::ByteData mTextBlob, mRoBlob, mDataBlob;
void importHeader();
void importCodeSegments();
size_t decompressData(const byte_t* src, size_t src_len, byte_t* dst, size_t dst_capacity);
void displayHeader();
void displayKernelCap(const pie::hac::KernelCapabilityControl& kern);
void displayKernelCap(const nn::hac::KernelCapabilityControl& kern);
std::string formatMappingAsString(const pie::hac::MemoryMappingHandler::sMemoryMapping& map) const;
std::string formatMappingAsString(const nn::hac::MemoryMappingHandler::sMemoryMapping& map) const;
};
}

View file

@ -1,9 +1,9 @@
#include "MetaProcess.h"
#include <pietendo/hac/AccessControlInfoUtil.h>
#include <pietendo/hac/FileSystemAccessUtil.h>
#include <pietendo/hac/KernelCapabilityUtil.h>
#include <pietendo/hac/MetaUtil.h>
#include <nn/hac/AccessControlInfoUtil.h>
#include <nn/hac/FileSystemAccessUtil.h>
#include <nn/hac/KernelCapabilityUtil.h>
#include <nn/hac/MetaUtil.h>
nstool::MetaProcess::MetaProcess() :
mModuleName("nstool::MetaProcess"),
@ -65,7 +65,7 @@ void nstool::MetaProcess::setVerifyMode(bool verify)
mVerify = verify;
}
const pie::hac::Meta& nstool::MetaProcess::getMeta() const
const nn::hac::Meta& nstool::MetaProcess::getMeta() const
{
return mMeta;
}
@ -96,7 +96,7 @@ void nstool::MetaProcess::importMeta()
mMeta.fromBytes(scratch.data(), scratch.size());
}
void nstool::MetaProcess::validateAcidSignature(const pie::hac::AccessControlInfoDesc& acid, byte_t key_generation)
void nstool::MetaProcess::validateAcidSignature(const nn::hac::AccessControlInfoDesc& acid, byte_t key_generation)
{
try {
if (mKeyCfg.acid_sign_key.find(key_generation) == mKeyCfg.acid_sign_key.end())
@ -112,7 +112,7 @@ void nstool::MetaProcess::validateAcidSignature(const pie::hac::AccessControlInf
}
void nstool::MetaProcess::validateAciFromAcid(const pie::hac::AccessControlInfo& aci, const pie::hac::AccessControlInfoDesc& acid)
void nstool::MetaProcess::validateAciFromAcid(const nn::hac::AccessControlInfo& aci, const nn::hac::AccessControlInfoDesc& acid)
{
// check Program ID
if (acid.getProgramIdRestrict().min > 0 && aci.getProgramId() < acid.getProgramIdRestrict().min)
@ -137,7 +137,7 @@ void nstool::MetaProcess::validateAciFromAcid(const pie::hac::AccessControlInfo&
if (rightFound == false)
{
fmt::print("[WARNING] ACI/FAC FsaRights: FAIL ({:s} not permitted)\n", pie::hac::FileSystemAccessUtil::getFsAccessFlagAsString(fs_access[i]));
fmt::print("[WARNING] ACI/FAC FsaRights: FAIL ({:s} not permitted)\n", nn::hac::FileSystemAccessUtil::getFsAccessFlagAsString(fs_access[i]));
}
}
@ -157,9 +157,6 @@ void nstool::MetaProcess::validateAciFromAcid(const pie::hac::AccessControlInfo&
}
}
// See https://github.com/jakcron/nstool/issues/92
// Nintendo doesn't populate SaveDataOwnerIdList in ACID, so this field cannot be verified
#if 0
for (size_t i = 0; i < aci.getFileSystemAccessControl().getSaveDataOwnerIdList().size(); i++)
{
bool rightFound = false;
@ -172,10 +169,9 @@ void nstool::MetaProcess::validateAciFromAcid(const pie::hac::AccessControlInfo&
if (rightFound == false)
{
fmt::print("[WARNING] ACI/FAC SaveDataOwnerId: FAIL (0x{:016x} ({:d}) not permitted)\n", aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].id, (uint32_t)aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].access_type);
fmt::print("[WARNING] ACI/FAC SaveDataOwnerId: FAIL (0x{:016x} ({:d}) not permitted)\n", aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].id, aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].access_type);
}
}
#endif
// check SAC
for (size_t i = 0; i < aci.getServiceAccessControl().getServiceList().size(); i++)
@ -218,7 +214,7 @@ void nstool::MetaProcess::validateAciFromAcid(const pie::hac::AccessControlInfo&
{
if (syscall_ids.test(i) && desc_syscall_ids.test(i) == false)
{
fmt::print("[WARNING] ACI/KC SystemCallList: FAIL ({:s} not permitted)\n", pie::hac::KernelCapabilityUtil::getSystemCallIdAsString(pie::hac::kc::SystemCallId(i)));
fmt::print("[WARNING] ACI/KC SystemCallList: FAIL ({:s} not permitted)\n", nn::hac::KernelCapabilityUtil::getSystemCallIdAsString(nn::hac::kc::SystemCallId(i)));
}
}
// check memory maps
@ -272,7 +268,7 @@ void nstool::MetaProcess::validateAciFromAcid(const pie::hac::AccessControlInfo&
// check misc params
if (aci.getKernelCapabilities().getMiscParams().getProgramType() != acid.getKernelCapabilities().getMiscParams().getProgramType())
{
fmt::print("[WARNING] ACI/KC ProgramType: FAIL ({:d} not permitted)\n", (uint32_t)aci.getKernelCapabilities().getMiscParams().getProgramType());
fmt::print("[WARNING] ACI/KC ProgramType: FAIL ({:d} not permitted)\n", aci.getKernelCapabilities().getMiscParams().getProgramType());
}
// check kernel version
uint32_t aciKernelVersion = (uint32_t)aci.getKernelCapabilities().getKernelVersion().getVerMajor() << 16 | (uint32_t)aci.getKernelCapabilities().getKernelVersion().getVerMinor();
@ -293,18 +289,18 @@ void nstool::MetaProcess::validateAciFromAcid(const pie::hac::AccessControlInfo&
{
if (misc_flags.test(i) && desc_misc_flags.test(i) == false)
{
fmt::print("[WARNING] ACI/KC MiscFlag: FAIL ({:s} not permitted)\n", pie::hac::KernelCapabilityUtil::getMiscFlagsBitAsString(pie::hac::kc::MiscFlagsBit(i)));
fmt::print("[WARNING] ACI/KC MiscFlag: FAIL ({:s} not permitted)\n", nn::hac::KernelCapabilityUtil::getMiscFlagsBitAsString(nn::hac::kc::MiscFlagsBit(i)));
}
}
}
void nstool::MetaProcess::displayMetaHeader(const pie::hac::Meta& hdr)
void nstool::MetaProcess::displayMetaHeader(const nn::hac::Meta& hdr)
{
fmt::print("[Meta Header]\n");
fmt::print(" ACID KeyGeneration: {:d}\n", hdr.getAccessControlInfoDescKeyGeneration());
fmt::print(" Flags:\n");
fmt::print(" Is64BitInstruction: {}\n", hdr.getIs64BitInstructionFlag());
fmt::print(" ProcessAddressSpace: {:s}\n", pie::hac::MetaUtil::getProcessAddressSpaceAsString(hdr.getProcessAddressSpace()));
fmt::print(" ProcessAddressSpace: {:s}\n", nn::hac::MetaUtil::getProcessAddressSpaceAsString(hdr.getProcessAddressSpace()));
fmt::print(" OptimizeMemoryAllocation: {}\n", hdr.getOptimizeMemoryAllocationFlag());
fmt::print(" SystemResourceSize: 0x{:x}\n", hdr.getSystemResourceSize());
fmt::print(" Main Thread Params:\n");
@ -320,25 +316,25 @@ void nstool::MetaProcess::displayMetaHeader(const pie::hac::Meta& hdr)
}
}
void nstool::MetaProcess::displayAciHdr(const pie::hac::AccessControlInfo& aci)
void nstool::MetaProcess::displayAciHdr(const nn::hac::AccessControlInfo& aci)
{
fmt::print("[Access Control Info]\n");
fmt::print(" ProgramID: 0x{:016x}\n", aci.getProgramId());
}
void nstool::MetaProcess::displayAciDescHdr(const pie::hac::AccessControlInfoDesc& acid)
void nstool::MetaProcess::displayAciDescHdr(const nn::hac::AccessControlInfoDesc& acid)
{
fmt::print("[Access Control Info Desc]\n");
fmt::print(" Flags: \n");
fmt::print(" Production: {}\n", acid.getProductionFlag());
fmt::print(" Unqualified Approval: {}\n", acid.getUnqualifiedApprovalFlag());
fmt::print(" Memory Region: {:s} ({:d})\n", pie::hac::AccessControlInfoUtil::getMemoryRegionAsString(acid.getMemoryRegion()), (uint32_t)acid.getMemoryRegion());
fmt::print(" Memory Region: {:s} ({:d})\n", nn::hac::AccessControlInfoUtil::getMemoryRegionAsString(acid.getMemoryRegion()), acid.getMemoryRegion());
fmt::print(" ProgramID Restriction\n");
fmt::print(" Min: 0x{:016x}\n", acid.getProgramIdRestrict().min);
fmt::print(" Max: 0x{:016x}\n", acid.getProgramIdRestrict().max);
}
void nstool::MetaProcess::displayFac(const pie::hac::FileSystemAccessControl& fac)
void nstool::MetaProcess::displayFac(const nn::hac::FileSystemAccessControl& fac)
{
fmt::print("[FS Access Control]\n");
fmt::print(" Format Version: {:d}\n", fac.getFormatVersion());
@ -348,10 +344,10 @@ void nstool::MetaProcess::displayFac(const pie::hac::FileSystemAccessControl& fa
std::vector<std::string> fs_access_str_list;
for (auto itr = fac.getFsAccess().begin(); itr != fac.getFsAccess().end(); itr++)
{
std::string flag_string = pie::hac::FileSystemAccessUtil::getFsAccessFlagAsString(pie::hac::fac::FsAccessFlag(*itr));
std::string flag_string = nn::hac::FileSystemAccessUtil::getFsAccessFlagAsString(nn::hac::fac::FsAccessFlag(*itr));
if (mCliOutputMode.show_extended_info)
{
fs_access_str_list.push_back(fmt::format("{:s} (bit {:d})", flag_string, (uint32_t)*itr));
fs_access_str_list.push_back(fmt::format("{:s} (bit {:d})", flag_string, *itr));
}
else
{
@ -378,12 +374,12 @@ void nstool::MetaProcess::displayFac(const pie::hac::FileSystemAccessControl& fa
fmt::print(" Save Data Owner IDs:\n");
for (size_t i = 0; i < fac.getSaveDataOwnerIdList().size(); i++)
{
fmt::print(" 0x{:016x} ({:s})\n", fac.getSaveDataOwnerIdList()[i].id, pie::hac::FileSystemAccessUtil::getSaveDataOwnerAccessModeAsString(fac.getSaveDataOwnerIdList()[i].access_type));
fmt::print(" 0x{:016x} ({:s})\n", fac.getSaveDataOwnerIdList()[i].id, nn::hac::FileSystemAccessUtil::getSaveDataOwnerAccessModeAsString(fac.getSaveDataOwnerIdList()[i].access_type));
}
}
}
void nstool::MetaProcess::displaySac(const pie::hac::ServiceAccessControl& sac)
void nstool::MetaProcess::displaySac(const nn::hac::ServiceAccessControl& sac)
{
fmt::print("[Service Access Control]\n");
fmt::print(" Service List:\n");
@ -395,12 +391,12 @@ void nstool::MetaProcess::displaySac(const pie::hac::ServiceAccessControl& sac)
fmt::print("{:s}", tc::cli::FormatUtil::formatListWithLineLimit(service_name_list, 60, 4));
}
void nstool::MetaProcess::displayKernelCap(const pie::hac::KernelCapabilityControl& kern)
void nstool::MetaProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern)
{
fmt::print("[Kernel Capabilities]\n");
if (kern.getThreadInfo().isSet())
{
pie::hac::ThreadInfoHandler threadInfo = kern.getThreadInfo();
nn::hac::ThreadInfoHandler threadInfo = kern.getThreadInfo();
fmt::print(" Thread Priority:\n");
fmt::print(" Min: {:d}\n", threadInfo.getMinPriority());
fmt::print(" Max: {:d}\n", threadInfo.getMaxPriority());
@ -417,7 +413,7 @@ void nstool::MetaProcess::displayKernelCap(const pie::hac::KernelCapabilityContr
for (size_t syscall_id = 0; syscall_id < syscall_ids.size(); syscall_id++)
{
if (syscall_ids.test(syscall_id))
syscall_names.push_back(pie::hac::KernelCapabilityUtil::getSystemCallIdAsString(pie::hac::kc::SystemCallId(syscall_id)));
syscall_names.push_back(nn::hac::KernelCapabilityUtil::getSystemCallIdAsString(nn::hac::kc::SystemCallId(syscall_id)));
}
fmt::print("{:s}", tc::cli::FormatUtil::formatListWithLineLimit(syscall_names, 60, 4));
}
@ -449,7 +445,7 @@ void nstool::MetaProcess::displayKernelCap(const pie::hac::KernelCapabilityContr
}
if (kern.getMiscParams().isSet())
{
fmt::print(" ProgramType: {:s} ({:d})\n", pie::hac::KernelCapabilityUtil::getProgramTypeAsString(kern.getMiscParams().getProgramType()), (uint32_t)kern.getMiscParams().getProgramType());
fmt::print(" ProgramType: {:s} ({:d})\n", nn::hac::KernelCapabilityUtil::getProgramTypeAsString(kern.getMiscParams().getProgramType()), kern.getMiscParams().getProgramType());
}
if (kern.getKernelVersion().isSet())
{
@ -467,13 +463,13 @@ void nstool::MetaProcess::displayKernelCap(const pie::hac::KernelCapabilityContr
for (size_t misc_flags_bit = 0; misc_flags_bit < misc_flags.size(); misc_flags_bit++)
{
if (misc_flags.test(misc_flags_bit))
misc_flags_names.push_back(pie::hac::KernelCapabilityUtil::getMiscFlagsBitAsString(pie::hac::kc::MiscFlagsBit(misc_flags_bit)));
misc_flags_names.push_back(nn::hac::KernelCapabilityUtil::getMiscFlagsBitAsString(nn::hac::kc::MiscFlagsBit(misc_flags_bit)));
}
fmt::print("{:s}", tc::cli::FormatUtil::formatListWithLineLimit(misc_flags_names, 60, 4));
}
}
std::string nstool::MetaProcess::formatMappingAsString(const pie::hac::MemoryMappingHandler::sMemoryMapping& map) const
std::string nstool::MetaProcess::formatMappingAsString(const nn::hac::MemoryMappingHandler::sMemoryMapping& map) const
{
return fmt::format("0x{:016x} - 0x{:016x} (perm={:s}) (type={:s})", ((uint64_t)map.addr << 12), (((uint64_t)(map.addr + map.size) << 12) - 1), pie::hac::KernelCapabilityUtil::getMemoryPermissionAsString(map.perm), pie::hac::KernelCapabilityUtil::getMappingTypeAsString(map.type));
return fmt::format("0x{:016x} - 0x{:016x} (perm={:s}) (type={:s})", ((uint64_t)map.addr << 12), (((uint64_t)(map.addr + map.size) << 12) - 1), nn::hac::KernelCapabilityUtil::getMemoryPermissionAsString(map.perm), nn::hac::KernelCapabilityUtil::getMappingTypeAsString(map.type));
}

View file

@ -2,7 +2,7 @@
#include "types.h"
#include "KeyBag.h"
#include <pietendo/hac/Meta.h>
#include <nn/hac/Meta.h>
namespace nstool {
@ -18,7 +18,7 @@ public:
void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify);
const pie::hac::Meta& getMeta() const;
const nn::hac::Meta& getMeta() const;
private:
std::string mModuleName;
@ -28,21 +28,21 @@ private:
CliOutputMode mCliOutputMode;
bool mVerify;
pie::hac::Meta mMeta;
nn::hac::Meta mMeta;
void importMeta();
void validateAcidSignature(const pie::hac::AccessControlInfoDesc& acid, byte_t key_generation);
void validateAciFromAcid(const pie::hac::AccessControlInfo& aci, const pie::hac::AccessControlInfoDesc& acid);
void validateAcidSignature(const nn::hac::AccessControlInfoDesc& acid, byte_t key_generation);
void validateAciFromAcid(const nn::hac::AccessControlInfo& aci, const nn::hac::AccessControlInfoDesc& acid);
void displayMetaHeader(const pie::hac::Meta& hdr);
void displayAciHdr(const pie::hac::AccessControlInfo& aci);
void displayAciDescHdr(const pie::hac::AccessControlInfoDesc& aci);
void displayFac(const pie::hac::FileSystemAccessControl& fac);
void displaySac(const pie::hac::ServiceAccessControl& sac);
void displayKernelCap(const pie::hac::KernelCapabilityControl& kern);
void displayMetaHeader(const nn::hac::Meta& hdr);
void displayAciHdr(const nn::hac::AccessControlInfo& aci);
void displayAciDescHdr(const nn::hac::AccessControlInfoDesc& aci);
void displayFac(const nn::hac::FileSystemAccessControl& fac);
void displaySac(const nn::hac::ServiceAccessControl& sac);
void displayKernelCap(const nn::hac::KernelCapabilityControl& kern);
std::string formatMappingAsString(const pie::hac::MemoryMappingHandler::sMemoryMapping& map) const;
std::string formatMappingAsString(const nn::hac::MemoryMappingHandler::sMemoryMapping& map) const;
};
}

View file

@ -1,6 +1,6 @@
#include "NacpProcess.h"
#include <pietendo/hac/ApplicationControlPropertyUtil.h>
#include <nn/hac/ApplicationControlPropertyUtil.h>
nstool::NacpProcess::NacpProcess() :
mModuleName("nstool::NacpProcess"),
@ -33,7 +33,7 @@ void nstool::NacpProcess::setVerifyMode(bool verify)
mVerify = verify;
}
const pie::hac::ApplicationControlProperty& nstool::NacpProcess::getApplicationControlProperty() const
const nn::hac::ApplicationControlProperty& nstool::NacpProcess::getApplicationControlProperty() const
{
return mNacp;
}
@ -51,7 +51,7 @@ void nstool::NacpProcess::importNacp()
// check if file_size does matches expected size
size_t file_size = tc::io::IOUtil::castInt64ToSize(mFile->length());
if (file_size != sizeof(pie::hac::sApplicationControlProperty))
if (file_size != sizeof(nn::hac::sApplicationControlProperty))
{
throw tc::Exception(mModuleName, "File was incorrect size.");
}
@ -74,7 +74,7 @@ void nstool::NacpProcess::displayNacp()
fmt::print(" Title:\n");
for (auto itr = mNacp.getTitle().begin(); itr != mNacp.getTitle().end(); itr++)
{
fmt::print(" {:s}:\n", pie::hac::ApplicationControlPropertyUtil::getLanguageAsString(itr->language));
fmt::print(" {:s}:\n", nn::hac::ApplicationControlPropertyUtil::getLanguageAsString(itr->language));
fmt::print(" Name: {:s}\n", itr->name);
fmt::print(" Publisher: {:s}\n", itr->publisher);
}
@ -95,21 +95,21 @@ void nstool::NacpProcess::displayNacp()
}
// StartupUserAccount
if (mNacp.getStartupUserAccount() != pie::hac::nacp::StartupUserAccount_None || mCliOutputMode.show_extended_info)
if (mNacp.getStartupUserAccount() != nn::hac::nacp::StartupUserAccount::None || mCliOutputMode.show_extended_info)
{
fmt::print(" StartupUserAccount: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getStartupUserAccountAsString(mNacp.getStartupUserAccount()));
fmt::print(" StartupUserAccount: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getStartupUserAccountAsString(mNacp.getStartupUserAccount()));
}
// UserAccountSwitchLock
if (mNacp.getUserAccountSwitchLock() != pie::hac::nacp::UserAccountSwitchLock_Disable || mCliOutputMode.show_extended_info)
if (mNacp.getUserAccountSwitchLock() != nn::hac::nacp::UserAccountSwitchLock::Disable || mCliOutputMode.show_extended_info)
{
fmt::print(" UserAccountSwitchLock: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getUserAccountSwitchLockAsString(mNacp.getUserAccountSwitchLock()));
fmt::print(" UserAccountSwitchLock: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getUserAccountSwitchLockAsString(mNacp.getUserAccountSwitchLock()));
}
// AddOnContentRegistrationType
if (mNacp.getAddOnContentRegistrationType() != pie::hac::nacp::AddOnContentRegistrationType_AllOnLaunch || mCliOutputMode.show_extended_info)
if (mNacp.getAddOnContentRegistrationType() != nn::hac::nacp::AddOnContentRegistrationType::AllOnLaunch || mCliOutputMode.show_extended_info)
{
fmt::print(" AddOnContentRegistrationType: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getAddOnContentRegistrationTypeAsString(mNacp.getAddOnContentRegistrationType()));
fmt::print(" AddOnContentRegistrationType: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getAddOnContentRegistrationTypeAsString(mNacp.getAddOnContentRegistrationType()));
}
// Attribute
@ -118,7 +118,7 @@ void nstool::NacpProcess::displayNacp()
fmt::print(" Attribute:\n");
for (auto itr = mNacp.getAttribute().begin(); itr != mNacp.getAttribute().end(); itr++)
{
fmt::print(" {:s}\n", pie::hac::ApplicationControlPropertyUtil::getAttributeFlagAsString(*itr));
fmt::print(" {:s}\n", nn::hac::ApplicationControlPropertyUtil::getAttributeFlagAsString(*itr));
}
}
else if (mCliOutputMode.show_extended_info)
@ -132,7 +132,7 @@ void nstool::NacpProcess::displayNacp()
fmt::print(" SupportedLanguage:\n");
for (auto itr = mNacp.getSupportedLanguage().begin(); itr != mNacp.getSupportedLanguage().end(); itr++)
{
fmt::print(" {:s}\n", pie::hac::ApplicationControlPropertyUtil::getLanguageAsString(*itr));
fmt::print(" {:s}\n", nn::hac::ApplicationControlPropertyUtil::getLanguageAsString(*itr));
}
}
else if (mCliOutputMode.show_extended_info)
@ -146,7 +146,7 @@ void nstool::NacpProcess::displayNacp()
fmt::print(" ParentalControl:\n");
for (auto itr = mNacp.getParentalControl().begin(); itr != mNacp.getParentalControl().end(); itr++)
{
fmt::print(" {:s}\n", pie::hac::ApplicationControlPropertyUtil::getParentalControlFlagAsString(*itr));
fmt::print(" {:s}\n", nn::hac::ApplicationControlPropertyUtil::getParentalControlFlagAsString(*itr));
}
}
else if (mCliOutputMode.show_extended_info)
@ -155,27 +155,27 @@ void nstool::NacpProcess::displayNacp()
}
// Screenshot
if (mNacp.getScreenshot() != pie::hac::nacp::Screenshot_Allow || mCliOutputMode.show_extended_info)
if (mNacp.getScreenshot() != nn::hac::nacp::Screenshot::Allow || mCliOutputMode.show_extended_info)
{
fmt::print(" Screenshot: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getScreenshotAsString(mNacp.getScreenshot()));
fmt::print(" Screenshot: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getScreenshotAsString(mNacp.getScreenshot()));
}
// VideoCapture
if (mNacp.getVideoCapture() != pie::hac::nacp::VideoCapture_Disable || mCliOutputMode.show_extended_info)
if (mNacp.getVideoCapture() != nn::hac::nacp::VideoCapture::Disable || mCliOutputMode.show_extended_info)
{
fmt::print(" VideoCapture: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getVideoCaptureAsString(mNacp.getVideoCapture()));
fmt::print(" VideoCapture: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getVideoCaptureAsString(mNacp.getVideoCapture()));
}
// DataLossConfirmation
if (mNacp.getDataLossConfirmation() != pie::hac::nacp::DataLossConfirmation_None || mCliOutputMode.show_extended_info)
if (mNacp.getDataLossConfirmation() != nn::hac::nacp::DataLossConfirmation::None || mCliOutputMode.show_extended_info)
{
fmt::print(" DataLossConfirmation: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getDataLossConfirmationAsString(mNacp.getDataLossConfirmation()));
fmt::print(" DataLossConfirmation: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getDataLossConfirmationAsString(mNacp.getDataLossConfirmation()));
}
// PlayLogPolicy
if (mNacp.getPlayLogPolicy() != pie::hac::nacp::PlayLogPolicy_All || mCliOutputMode.show_extended_info)
if (mNacp.getPlayLogPolicy() != nn::hac::nacp::PlayLogPolicy::All || mCliOutputMode.show_extended_info)
{
fmt::print(" PlayLogPolicy: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getPlayLogPolicyAsString(mNacp.getPlayLogPolicy()));
fmt::print(" PlayLogPolicy: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getPlayLogPolicyAsString(mNacp.getPlayLogPolicy()));
}
// PresenceGroupId
@ -191,7 +191,7 @@ void nstool::NacpProcess::displayNacp()
for (auto itr = mNacp.getRatingAge().begin(); itr != mNacp.getRatingAge().end(); itr++)
{
fmt::print(" {:s}:\n", pie::hac::ApplicationControlPropertyUtil::getOrganisationAsString(itr->organisation));
fmt::print(" {:s}:\n", nn::hac::ApplicationControlPropertyUtil::getOrganisationAsString(itr->organisation));
fmt::print(" Age: {:d}\n", itr->age);
}
}
@ -225,31 +225,31 @@ void nstool::NacpProcess::displayNacp()
// UserAccountSaveDataSize
if (mNacp.getUserAccountSaveDataSize().size != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" UserAccountSaveDataSize: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataSize().size));
fmt::print(" UserAccountSaveDataSize: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataSize().size));
}
// UserAccountSaveDataJournalSize
if (mNacp.getUserAccountSaveDataSize().journal_size != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" UserAccountSaveDataJournalSize: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataSize().journal_size));
fmt::print(" UserAccountSaveDataJournalSize: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataSize().journal_size));
}
// DeviceSaveDataSize
if (mNacp.getDeviceSaveDataSize().size != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" DeviceSaveDataSize: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataSize().size));
fmt::print(" DeviceSaveDataSize: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataSize().size));
}
// DeviceSaveDataJournalSize
if (mNacp.getDeviceSaveDataSize().journal_size != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" DeviceSaveDataJournalSize: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataSize().journal_size));
fmt::print(" DeviceSaveDataJournalSize: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataSize().journal_size));
}
// BcatDeliveryCacheStorageSize
if (mNacp.getBcatDeliveryCacheStorageSize() != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" BcatDeliveryCacheStorageSize: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getBcatDeliveryCacheStorageSize()));
fmt::print(" BcatDeliveryCacheStorageSize: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getBcatDeliveryCacheStorageSize()));
}
// ApplicationErrorCodeCategory
@ -277,39 +277,39 @@ void nstool::NacpProcess::displayNacp()
}
// LogoType
//if (mNacp.getLogoType() != pie::hac::nacp::LogoType_Nintendo || mCliOutputMode.show_extended_info)
//if (mNacp.getLogoType() != nn::hac::nacp::LogoType::Nintendo || mCliOutputMode.show_extended_info)
//{
fmt::print(" LogoType: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getLogoTypeAsString(mNacp.getLogoType()));
fmt::print(" LogoType: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getLogoTypeAsString(mNacp.getLogoType()));
//}
// LogoHandling
if (mNacp.getLogoHandling() != pie::hac::nacp::LogoHandling_Auto || mCliOutputMode.show_extended_info)
if (mNacp.getLogoHandling() != nn::hac::nacp::LogoHandling::Auto || mCliOutputMode.show_extended_info)
{
fmt::print(" LogoHandling: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getLogoHandlingAsString(mNacp.getLogoHandling()));
fmt::print(" LogoHandling: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getLogoHandlingAsString(mNacp.getLogoHandling()));
}
// RuntimeAddOnContentInstall
if (mNacp.getRuntimeAddOnContentInstall() != pie::hac::nacp::RuntimeAddOnContentInstall_Deny || mCliOutputMode.show_extended_info)
if (mNacp.getRuntimeAddOnContentInstall() != nn::hac::nacp::RuntimeAddOnContentInstall::Deny || mCliOutputMode.show_extended_info)
{
fmt::print(" RuntimeAddOnContentInstall: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getRuntimeAddOnContentInstallAsString(mNacp.getRuntimeAddOnContentInstall()));
fmt::print(" RuntimeAddOnContentInstall: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getRuntimeAddOnContentInstallAsString(mNacp.getRuntimeAddOnContentInstall()));
}
// RuntimeParameterDelivery
if (mNacp.getRuntimeParameterDelivery() != pie::hac::nacp::RuntimeParameterDelivery_Always || mCliOutputMode.show_extended_info)
if (mNacp.getRuntimeParameterDelivery() != nn::hac::nacp::RuntimeParameterDelivery::Always || mCliOutputMode.show_extended_info)
{
fmt::print(" RuntimeParameterDelivery: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getRuntimeParameterDeliveryAsString(mNacp.getRuntimeParameterDelivery()));
fmt::print(" RuntimeParameterDelivery: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getRuntimeParameterDeliveryAsString(mNacp.getRuntimeParameterDelivery()));
}
// CrashReport
if (mNacp.getCrashReport() != pie::hac::nacp::CrashReport_Deny || mCliOutputMode.show_extended_info)
if (mNacp.getCrashReport() != nn::hac::nacp::CrashReport::Deny || mCliOutputMode.show_extended_info)
{
fmt::print(" CrashReport: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getCrashReportAsString(mNacp.getCrashReport()));
fmt::print(" CrashReport: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getCrashReportAsString(mNacp.getCrashReport()));
}
// Hdcp
if (mNacp.getHdcp() != pie::hac::nacp::Hdcp_None || mCliOutputMode.show_extended_info)
if (mNacp.getHdcp() != nn::hac::nacp::Hdcp::None || mCliOutputMode.show_extended_info)
{
fmt::print(" Hdcp: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getHdcpAsString(mNacp.getHdcp()));
fmt::print(" Hdcp: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getHdcpAsString(mNacp.getHdcp()));
}
// SeedForPsuedoDeviceId
@ -334,7 +334,7 @@ void nstool::NacpProcess::displayNacp()
fmt::print(" StartupUserAccountOption:\n");
for (auto itr = mNacp.getStartupUserAccountOption().begin(); itr != mNacp.getStartupUserAccountOption().end(); itr++)
{
fmt::print(" {:s}\n", pie::hac::ApplicationControlPropertyUtil::getStartupUserAccountOptionFlagAsString(*itr));
fmt::print(" {:s}\n", nn::hac::ApplicationControlPropertyUtil::getStartupUserAccountOptionFlagAsString(*itr));
}
}
else if (mCliOutputMode.show_extended_info)
@ -345,49 +345,49 @@ void nstool::NacpProcess::displayNacp()
// UserAccountSaveDataSizeMax
if (mNacp.getUserAccountSaveDataMax().size != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" UserAccountSaveDataSizeMax: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataMax().size));
fmt::print(" UserAccountSaveDataSizeMax: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataMax().size));
}
// UserAccountSaveDataJournalSizeMax
if (mNacp.getUserAccountSaveDataMax().journal_size != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" UserAccountSaveDataJournalSizeMax: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataMax().journal_size));
fmt::print(" UserAccountSaveDataJournalSizeMax: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataMax().journal_size));
}
// DeviceSaveDataSizeMax
if (mNacp.getDeviceSaveDataMax().size != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" DeviceSaveDataSizeMax: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataMax().size));
fmt::print(" DeviceSaveDataSizeMax: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataMax().size));
}
// DeviceSaveDataJournalSizeMax
if (mNacp.getDeviceSaveDataMax().journal_size != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" DeviceSaveDataJournalSizeMax: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataMax().journal_size));
fmt::print(" DeviceSaveDataJournalSizeMax: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataMax().journal_size));
}
// TemporaryStorageSize
if (mNacp.getTemporaryStorageSize() != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" TemporaryStorageSize: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getTemporaryStorageSize()));
fmt::print(" TemporaryStorageSize: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getTemporaryStorageSize()));
}
// CacheStorageSize
if (mNacp.getCacheStorageSize().size != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" CacheStorageSize: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageSize().size));
fmt::print(" CacheStorageSize: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageSize().size));
}
// CacheStorageJournalSize
if (mNacp.getCacheStorageSize().journal_size != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" CacheStorageJournalSize: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageSize().journal_size));
fmt::print(" CacheStorageJournalSize: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageSize().journal_size));
}
// CacheStorageDataAndJournalSizeMax
if (mNacp.getCacheStorageDataAndJournalSizeMax() != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" CacheStorageDataAndJournalSizeMax: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageDataAndJournalSizeMax()));
fmt::print(" CacheStorageDataAndJournalSizeMax: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageDataAndJournalSizeMax()));
}
// CacheStorageIndexMax
@ -411,9 +411,9 @@ void nstool::NacpProcess::displayNacp()
}
// PlayLogQueryCapability
if (mNacp.getPlayLogQueryCapability() != pie::hac::nacp::PlayLogQueryCapability_None || mCliOutputMode.show_extended_info)
if (mNacp.getPlayLogQueryCapability() != nn::hac::nacp::PlayLogQueryCapability::None || mCliOutputMode.show_extended_info)
{
fmt::print(" PlayLogQueryCapability: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getPlayLogQueryCapabilityAsString(mNacp.getPlayLogQueryCapability()));
fmt::print(" PlayLogQueryCapability: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getPlayLogQueryCapabilityAsString(mNacp.getPlayLogQueryCapability()));
}
// Repair
@ -422,7 +422,7 @@ void nstool::NacpProcess::displayNacp()
fmt::print(" Repair:\n");
for (auto itr = mNacp.getRepair().begin(); itr != mNacp.getRepair().end(); itr++)
{
fmt::print(" {:s}\n", pie::hac::ApplicationControlPropertyUtil::getRepairFlagAsString(*itr));
fmt::print(" {:s}\n", nn::hac::ApplicationControlPropertyUtil::getRepairFlagAsString(*itr));
}
}
else if (mCliOutputMode.show_extended_info)
@ -442,7 +442,7 @@ void nstool::NacpProcess::displayNacp()
fmt::print(" RequiredNetworkServiceLicenseOnLaunch:\n");
for (auto itr = mNacp.getRequiredNetworkServiceLicenseOnLaunch().begin(); itr != mNacp.getRequiredNetworkServiceLicenseOnLaunch().end(); itr++)
{
fmt::print(" {:s}\n", pie::hac::ApplicationControlPropertyUtil::getRequiredNetworkServiceLicenseOnLaunchFlagAsString(*itr));
fmt::print(" {:s}\n", nn::hac::ApplicationControlPropertyUtil::getRequiredNetworkServiceLicenseOnLaunchFlagAsString(*itr));
}
}
else if (mCliOutputMode.show_extended_info)
@ -468,7 +468,7 @@ void nstool::NacpProcess::displayNacp()
if (detect_config.countReceivableGroupConfig() > 0)
{
fmt::print(" ReceivableGroupConfig:\n");
for (size_t i = 0; i < pie::hac::nacp::kReceivableGroupConfigurationCount; i++)
for (size_t i = 0; i < nn::hac::nacp::kReceivableGroupConfigurationCount; i++)
{
if (detect_config.receivable_data_configuration[i].isNull())
continue;
@ -496,21 +496,21 @@ void nstool::NacpProcess::displayNacp()
}
// PlayReportPermission
if (mNacp.getPlayReportPermission() != pie::hac::nacp::PlayReportPermission_None || mCliOutputMode.show_extended_info)
if (mNacp.getPlayReportPermission() != nn::hac::nacp::PlayReportPermission::None || mCliOutputMode.show_extended_info)
{
fmt::print(" PlayReportPermission: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getPlayReportPermissionAsString(mNacp.getPlayReportPermission()));
fmt::print(" PlayReportPermission: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getPlayReportPermissionAsString(mNacp.getPlayReportPermission()));
}
// CrashScreenshotForProd
if (mNacp.getCrashScreenshotForProd() != pie::hac::nacp::CrashScreenshotForProd_Deny || mCliOutputMode.show_extended_info)
if (mNacp.getCrashScreenshotForProd() != nn::hac::nacp::CrashScreenshotForProd::Deny || mCliOutputMode.show_extended_info)
{
fmt::print(" CrashScreenshotForProd: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getCrashScreenshotForProdAsString(mNacp.getCrashScreenshotForProd()));
fmt::print(" CrashScreenshotForProd: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getCrashScreenshotForProdAsString(mNacp.getCrashScreenshotForProd()));
}
// CrashScreenshotForDev
if (mNacp.getCrashScreenshotForDev() != pie::hac::nacp::CrashScreenshotForDev_Deny || mCliOutputMode.show_extended_info)
if (mNacp.getCrashScreenshotForDev() != nn::hac::nacp::CrashScreenshotForDev::Deny || mCliOutputMode.show_extended_info)
{
fmt::print(" CrashScreenshotForDev: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getCrashScreenshotForDevAsString(mNacp.getCrashScreenshotForDev()));
fmt::print(" CrashScreenshotForDev: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getCrashScreenshotForDevAsString(mNacp.getCrashScreenshotForDev()));
}
// AccessibleLaunchRequiredVersion

View file

@ -1,7 +1,7 @@
#pragma once
#include "types.h"
#include <pietendo/hac/ApplicationControlProperty.h>
#include <nn/hac/ApplicationControlProperty.h>
namespace nstool {
@ -16,7 +16,7 @@ public:
void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify);
const pie::hac::ApplicationControlProperty& getApplicationControlProperty() const;
const nn::hac::ApplicationControlProperty& getApplicationControlProperty() const;
private:
std::string mModuleName;
@ -25,7 +25,7 @@ private:
CliOutputMode mCliOutputMode;
bool mVerify;
pie::hac::ApplicationControlProperty mNacp;
nn::hac::ApplicationControlProperty mNacp;
void importNacp();
void displayNacp();

View file

@ -2,14 +2,15 @@
#include "MetaProcess.h"
#include "util.h"
#include <pietendo/hac/ContentArchiveUtil.h>
#include <pietendo/hac/AesKeygen.h>
#include <pietendo/hac/HierarchicalSha256Stream.h>
#include <pietendo/hac/HierarchicalIntegrityStream.h>
#include <pietendo/hac/BKTREncryptedStream.h>
#include <pietendo/hac/PartitionFsSnapshotGenerator.h>
#include <pietendo/hac/RomFsSnapshotGenerator.h>
#include <pietendo/hac/CombinedFsSnapshotGenerator.h>
#include <tc/crypto/detail/BlockUtilImpl.h>
#include <nn/hac/ContentArchiveUtil.h>
#include <nn/hac/AesKeygen.h>
#include <nn/hac/HierarchicalSha256Stream.h>
#include <nn/hac/HierarchicalIntegrityStream.h>
#include <nn/hac/PartitionFsMetaGenerator.h>
#include <nn/hac/RomFsMetaGenerator.h>
#include <nn/hac/CombinedFsMetaGenerator.h>
nstool::NcaProcess::NcaProcess() :
mModuleName("nstool::NcaProcess"),
@ -49,11 +50,6 @@ void nstool::NcaProcess::setInputFile(const std::shared_ptr<tc::io::IStream>& fi
mFile = file;
}
void nstool::NcaProcess::setBaseNcaPath(const tc::Optional<tc::io::Path>& nca_path)
{
mBaseNcaPath = nca_path;
}
void nstool::NcaProcess::setKeyCfg(const KeyBag& keycfg)
{
mKeyCfg = keycfg;
@ -84,7 +80,7 @@ void nstool::NcaProcess::setExtractJobs(const std::vector<nstool::ExtractJob>& e
mFsProcess.setExtractJobs(extract_jobs);
}
const std::shared_ptr<tc::io::IFileSystem>& nstool::NcaProcess::getFileSystem() const
const std::shared_ptr<tc::io::IStorage>& nstool::NcaProcess::getFileSystem() const
{
return mFileSystem;
}
@ -101,25 +97,25 @@ void nstool::NcaProcess::importHeader()
}
// read header block
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(sizeof(pie::hac::sContentArchiveHeaderBlock)))
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(sizeof(nn::hac::sContentArchiveHeaderBlock)))
{
throw tc::Exception(mModuleName, "Corrupt NCA: File too small.");
}
mFile->seek(0, tc::io::SeekOrigin::Begin);
mFile->read((byte_t*)(&mHdrBlock), sizeof(pie::hac::sContentArchiveHeaderBlock));
mFile->read((byte_t*)(&mHdrBlock), sizeof(nn::hac::sContentArchiveHeaderBlock));
// decrypt header block
if (mKeyCfg.nca_header_key.isNull())
{
throw tc::Exception(mModuleName, "Failed to decrypt NCA header. (nca_header_key could not be loaded)");
}
pie::hac::ContentArchiveUtil::decryptContentArchiveHeader((byte_t*)&mHdrBlock, (byte_t*)&mHdrBlock, mKeyCfg.nca_header_key.get());
nn::hac::ContentArchiveUtil::decryptContentArchiveHeader((byte_t*)&mHdrBlock, (byte_t*)&mHdrBlock, mKeyCfg.nca_header_key.get());
// generate header hash
tc::crypto::GenerateSha2256Hash(mHdrHash.data(), (byte_t*)&mHdrBlock.header, sizeof(pie::hac::sContentArchiveHeader));
tc::crypto::GenerateSha256Hash(mHdrHash.data(), (byte_t*)&mHdrBlock.header, sizeof(nn::hac::sContentArchiveHeader));
// proccess main header
mHdr.fromBytes((byte_t*)&mHdrBlock.header, sizeof(pie::hac::sContentArchiveHeader));
mHdr.fromBytes((byte_t*)&mHdrBlock.header, sizeof(nn::hac::sContentArchiveHeader));
}
void nstool::NcaProcess::generateNcaBodyEncryptionKeys()
@ -129,7 +125,7 @@ void nstool::NcaProcess::generateNcaBodyEncryptionKeys()
memset(zero_aesctr_key.data(), 0, zero_aesctr_key.size());
// get key data from header
byte_t masterkey_rev = pie::hac::AesKeygen::getMasterKeyRevisionFromKeyGeneration(mHdr.getKeyGeneration());
byte_t masterkey_rev = nn::hac::AesKeygen::getMasterKeyRevisionFromKeyGeneration(mHdr.getKeyGeneration());
byte_t keak_index = mHdr.getKeyAreaEncryptionKeyIndex();
// process key area
@ -145,13 +141,13 @@ void nstool::NcaProcess::generateNcaBodyEncryptionKeys()
if (i < 4 && mKeyCfg.nca_key_area_encryption_key[keak_index].find(masterkey_rev) != mKeyCfg.nca_key_area_encryption_key[keak_index].end())
{
kak.decrypted = true;
pie::hac::AesKeygen::generateKey(kak.dec.data(), kak.enc.data(), mKeyCfg.nca_key_area_encryption_key[keak_index][masterkey_rev].data());
nn::hac::AesKeygen::generateKey(kak.dec.data(), kak.enc.data(), mKeyCfg.nca_key_area_encryption_key[keak_index][masterkey_rev].data());
}
// key[KeyBankIndex_AesCtrHw]
else if (i == pie::hac::nca::KeyBankIndex_AesCtrHw && mKeyCfg.nca_key_area_encryption_key_hw[keak_index].find(masterkey_rev) != mKeyCfg.nca_key_area_encryption_key_hw[keak_index].end())
// key[KEY_AESCTR_HW]
else if (i == nn::hac::nca::KEY_AESCTR_HW && mKeyCfg.nca_key_area_encryption_key_hw[keak_index].find(masterkey_rev) != mKeyCfg.nca_key_area_encryption_key_hw[keak_index].end())
{
kak.decrypted = true;
pie::hac::AesKeygen::generateKey(kak.dec.data(), kak.enc.data(), mKeyCfg.nca_key_area_encryption_key_hw[keak_index][masterkey_rev].data());
nn::hac::AesKeygen::generateKey(kak.dec.data(), kak.enc.data(), mKeyCfg.nca_key_area_encryption_key_hw[keak_index][masterkey_rev].data());
}
else
{
@ -162,7 +158,7 @@ void nstool::NcaProcess::generateNcaBodyEncryptionKeys()
}
// clear content key
mContentKey.aes_ctr = tc::Optional<pie::hac::detail::aes128_key_t>();
mContentKey.aes_ctr = tc::Optional<nn::hac::detail::aes128_key_t>();
// if this has a rights id, the key needs to be sourced from a ticket
if (mHdr.hasRightsId() == true)
@ -176,21 +172,12 @@ void nstool::NcaProcess::generateNcaBodyEncryptionKeys()
{
mContentKey.aes_ctr = mKeyCfg.fallback_content_key.get();
}
else if (mKeyCfg.external_enc_content_keys.find(mHdr.getRightsId()) != mKeyCfg.external_enc_content_keys.end())
{
tmp_key = mKeyCfg.external_enc_content_keys[mHdr.getRightsId()];
if (mKeyCfg.etik_common_key.find(masterkey_rev) != mKeyCfg.etik_common_key.end())
{
pie::hac::AesKeygen::generateKey(tmp_key.data(), tmp_key.data(), mKeyCfg.etik_common_key[masterkey_rev].data());
mContentKey.aes_ctr = tmp_key;
}
}
else if (mKeyCfg.fallback_enc_content_key.isSet())
{
tmp_key = mKeyCfg.fallback_enc_content_key.get();
if (mKeyCfg.etik_common_key.find(masterkey_rev) != mKeyCfg.etik_common_key.end())
{
pie::hac::AesKeygen::generateKey(tmp_key.data(), tmp_key.data(), mKeyCfg.etik_common_key[masterkey_rev].data());
nn::hac::AesKeygen::generateKey(tmp_key.data(), tmp_key.data(), mKeyCfg.etik_common_key[masterkey_rev].data());
mContentKey.aes_ctr = tmp_key;
}
}
@ -200,7 +187,7 @@ void nstool::NcaProcess::generateNcaBodyEncryptionKeys()
{
for (size_t i = 0; i < mContentKey.kak_list.size(); i++)
{
if (mContentKey.kak_list[i].index == pie::hac::nca::KeyBankIndex_AesCtr && mContentKey.kak_list[i].decrypted)
if (mContentKey.kak_list[i].index == nn::hac::nca::KEY_AESCTR && mContentKey.kak_list[i].decrypted)
{
mContentKey.aes_ctr = mContentKey.kak_list[i].dec;
}
@ -226,72 +213,44 @@ void nstool::NcaProcess::generateNcaBodyEncryptionKeys()
}
}
nstool::NcaProcess nstool::NcaProcess::readBaseNCA()
{
// open base nca stream
if (mBaseNcaPath.isNull())
{
throw tc::Exception(mModuleName, "Base NCA not supplied. Necessary for update NCA.");
}
std::shared_ptr<tc::io::IStream> base_stream = std::make_shared<tc::io::FileStream>(tc::io::FileStream(mBaseNcaPath.get(), tc::io::FileMode::Open, tc::io::FileAccess::Read));
// process base nca with output suppressed
NcaProcess obj;
nstool::CliOutputMode cliOutput;
cliOutput.show_basic_info = false;
cliOutput.show_extended_info = false;
cliOutput.show_keydata = false;
cliOutput.show_layout = false;
obj.setCliOutputMode(cliOutput);
obj.setVerifyMode(true);
obj.setKeyCfg(mKeyCfg);
obj.setInputFile(base_stream);
obj.process();
// return processed base nca
return obj;
}
void nstool::NcaProcess::generatePartitionConfiguration()
{
for (size_t i = 0; i < mHdr.getPartitionEntryList().size(); i++)
{
// get reference to relevant structures
const pie::hac::ContentArchiveHeader::sPartitionEntry& partition = mHdr.getPartitionEntryList()[i];
pie::hac::sContentArchiveFsHeader& fs_header = mHdrBlock.fs_header[partition.header_index];
const nn::hac::ContentArchiveHeader::sPartitionEntry& partition = mHdr.getPartitionEntryList()[i];
nn::hac::sContentArchiveFsHeader& fs_header = mHdrBlock.fs_header[partition.header_index];
// output structure
sPartitionInfo& info = mPartitions[partition.header_index];
// validate header hash
pie::hac::detail::sha256_hash_t fs_header_hash;
tc::crypto::GenerateSha2256Hash(fs_header_hash.data(), (const byte_t*)&mHdrBlock.fs_header[partition.header_index], sizeof(pie::hac::sContentArchiveFsHeader));
nn::hac::detail::sha256_hash_t fs_header_hash;
tc::crypto::GenerateSha256Hash(fs_header_hash.data(), (const byte_t*)&mHdrBlock.fs_header[partition.header_index], sizeof(nn::hac::sContentArchiveFsHeader));
if (fs_header_hash != partition.fs_header_hash)
{
throw tc::Exception(mModuleName, fmt::format("NCA FS Header [{:d}] Hash: FAIL", partition.header_index));
}
if (fs_header.version.unwrap() != pie::hac::nca::kDefaultFsHeaderVersion)
if (fs_header.version.unwrap() != nn::hac::nca::kDefaultFsHeaderVersion)
{
throw tc::Exception(mModuleName, fmt::format("NCA FS Header [{:d}] Version({:d}): UNSUPPORTED", partition.header_index, fs_header.version.unwrap()));
}
// setup AES-CTR
pie::hac::ContentArchiveUtil::getNcaPartitionAesCtr(&fs_header, info.aes_ctr.data());
nn::hac::ContentArchiveUtil::getNcaPartitionAesCtr(&fs_header, info.aes_ctr.data());
// save partition configinfo
info.offset = partition.offset;
info.size = partition.size;
info.format_type = (pie::hac::nca::FormatType)fs_header.format_type;
info.hash_type = (pie::hac::nca::HashType)fs_header.hash_type;
info.enc_type = (pie::hac::nca::EncryptionType)fs_header.encryption_type;
info.metadata_hash_type = (pie::hac::nca::MetaDataHashType)fs_header.meta_data_hash_type;
if (info.hash_type == pie::hac::nca::HashType_HierarchicalSha256)
info.format_type = (nn::hac::nca::FormatType)fs_header.format_type;
info.hash_type = (nn::hac::nca::HashType)fs_header.hash_type;
info.enc_type = (nn::hac::nca::EncryptionType)fs_header.encryption_type;
if (info.hash_type == nn::hac::nca::HashType::HierarchicalSha256)
{
info.hierarchicalsha256_hdr.fromBytes(fs_header.hash_info.data(), fs_header.hash_info.size());
}
else if (info.hash_type == pie::hac::nca::HashType_HierarchicalIntegrity)
else if (info.hash_type == nn::hac::nca::HashType::HierarchicalIntegrity)
{
info.hierarchicalintegrity_hdr.fromBytes(fs_header.hash_info.data(), fs_header.hash_info.size());
}
@ -307,106 +266,68 @@ void nstool::NcaProcess::generatePartitionConfiguration()
else
{
// create raw partition
info.raw_reader = std::make_shared<tc::io::SubStream>(tc::io::SubStream(mFile, info.offset, info.size));
info.reader = std::make_shared<tc::io::SubStream>(tc::io::SubStream(mFile, info.offset, info.size));
// handle encryption if required reader based on encryption type
if (info.enc_type == pie::hac::nca::EncryptionType_None)
if (info.enc_type == nn::hac::nca::EncryptionType::None)
{
// no encryption so do nothing
info.decrypt_reader = info.raw_reader;
//info.reader = info.reader;
}
else if (info.enc_type == pie::hac::nca::EncryptionType_AesCtr)
else if (info.enc_type == nn::hac::nca::EncryptionType::AesCtr)
{
if (mContentKey.aes_ctr.isNull())
throw tc::Exception(mModuleName, "AES-CTR Key was not determined");
// get partition key
pie::hac::detail::aes128_key_t partition_key = mContentKey.aes_ctr.get();
nn::hac::detail::aes128_key_t partition_key = mContentKey.aes_ctr.get();
// get partition counter
pie::hac::detail::aes_iv_t partition_ctr = info.aes_ctr;
tc::crypto::IncrementCounterAes128Ctr(partition_ctr.data(), info.offset >> 4);
nn::hac::detail::aes_iv_t partition_ctr = info.aes_ctr;
tc::crypto::detail::incr_counter<16>(partition_ctr.data(), info.offset>>4);
// create decryption stream
info.decrypt_reader = std::make_shared<tc::crypto::Aes128CtrEncryptedStream>(tc::crypto::Aes128CtrEncryptedStream(info.raw_reader, partition_key, partition_ctr));
info.reader = std::make_shared<tc::crypto::Aes128CtrEncryptedStream>(tc::crypto::Aes128CtrEncryptedStream(info.reader, partition_key, partition_ctr));
}
else if (info.enc_type == pie::hac::nca::EncryptionType_AesCtrEx)
else if (info.enc_type == nn::hac::nca::EncryptionType::AesXts || info.enc_type == nn::hac::nca::EncryptionType::AesCtrEx)
{
if (mContentKey.aes_ctr.isNull())
throw tc::Exception(mModuleName, "AES-CTR Key was not determined");
// get partition key
pie::hac::detail::aes128_key_t partition_key = mContentKey.aes_ctr.get();
// get partition counter
pie::hac::detail::aes_iv_t partition_ctr = info.aes_ctr;
tc::crypto::IncrementCounterAes128Ctr(partition_ctr.data(), info.offset >> 4);
// TODO see if AesCtrEx encryption can just be for creating the transparent decryption, with IndirectStorage IStream construction being done after decryption but before hash layer processing
// this might be relevant when processing compressed or sparse storage
NcaProcess nca_base = readBaseNCA();
if (nca_base.mHdr.getProgramId() != mHdr.getProgramId())
{
throw tc::Exception(mModuleName, "Invalid base nca. ProgramID diferent.");
}
std::shared_ptr<tc::io::IStream> base_reader;
for (auto& partition_base : nca_base.mPartitions)
{
if (partition_base.format_type == pie::hac::nca::FormatType::FormatType_RomFs && partition_base.raw_reader != nullptr)
{
base_reader = partition_base.decrypt_reader;
}
}
if (base_reader == nullptr)
{
throw tc::Exception(mModuleName, "Cannot determine RomFs from base nca.");
}
// create decryption stream
info.decrypt_reader = std::make_shared<pie::hac::BKTREncryptedStream>(pie::hac::BKTREncryptedStream(info.raw_reader, partition_key, partition_ctr, fs_header.patch_info, base_reader));
}
else if (info.enc_type == pie::hac::nca::EncryptionType_AesXts)
{
throw tc::Exception(mModuleName, fmt::format("EncryptionType({:s}): UNSUPPORTED", pie::hac::ContentArchiveUtil::getEncryptionTypeAsString(info.enc_type)));
throw tc::Exception(mModuleName, fmt::format("EncryptionType({:s}): UNSUPPORTED", nn::hac::ContentArchiveUtil::getEncryptionTypeAsString(info.enc_type)));
}
else
{
throw tc::Exception(mModuleName, fmt::format("EncryptionType({:s}): UNKNOWN", pie::hac::ContentArchiveUtil::getEncryptionTypeAsString(info.enc_type)));
throw tc::Exception(mModuleName, fmt::format("EncryptionType({:s}): UNKNOWN", nn::hac::ContentArchiveUtil::getEncryptionTypeAsString(info.enc_type)));
}
}
// filter out unrecognised hash types, and hash based readers
switch (info.hash_type)
{
case (pie::hac::nca::HashType_None):
// no hash layer, do nothing
info.reader = info.decrypt_reader;
case (nn::hac::nca::HashType::None):
break;
case (pie::hac::nca::HashType_HierarchicalSha256):
info.reader = std::make_shared<pie::hac::HierarchicalSha256Stream>(pie::hac::HierarchicalSha256Stream(info.decrypt_reader, info.hierarchicalsha256_hdr));
case (nn::hac::nca::HashType::HierarchicalSha256):
info.reader = std::make_shared<nn::hac::HierarchicalSha256Stream>(nn::hac::HierarchicalSha256Stream(info.reader, info.hierarchicalsha256_hdr));
break;
case (pie::hac::nca::HashType_HierarchicalIntegrity):
info.reader = std::make_shared<pie::hac::HierarchicalIntegrityStream>(pie::hac::HierarchicalIntegrityStream(info.decrypt_reader, info.hierarchicalintegrity_hdr));
case (nn::hac::nca::HashType::HierarchicalIntegrity):
info.reader = std::make_shared<nn::hac::HierarchicalIntegrityStream>(nn::hac::HierarchicalIntegrityStream(info.reader, info.hierarchicalintegrity_hdr));
break;
default:
throw tc::Exception(mModuleName, fmt::format("HashType({:s}): UNKNOWN", pie::hac::ContentArchiveUtil::getHashTypeAsString(info.hash_type)));
throw tc::Exception(mModuleName, fmt::format("HashType({:s}): UNKNOWN", nn::hac::ContentArchiveUtil::getHashTypeAsString(info.hash_type)));
}
// filter out unrecognised format types
switch (info.format_type)
{
case (pie::hac::nca::FormatType_PartitionFs):
info.fs_snapshot = pie::hac::PartitionFsSnapshotGenerator(info.reader);
info.fs_reader = std::make_shared<tc::io::VirtualFileSystem>(tc::io::VirtualFileSystem(info.fs_snapshot));
case (nn::hac::nca::FormatType::PartitionFs):
info.fs_meta = nn::hac::PartitionFsMetaGenerator(info.reader);
info.fs_reader = std::make_shared<tc::io::VirtualFileSystem>(tc::io::VirtualFileSystem(info.fs_meta));
break;
case (pie::hac::nca::FormatType_RomFs):
info.fs_snapshot = pie::hac::RomFsSnapshotGenerator(info.reader);
info.fs_reader = std::make_shared<tc::io::VirtualFileSystem>(tc::io::VirtualFileSystem(info.fs_snapshot));
case (nn::hac::nca::FormatType::RomFs):
info.fs_meta = nn::hac::RomFsMetaGenerator(info.reader);
info.fs_reader = std::make_shared<tc::io::VirtualFileSystem>(tc::io::VirtualFileSystem(info.fs_meta));
break;
default:
throw tc::Exception(mModuleName, fmt::format("FormatType({:s}): UNKNOWN", pie::hac::ContentArchiveUtil::getFormatTypeAsString(info.format_type)));
throw tc::Exception(mModuleName, fmt::format("FormatType({:s}): UNKNOWN", nn::hac::ContentArchiveUtil::getFormatTypeAsString(info.format_type)));
}
}
catch (const tc::Exception& e)
@ -421,7 +342,7 @@ void nstool::NcaProcess::validateNcaSignatures()
// validate signature[0]
if (mKeyCfg.nca_header_sign0_key.find(mHdr.getSignatureKeyGeneration()) != mKeyCfg.nca_header_sign0_key.end())
{
if (tc::crypto::VerifyRsa2048PssSha2256(mHdrBlock.signature_main.data(), mHdrHash.data(), mKeyCfg.nca_header_sign0_key[mHdr.getSignatureKeyGeneration()]) == false)
if (tc::crypto::VerifyRsa2048PssSha256(mHdrBlock.signature_main.data(), mHdrHash.data(), mKeyCfg.nca_header_sign0_key[mHdr.getSignatureKeyGeneration()]) == false)
{
fmt::print("[WARNING] NCA Header Main Signature: FAIL\n");
}
@ -433,16 +354,16 @@ void nstool::NcaProcess::validateNcaSignatures()
// validate signature[1]
if (mHdr.getContentType() == pie::hac::nca::ContentType_Program)
if (mHdr.getContentType() == nn::hac::nca::ContentType::Program)
{
try {
if (mPartitions[pie::hac::nca::ProgramContentPartitionIndex_Code].format_type == pie::hac::nca::FormatType_PartitionFs)
if (mPartitions[nn::hac::nca::PARTITION_CODE].format_type == nn::hac::nca::FormatType::PartitionFs)
{
if (mPartitions[pie::hac::nca::ProgramContentPartitionIndex_Code].fs_reader != nullptr)
if (mPartitions[nn::hac::nca::PARTITION_CODE].fs_reader != nullptr)
{
std::shared_ptr<tc::io::IStream> npdm_file;
try {
mPartitions[pie::hac::nca::ProgramContentPartitionIndex_Code].fs_reader->openFile(tc::io::Path(kNpdmExefsPath), tc::io::FileMode::Open, tc::io::FileAccess::Read, npdm_file);
mPartitions[nn::hac::nca::PARTITION_CODE].fs_reader->openFile(tc::io::Path(kNpdmExefsPath), tc::io::FileMode::Open, tc::io::FileAccess::Read, npdm_file);
}
catch (tc::io::FileNotFoundException&) {
throw tc::Exception(fmt::format("\"{:s}\" not present in ExeFs", kNpdmExefsPath));
@ -455,7 +376,7 @@ void nstool::NcaProcess::validateNcaSignatures()
npdm.setCliOutputMode(CliOutputMode(false, false, false, false));
npdm.process();
if (tc::crypto::VerifyRsa2048PssSha2256(mHdrBlock.signature_acid.data(), mHdrHash.data(), npdm.getMeta().getAccessControlInfoDesc().getContentArchiveHeaderSignature2Key()) == false)
if (tc::crypto::VerifyRsa2048PssSha256(mHdrBlock.signature_acid.data(), mHdrHash.data(), npdm.getMeta().getAccessControlInfoDesc().getContentArchiveHeaderSignature2Key()) == false)
{
throw tc::Exception("Bad signature");
}
@ -479,16 +400,16 @@ void nstool::NcaProcess::validateNcaSignatures()
void nstool::NcaProcess::displayHeader()
{
fmt::print("[NCA Header]\n");
fmt::print(" Format Type: {:s}\n", pie::hac::ContentArchiveUtil::getFormatHeaderVersionAsString((pie::hac::nca::HeaderFormatVersion)mHdr.getFormatVersion()));
fmt::print(" Dist. Type: {:s}\n", pie::hac::ContentArchiveUtil::getDistributionTypeAsString(mHdr.getDistributionType()));
fmt::print(" Content Type: {:s}\n", pie::hac::ContentArchiveUtil::getContentTypeAsString(mHdr.getContentType()));
fmt::print(" Format Type: {:s}\n", nn::hac::ContentArchiveUtil::getFormatHeaderVersionAsString((nn::hac::nca::HeaderFormatVersion)mHdr.getFormatVersion()));
fmt::print(" Dist. Type: {:s}\n", nn::hac::ContentArchiveUtil::getDistributionTypeAsString(mHdr.getDistributionType()));
fmt::print(" Content Type: {:s}\n", nn::hac::ContentArchiveUtil::getContentTypeAsString(mHdr.getContentType()));
fmt::print(" Key Generation: {:d}\n", mHdr.getKeyGeneration());
fmt::print(" Sig. Generation: {:d}\n", mHdr.getSignatureKeyGeneration());
fmt::print(" Kaek Index: {:s} ({:d})\n", pie::hac::ContentArchiveUtil::getKeyAreaEncryptionKeyIndexAsString((pie::hac::nca::KeyAreaEncryptionKeyIndex)mHdr.getKeyAreaEncryptionKeyIndex()), mHdr.getKeyAreaEncryptionKeyIndex());
fmt::print(" Kaek Index: {:s} ({:d})\n", nn::hac::ContentArchiveUtil::getKeyAreaEncryptionKeyIndexAsString((nn::hac::nca::KeyAreaEncryptionKeyIndex)mHdr.getKeyAreaEncryptionKeyIndex()), mHdr.getKeyAreaEncryptionKeyIndex());
fmt::print(" Size: 0x{:x}\n", mHdr.getContentSize());
fmt::print(" ProgID: 0x{:016x}\n", mHdr.getProgramId());
fmt::print(" Content Index: {:d}\n", mHdr.getContentIndex());
fmt::print(" SdkAddon Ver.: {:s} (v{:d})\n", pie::hac::ContentArchiveUtil::getSdkAddonVersionAsString(mHdr.getSdkAddonVersion()), mHdr.getSdkAddonVersion());
fmt::print(" SdkAddon Ver.: {:s} (v{:d})\n", nn::hac::ContentArchiveUtil::getSdkAddonVersionAsString(mHdr.getSdkAddonVersion()), mHdr.getSdkAddonVersion());
if (mHdr.hasRightsId())
{
fmt::print(" RightsId: {:s}\n", tc::cli::FormatUtil::formatBytesAsString(mHdr.getRightsId().data(), mHdr.getRightsId().size(), true, ""));
@ -497,18 +418,22 @@ void nstool::NcaProcess::displayHeader()
if (mContentKey.kak_list.size() > 0 && mCliOutputMode.show_keydata)
{
fmt::print(" Key Area:\n");
fmt::print(" <--------------------------------------------------------------------------->\n");
fmt::print(" | IDX | ENCRYPTED KEY | DECRYPTED KEY |\n");
fmt::print(" |-----|----------------------------------|----------------------------------|\n");
fmt::print(" <--------------------------------------------------------------------------------------------------------->\n");
fmt::print(" | IDX | ENCRYPTED KEY | DECRYPTED KEY |\n");
fmt::print(" |-----|-------------------------------------------------|-------------------------------------------------|\n");
for (size_t i = 0; i < mContentKey.kak_list.size(); i++)
{
std::string enc_key = tc::cli::FormatUtil::formatBytesAsString(mContentKey.kak_list[i].enc.data(), mContentKey.kak_list[i].enc.size(), true, "");
std::string dec_key = mContentKey.kak_list[i].decrypted ? tc::cli::FormatUtil::formatBytesAsString(mContentKey.kak_list[i].dec.data(), mContentKey.kak_list[i].dec.size(), true, "") : "<unable to decrypt>";
fmt::print(" | {:3d} | {:s} | ", mContentKey.kak_list[i].index, tc::cli::FormatUtil::formatBytesAsString(mContentKey.kak_list[i].enc.data(), mContentKey.kak_list[i].enc.size(), true, ""));
fmt::print(" | {:3d} | {:32s} | {:32s} |\n", mContentKey.kak_list[i].index, enc_key, dec_key);
if (mContentKey.kak_list[i].decrypted)
fmt::print("{:s}", tc::cli::FormatUtil::formatBytesAsString(mContentKey.kak_list[i].dec.data(), mContentKey.kak_list[i].dec.size(), true, ""));
else
fmt::print("<unable to decrypt> ");
fmt::print(" |\n");
}
fmt::print(" <--------------------------------------------------------------------------->\n");
fmt::print(" <--------------------------------------------------------------------------------------------------------->\n");
}
if (mCliOutputMode.show_layout)
@ -523,18 +448,18 @@ void nstool::NcaProcess::displayHeader()
fmt::print(" {:d}:\n", index);
fmt::print(" Offset: 0x{:x}\n", info.offset);
fmt::print(" Size: 0x{:x}\n", info.size);
fmt::print(" Format Type: {:s}\n", pie::hac::ContentArchiveUtil::getFormatTypeAsString(info.format_type));
fmt::print(" Hash Type: {:s}\n", pie::hac::ContentArchiveUtil::getHashTypeAsString(info.hash_type));
fmt::print(" Enc. Type: {:s}\n", pie::hac::ContentArchiveUtil::getEncryptionTypeAsString(info.enc_type));
if (info.enc_type == pie::hac::nca::EncryptionType_AesCtr)
fmt::print(" Format Type: {:s}\n", nn::hac::ContentArchiveUtil::getFormatTypeAsString(info.format_type));
fmt::print(" Hash Type: {:s}\n", nn::hac::ContentArchiveUtil::getHashTypeAsString(info.hash_type));
fmt::print(" Enc. Type: {:s}\n", nn::hac::ContentArchiveUtil::getEncryptionTypeAsString(info.enc_type));
if (info.enc_type == nn::hac::nca::EncryptionType::AesCtr)
{
pie::hac::detail::aes_iv_t aes_ctr;
nn::hac::detail::aes_iv_t aes_ctr;
memcpy(aes_ctr.data(), info.aes_ctr.data(), aes_ctr.size());
tc::crypto::IncrementCounterAes128Ctr(aes_ctr.data(), info.offset>>4);
tc::crypto::detail::incr_counter<16>(aes_ctr.data(), info.offset>>4);
fmt::print(" AesCtr Counter:\n");
fmt::print(" {:s}\n", tc::cli::FormatUtil::formatBytesAsString(aes_ctr.data(), aes_ctr.size(), true, ""));
}
if (info.hash_type == pie::hac::nca::HashType_HierarchicalIntegrity)
if (info.hash_type == nn::hac::nca::HashType::HierarchicalIntegrity)
{
auto hash_hdr = info.hierarchicalintegrity_hdr;
fmt::print(" HierarchicalIntegrity Header:\n");
@ -559,7 +484,7 @@ void nstool::NcaProcess::displayHeader()
fmt::print(" {:s}\n", tc::cli::FormatUtil::formatBytesAsString(hash_hdr.getMasterHashList()[j].data()+0x10, 0x10, true, ""));
}
}
else if (info.hash_type == pie::hac::nca::HashType_HierarchicalSha256)
else if (info.hash_type == nn::hac::nca::HashType::HierarchicalSha256)
{
auto hash_hdr = info.hierarchicalsha256_hdr;
fmt::print(" HierarchicalSha256 Header:\n");
@ -588,7 +513,7 @@ void nstool::NcaProcess::displayHeader()
void nstool::NcaProcess::processPartitions()
{
std::vector<pie::hac::CombinedFsSnapshotGenerator::MountPointInfo> mount_points;
std::vector<nn::hac::CombinedFsMetaGenerator::MountPointInfo> mount_points;
for (size_t i = 0; i < mHdr.getPartitionEntryList().size(); i++)
{
@ -609,9 +534,9 @@ void nstool::NcaProcess::processPartitions()
std::string mount_point_name;
/*
if (mHdr.getContentType() == pie::hac::nca::ContentType_Program)
if (mHdr.getContentType() == nn::hac::nca::ContentType::Program)
{
mount_point_name = pie::hac::ContentArchiveUtil::getProgramContentParititionIndexAsString((pie::hac::nca::ProgramContentPartitionIndex)index);
mount_point_name = nn::hac::ContentArchiveUtil::getProgramContentParititionIndexAsString((nn::hac::nca::ProgramContentPartitionIndex)index);
}
else
*/
@ -619,12 +544,12 @@ void nstool::NcaProcess::processPartitions()
mount_point_name = fmt::format("{:d}", index);
}
mount_points.push_back( { mount_point_name, partition.fs_snapshot } );
mount_points.push_back( { mount_point_name, partition.fs_meta } );
}
tc::io::VirtualFileSystem::FileSystemSnapshot fs_snapshot = pie::hac::CombinedFsSnapshotGenerator(mount_points);
tc::io::VirtualFileSystem::FileSystemMeta fs_meta = nn::hac::CombinedFsMetaGenerator(mount_points);
std::shared_ptr<tc::io::IFileSystem> nca_fs = std::make_shared<tc::io::VirtualFileSystem>(tc::io::VirtualFileSystem(fs_snapshot));
std::shared_ptr<tc::io::IStorage> nca_fs = std::make_shared<tc::io::VirtualFileSystem>(tc::io::VirtualFileSystem(fs_meta));
mFsProcess.setInputFileSystem(nca_fs);
mFsProcess.setFsFormatName("ContentArchive");
@ -632,28 +557,28 @@ void nstool::NcaProcess::processPartitions()
mFsProcess.process();
}
std::string nstool::NcaProcess::getContentTypeForMountStr(pie::hac::nca::ContentType cont_type) const
std::string nstool::NcaProcess::getContentTypeForMountStr(nn::hac::nca::ContentType cont_type) const
{
std::string str;
switch (cont_type)
{
case (pie::hac::nca::ContentType_Program):
case (nn::hac::nca::ContentType::Program):
str = "program";
break;
case (pie::hac::nca::ContentType_Meta):
case (nn::hac::nca::ContentType::Meta):
str = "meta";
break;
case (pie::hac::nca::ContentType_Control):
case (nn::hac::nca::ContentType::Control):
str = "control";
break;
case (pie::hac::nca::ContentType_Manual):
case (nn::hac::nca::ContentType::Manual):
str = "manual";
break;
case (pie::hac::nca::ContentType_Data):
case (nn::hac::nca::ContentType::Data):
str = "data";
break;
case (pie::hac::nca::ContentType_PublicData):
case (nn::hac::nca::ContentType::PublicData):
str = "publicdata";
break;
default:

View file

@ -3,9 +3,9 @@
#include "KeyBag.h"
#include "FsProcess.h"
#include <pietendo/hac/ContentArchiveHeader.h>
#include <pietendo/hac/HierarchicalIntegrityHeader.h>
#include <pietendo/hac/HierarchicalSha256Header.h>
#include <nn/hac/ContentArchiveHeader.h>
#include <nn/hac/HierarchicalIntegrityHeader.h>
#include <nn/hac/HierarchicalSha256Header.h>
namespace nstool {
@ -21,8 +21,6 @@ public:
void setKeyCfg(const KeyBag& keycfg);
void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify);
void setBaseNcaPath(const tc::Optional<tc::io::Path>& nca_path);
// fs specific
void setShowFsTree(bool show_fs_tree);
@ -30,7 +28,7 @@ public:
void setExtractJobs(const std::vector<nstool::ExtractJob>& extract_jobs);
// post process() get FS out
const std::shared_ptr<tc::io::IFileSystem>& getFileSystem() const;
const std::shared_ptr<tc::io::IStorage>& getFileSystem() const;
private:
const std::string kNpdmExefsPath = "/main.npdm";
@ -41,16 +39,15 @@ private:
KeyBag mKeyCfg;
CliOutputMode mCliOutputMode;
bool mVerify;
tc::Optional<tc::io::Path> mBaseNcaPath;
// fs processing
std::shared_ptr<tc::io::IFileSystem> mFileSystem;
std::shared_ptr<tc::io::IStorage> mFileSystem;
FsProcess mFsProcess;
// nca data
pie::hac::sContentArchiveHeaderBlock mHdrBlock;
pie::hac::detail::sha256_hash_t mHdrHash;
pie::hac::ContentArchiveHeader mHdr;
nn::hac::sContentArchiveHeaderBlock mHdrBlock;
nn::hac::detail::sha256_hash_t mHdrHash;
nn::hac::ContentArchiveHeader mHdr;
// crypto
struct sKeys
@ -85,7 +82,7 @@ private:
};
std::vector<sKeyAreaKey> kak_list;
tc::Optional<pie::hac::detail::aes128_key_t> aes_ctr;
tc::Optional<nn::hac::detail::aes128_key_t> aes_ctr;
} mContentKey;
struct SparseInfo
@ -96,33 +93,30 @@ private:
// raw partition data
struct sPartitionInfo
{
std::shared_ptr<tc::io::IStream> raw_reader; // raw unprocessed partition stream
std::shared_ptr<tc::io::IStream> decrypt_reader; // partition stream with transparent decryption
std::shared_ptr<tc::io::IStream> reader; // partition stream with transparent decryption & hash layer processing
tc::io::VirtualFileSystem::FileSystemSnapshot fs_snapshot;
std::shared_ptr<tc::io::IFileSystem> fs_reader;
std::shared_ptr<tc::io::IStream> reader;
tc::io::VirtualFileSystem::FileSystemMeta fs_meta;
std::shared_ptr<tc::io::IStorage> fs_reader;
std::string fail_reason;
int64_t offset;
int64_t size;
// meta data
pie::hac::nca::FormatType format_type;
pie::hac::nca::HashType hash_type;
pie::hac::nca::EncryptionType enc_type;
pie::hac::nca::MetaDataHashType metadata_hash_type;
nn::hac::nca::FormatType format_type;
nn::hac::nca::HashType hash_type;
nn::hac::nca::EncryptionType enc_type;
// hash meta data
pie::hac::HierarchicalIntegrityHeader hierarchicalintegrity_hdr;
pie::hac::HierarchicalSha256Header hierarchicalsha256_hdr;
nn::hac::HierarchicalIntegrityHeader hierarchicalintegrity_hdr;
nn::hac::HierarchicalSha256Header hierarchicalsha256_hdr;
// crypto metadata
pie::hac::detail::aes_iv_t aes_ctr;
nn::hac::detail::aes_iv_t aes_ctr;
// sparse metadata
SparseInfo sparse_info;
};
std::array<sPartitionInfo, pie::hac::nca::kPartitionNum> mPartitions;
std::array<sPartitionInfo, nn::hac::nca::kPartitionNum> mPartitions;
void importHeader();
void generateNcaBodyEncryptionKeys();
@ -131,9 +125,7 @@ private:
void displayHeader();
void processPartitions();
NcaProcess readBaseNCA();
std::string getContentTypeForMountStr(pie::hac::nca::ContentType cont_type) const;
std::string getContentTypeForMountStr(nn::hac::nca::ContentType cont_type) const;
};
}

View file

@ -1,5 +1,7 @@
#include "NroProcess.h"
#include <nn/hac/define/nro-hb.h>
nstool::NroProcess::NroProcess() :
mModuleName("nstool::NroProcess"),
mFile(),
@ -89,13 +91,13 @@ void nstool::NroProcess::importHeader()
}
// check if file_size is smaller than NRO header size
if (tc::io::IOUtil::castInt64ToSize(mFile->length()) < sizeof(pie::hac::sNroHeader))
if (tc::io::IOUtil::castInt64ToSize(mFile->length()) < sizeof(nn::hac::sNroHeader))
{
throw tc::Exception(mModuleName, "Corrupt NRO: file too small.");
}
// read nro
tc::ByteData scratch = tc::ByteData(sizeof(pie::hac::sNroHeader));
tc::ByteData scratch = tc::ByteData(sizeof(nn::hac::sNroHeader));
mFile->seek(0, tc::io::SeekOrigin::Begin);
mFile->read(scratch.data(), scratch.size());
@ -103,10 +105,10 @@ void nstool::NroProcess::importHeader()
mHdr.fromBytes(scratch.data(), scratch.size());
// setup homebrew extension
pie::hac::sNroHeader* raw_hdr = (pie::hac::sNroHeader*)scratch.data();
nn::hac::sNroHeader* raw_hdr = (nn::hac::sNroHeader*)scratch.data();
int64_t file_size = mFile->length();
if (((tc::bn::le64<uint64_t>*)raw_hdr->reserved_0.data())->unwrap() == pie::hac::nro::kNroHomebrewStructMagic && file_size > int64_t(mHdr.getNroSize()))
if (((tc::bn::le64<uint64_t>*)raw_hdr->reserved_0.data())->unwrap() == nn::hac::nro::kNroHomebrewStructMagic && file_size > int64_t(mHdr.getNroSize()))
{
mIsHomebrewNro = true;
mAssetProc.setInputFile(std::make_shared<tc::io::SubStream>(tc::io::SubStream(mFile, int64_t(mHdr.getNroSize()), file_size - int64_t(mHdr.getNroSize()))));

View file

@ -3,7 +3,7 @@
#include "RoMetadataProcess.h"
#include "AssetProcess.h"
#include <pietendo/hac/NroHeader.h>
#include <nn/hac/NroHeader.h>
namespace nstool {
@ -36,7 +36,7 @@ private:
CliOutputMode mCliOutputMode;
bool mVerify;
pie::hac::NroHeader mHdr;
nn::hac::NroHeader mHdr;
tc::ByteData mTextBlob, mRoBlob, mDataBlob;
nstool::RoMetadataProcess mRoMeta;
bool mIsHomebrewNro;

View file

@ -71,13 +71,13 @@ void nstool::NsoProcess::importHeader()
// check if file_size is smaller than NSO header size
size_t file_size = tc::io::IOUtil::castInt64ToSize(mFile->length());
if (file_size < sizeof(pie::hac::sNsoHeader))
if (file_size < sizeof(nn::hac::sNsoHeader))
{
throw tc::Exception(mModuleName, "Corrupt NSO: file too small.");
}
// read nso
tc::ByteData scratch = tc::ByteData(sizeof(pie::hac::sNsoHeader));
tc::ByteData scratch = tc::ByteData(sizeof(nn::hac::sNsoHeader));
mFile->seek(0, tc::io::SeekOrigin::Begin);
mFile->read(scratch.data(), scratch.size());
@ -88,7 +88,7 @@ void nstool::NsoProcess::importHeader()
void nstool::NsoProcess::importCodeSegments()
{
tc::ByteData scratch;
pie::hac::detail::sha256_hash_t calc_hash;
nn::hac::detail::sha256_hash_t calc_hash;
// process text segment
if (mHdr.getTextSegmentInfo().is_compressed)
@ -116,7 +116,7 @@ void nstool::NsoProcess::importCodeSegments()
}
if (mHdr.getTextSegmentInfo().is_hashed)
{
tc::crypto::GenerateSha2256Hash(calc_hash.data(), mTextBlob.data(), mTextBlob.size());
tc::crypto::GenerateSha256Hash(calc_hash.data(), mTextBlob.data(), mTextBlob.size());
if (calc_hash != mHdr.getTextSegmentInfo().hash)
{
throw tc::Exception(mModuleName, "NSO text segment failed SHA256 verification");
@ -149,7 +149,7 @@ void nstool::NsoProcess::importCodeSegments()
}
if (mHdr.getRoSegmentInfo().is_hashed)
{
tc::crypto::GenerateSha2256Hash(calc_hash.data(), mRoBlob.data(), mRoBlob.size());
tc::crypto::GenerateSha256Hash(calc_hash.data(), mRoBlob.data(), mRoBlob.size());
if (calc_hash != mHdr.getRoSegmentInfo().hash)
{
throw tc::Exception(mModuleName, "NSO ro segment failed SHA256 verification");
@ -182,7 +182,7 @@ void nstool::NsoProcess::importCodeSegments()
}
if (mHdr.getDataSegmentInfo().is_hashed)
{
tc::crypto::GenerateSha2256Hash(calc_hash.data(), mDataBlob.data(), mDataBlob.size());
tc::crypto::GenerateSha256Hash(calc_hash.data(), mDataBlob.data(), mDataBlob.size());
if (calc_hash != mHdr.getDataSegmentInfo().hash)
{
throw tc::Exception(mModuleName, "NSO data segment failed SHA256 verification");

View file

@ -2,8 +2,8 @@
#include "types.h"
#include "RoMetadataProcess.h"
#include <pietendo/hac/define/meta.h>
#include <pietendo/hac/NsoHeader.h>
#include <nn/hac/define/meta.h>
#include <nn/hac/NsoHeader.h>
namespace nstool {
@ -33,7 +33,7 @@ private:
bool mListApi;
bool mListSymbols;
pie::hac::NsoHeader mHdr;
nn::hac::NsoHeader mHdr;
tc::ByteData mTextBlob, mRoBlob, mDataBlob;
nstool::RoMetadataProcess mRoMeta;

View file

@ -1,11 +1,11 @@
#include "PfsProcess.h"
#include "util.h"
#include <pietendo/hac/PartitionFsUtil.h>
#include <tc/io/LocalFileSystem.h>
#include <nn/hac/PartitionFsUtil.h>
#include <tc/io/LocalStorage.h>
#include <tc/io/VirtualFileSystem.h>
#include <pietendo/hac/PartitionFsSnapshotGenerator.h>
#include <nn/hac/PartitionFsMetaGenerator.h>
nstool::PfsProcess::PfsProcess() :
@ -34,21 +34,21 @@ void nstool::PfsProcess::process()
tc::ByteData scratch;
// read base header to determine complete header size
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(sizeof(pie::hac::sPfsHeader)))
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(sizeof(nn::hac::sPfsHeader)))
{
throw tc::Exception(mModuleName, "Corrupt PartitionFs: File too small");
}
scratch = tc::ByteData(sizeof(pie::hac::sPfsHeader));
scratch = tc::ByteData(sizeof(nn::hac::sPfsHeader));
mFile->seek(0, tc::io::SeekOrigin::Begin);
mFile->read(scratch.data(), scratch.size());
if (validateHeaderMagic(((pie::hac::sPfsHeader*)scratch.data())) == false)
if (validateHeaderMagic(((nn::hac::sPfsHeader*)scratch.data())) == false)
{
throw tc::Exception(mModuleName, "Corrupt PartitionFs: Header had incorrect struct magic.");
}
// read complete size header
size_t pfsHeaderSize = determineHeaderSize(((pie::hac::sPfsHeader*)scratch.data()));
size_t pfsHeaderSize = determineHeaderSize(((nn::hac::sPfsHeader*)scratch.data()));
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(pfsHeaderSize))
{
throw tc::Exception(mModuleName, "Corrupt PartitionFs: File too small");
@ -62,12 +62,12 @@ void nstool::PfsProcess::process()
mPfs.fromBytes(scratch.data(), scratch.size());
// create virtual filesystem
mFileSystem = std::make_shared<tc::io::VirtualFileSystem>(tc::io::VirtualFileSystem(pie::hac::PartitionFsSnapshotGenerator(mFile, mVerify ? pie::hac::PartitionFsSnapshotGenerator::ValidationMode_Warn : pie::hac::PartitionFsSnapshotGenerator::ValidationMode_None)));
mFileSystem = std::make_shared<tc::io::VirtualFileSystem>(tc::io::VirtualFileSystem(nn::hac::PartitionFsMetaGenerator(mFile, mVerify ? nn::hac::PartitionFsMetaGenerator::ValidationMode_Warn : nn::hac::PartitionFsMetaGenerator::ValidationMode_None)));
mFsProcess.setInputFileSystem(mFileSystem);
// set properties for FsProcess
mFsProcess.setFsProperties({
fmt::format("Type: {:s}", pie::hac::PartitionFsUtil::getFsTypeAsString(mPfs.getFsType())),
fmt::format("Type: {:s}", nn::hac::PartitionFsUtil::getFsTypeAsString(mPfs.getFsType())),
fmt::format("FileNum: {:d}", mPfs.getFileList().size())
});
@ -105,28 +105,28 @@ void nstool::PfsProcess::setExtractJobs(const std::vector<nstool::ExtractJob>& e
mFsProcess.setExtractJobs(extract_jobs);
}
const pie::hac::PartitionFsHeader& nstool::PfsProcess::getPfsHeader() const
const nn::hac::PartitionFsHeader& nstool::PfsProcess::getPfsHeader() const
{
return mPfs;
}
const std::shared_ptr<tc::io::IFileSystem>& nstool::PfsProcess::getFileSystem() const
const std::shared_ptr<tc::io::IStorage>& nstool::PfsProcess::getFileSystem() const
{
return mFileSystem;
}
size_t nstool::PfsProcess::determineHeaderSize(const pie::hac::sPfsHeader* hdr)
size_t nstool::PfsProcess::determineHeaderSize(const nn::hac::sPfsHeader* hdr)
{
size_t fileEntrySize = 0;
if (hdr->st_magic.unwrap() == pie::hac::pfs::kPfsStructMagic)
fileEntrySize = sizeof(pie::hac::sPfsFile);
if (hdr->st_magic.unwrap() == nn::hac::pfs::kPfsStructMagic)
fileEntrySize = sizeof(nn::hac::sPfsFile);
else
fileEntrySize = sizeof(pie::hac::sHashedPfsFile);
fileEntrySize = sizeof(nn::hac::sHashedPfsFile);
return sizeof(pie::hac::sPfsHeader) + hdr->file_num.unwrap() * fileEntrySize + hdr->name_table_size.unwrap();
return sizeof(nn::hac::sPfsHeader) + hdr->file_num.unwrap() * fileEntrySize + hdr->name_table_size.unwrap();
}
bool nstool::PfsProcess::validateHeaderMagic(const pie::hac::sPfsHeader* hdr)
bool nstool::PfsProcess::validateHeaderMagic(const nn::hac::sPfsHeader* hdr)
{
return hdr->st_magic.unwrap() == pie::hac::pfs::kPfsStructMagic || hdr->st_magic.unwrap() == pie::hac::pfs::kHashedPfsStructMagic;
return hdr->st_magic.unwrap() == nn::hac::pfs::kPfsStructMagic || hdr->st_magic.unwrap() == nn::hac::pfs::kHashedPfsStructMagic;
}

View file

@ -2,7 +2,7 @@
#include "types.h"
#include "FsProcess.h"
#include <pietendo/hac/PartitionFsHeader.h>
#include <nn/hac/PartitionFsHeader.h>
namespace nstool {
@ -24,8 +24,8 @@ public:
void setExtractJobs(const std::vector<nstool::ExtractJob>& extract_jobs);
// post process() get PFS/FS out
const pie::hac::PartitionFsHeader& getPfsHeader() const;
const std::shared_ptr<tc::io::IFileSystem>& getFileSystem() const;
const nn::hac::PartitionFsHeader& getPfsHeader() const;
const std::shared_ptr<tc::io::IStorage>& getFileSystem() const;
private:
static const size_t kCacheSize = 0x10000;
@ -36,13 +36,13 @@ private:
CliOutputMode mCliOutputMode;
bool mVerify;
pie::hac::PartitionFsHeader mPfs;
nn::hac::PartitionFsHeader mPfs;
std::shared_ptr<tc::io::IFileSystem> mFileSystem;
std::shared_ptr<tc::io::IStorage> mFileSystem;
FsProcess mFsProcess;
size_t determineHeaderSize(const pie::hac::sPfsHeader* hdr);
bool validateHeaderMagic(const pie::hac::sPfsHeader* hdr);
size_t determineHeaderSize(const nn::hac::sPfsHeader* hdr);
bool validateHeaderMagic(const nn::hac::sPfsHeader* hdr);
};
}

View file

@ -1,8 +1,8 @@
#include "PkiValidator.h"
#include <tc/crypto.h>
#include <pietendo/hac/define/types.h>
#include <pietendo/hac/es/SignUtils.h>
#include <nn/hac/define/types.h>
#include <nn/pki/SignUtils.h>
nstool::PkiValidator::PkiValidator() :
mModuleName("nstool::PkiValidator")
@ -13,7 +13,7 @@ nstool::PkiValidator::PkiValidator() :
void nstool::PkiValidator::setKeyCfg(const KeyBag& keycfg)
{
// save a copy of the certificate bank
std::vector<pie::hac::es::SignedData<pie::hac::es::CertificateBody>> old_certs = mCertificateBank;
std::vector<nn::pki::SignedData<nn::pki::CertificateBody>> old_certs = mCertificateBank;
// clear the certificate bank
mCertificateBank.clear();
@ -28,7 +28,7 @@ void nstool::PkiValidator::setKeyCfg(const KeyBag& keycfg)
}
}
void nstool::PkiValidator::addCertificates(const std::vector<pie::hac::es::SignedData<pie::hac::es::CertificateBody>>& certs)
void nstool::PkiValidator::addCertificates(const std::vector<nn::pki::SignedData<nn::pki::CertificateBody>>& certs)
{
for (size_t i = 0; i < certs.size(); i++)
{
@ -36,10 +36,11 @@ void nstool::PkiValidator::addCertificates(const std::vector<pie::hac::es::Signe
}
}
void nstool::PkiValidator::addCertificate(const pie::hac::es::SignedData<pie::hac::es::CertificateBody>& cert)
void nstool::PkiValidator::addCertificate(const nn::pki::SignedData<nn::pki::CertificateBody>& cert)
{
std::string cert_ident;
pie::hac::es::sign::HashAlgo cert_hash_algo;
nn::pki::sign::SignatureAlgo cert_sign_algo;
nn::pki::sign::HashAlgo cert_hash_algo;
tc::ByteData cert_hash;
try
@ -51,19 +52,20 @@ void nstool::PkiValidator::addCertificate(const pie::hac::es::SignedData<pie::ha
throw tc::Exception(mModuleName, "Certificate already exists");
}
cert_hash_algo = pie::hac::es::sign::getHashAlgo(cert.getSignature().getSignType());
cert_sign_algo = nn::pki::sign::getSignatureAlgo(cert.getSignature().getSignType());
cert_hash_algo = nn::pki::sign::getHashAlgo(cert.getSignature().getSignType());
// get cert hash
switch (cert_hash_algo)
{
case (pie::hac::es::sign::HASH_ALGO_SHA1):
case (nn::pki::sign::HASH_ALGO_SHA1):
cert_hash = tc::ByteData(tc::crypto::Sha1Generator::kHashSize);
tc::crypto::GenerateSha1Hash(cert_hash.data(), cert.getBody().getBytes().data(), cert.getBody().getBytes().size());
break;
case (pie::hac::es::sign::HASH_ALGO_SHA256):
cert_hash = tc::ByteData(tc::crypto::Sha2256Generator::kHashSize);
tc::crypto::GenerateSha2256Hash(cert_hash.data(), cert.getBody().getBytes().data(), cert.getBody().getBytes().size());
case (nn::pki::sign::HASH_ALGO_SHA256):
cert_hash = tc::ByteData(tc::crypto::Sha256Generator::kHashSize);
tc::crypto::GenerateSha256Hash(cert_hash.data(), cert.getBody().getBytes().data(), cert.getBody().getBytes().size());
break;
default:
throw tc::Exception(mModuleName, "Unrecognised hash type");
@ -84,9 +86,9 @@ void nstool::PkiValidator::clearCertificates()
mCertificateBank.clear();
}
void nstool::PkiValidator::validateSignature(const std::string& issuer, pie::hac::es::sign::SignatureId signature_id, const tc::ByteData& signature, const tc::ByteData& hash) const
void nstool::PkiValidator::validateSignature(const std::string& issuer, nn::pki::sign::SignatureId signature_id, const tc::ByteData& signature, const tc::ByteData& hash) const
{
pie::hac::es::sign::SignatureAlgo sign_algo = pie::hac::es::sign::getSignatureAlgo(signature_id);
nn::pki::sign::SignatureAlgo sign_algo = nn::pki::sign::getSignatureAlgo(signature_id);
// validate signature
bool sig_valid = false;
@ -110,7 +112,7 @@ void nstool::PkiValidator::validateSignature(const std::string& issuer, pie::hac
throw tc::Exception(mModuleName, fmt::format("Public key for issuer \"{:s}\" cannot verify this signature.", issuer));
}
if (sign_algo == pie::hac::es::sign::SIGN_ALGO_ECDSA240)
if (sign_algo == nn::pki::sign::SIGN_ALGO_ECDSA240)
{
throw tc::Exception(mModuleName, "ECDSA signatures are not supported");
}
@ -120,18 +122,18 @@ void nstool::PkiValidator::validateSignature(const std::string& issuer, pie::hac
else
{
// try to find issuer cert
const pie::hac::es::CertificateBody& issuer_cert = getCert(issuer).getBody();
pie::hac::es::cert::PublicKeyType issuer_pubk_type = issuer_cert.getPublicKeyType();
const nn::pki::CertificateBody& issuer_cert = getCert(issuer).getBody();
nn::pki::cert::PublicKeyType issuer_pubk_type = issuer_cert.getPublicKeyType();
if (issuer_pubk_type == pie::hac::es::cert::RSA4096 && sign_algo == pie::hac::es::sign::SIGN_ALGO_RSA4096)
if (issuer_pubk_type == nn::pki::cert::RSA4096 && sign_algo == nn::pki::sign::SIGN_ALGO_RSA4096)
{
rsa_key = issuer_cert.getRsa4096PublicKey();
}
else if (issuer_pubk_type == pie::hac::es::cert::RSA2048 && sign_algo == pie::hac::es::sign::SIGN_ALGO_RSA2048)
else if (issuer_pubk_type == nn::pki::cert::RSA2048 && sign_algo == nn::pki::sign::SIGN_ALGO_RSA2048)
{
rsa_key = issuer_cert.getRsa2048PublicKey();
}
else if (issuer_pubk_type == pie::hac::es::cert::ECDSA240 && sign_algo == pie::hac::es::sign::SIGN_ALGO_ECDSA240)
else if (issuer_pubk_type == nn::pki::cert::ECDSA240 && sign_algo == nn::pki::sign::SIGN_ALGO_ECDSA240)
{
// ecc_key = issuer_cert.getEcdsa240PublicKey();
throw tc::Exception(mModuleName, "ECDSA signatures are not supported");
@ -144,22 +146,22 @@ void nstool::PkiValidator::validateSignature(const std::string& issuer, pie::hac
// verify signature
switch (signature_id) {
case (pie::hac::es::sign::SIGN_ID_RSA4096_SHA1):
case (nn::pki::sign::SIGN_ID_RSA4096_SHA1):
sig_valid = tc::crypto::VerifyRsa4096Pkcs1Sha1(signature.data(), hash.data(), rsa_key);
break;
case (pie::hac::es::sign::SIGN_ID_RSA2048_SHA1):
case (nn::pki::sign::SIGN_ID_RSA2048_SHA1):
sig_valid = tc::crypto::VerifyRsa2048Pkcs1Sha1(signature.data(), hash.data(), rsa_key);
break;
case (pie::hac::es::sign::SIGN_ID_ECDSA240_SHA1):
case (nn::pki::sign::SIGN_ID_ECDSA240_SHA1):
sig_valid = false;
break;
case (pie::hac::es::sign::SIGN_ID_RSA4096_SHA256):
sig_valid = tc::crypto::VerifyRsa4096Pkcs1Sha2256(signature.data(), hash.data(), rsa_key);
case (nn::pki::sign::SIGN_ID_RSA4096_SHA256):
sig_valid = tc::crypto::VerifyRsa4096Pkcs1Sha256(signature.data(), hash.data(), rsa_key);
break;
case (pie::hac::es::sign::SIGN_ID_RSA2048_SHA256):
sig_valid = tc::crypto::VerifyRsa2048Pkcs1Sha2256(signature.data(), hash.data(), rsa_key);
case (nn::pki::sign::SIGN_ID_RSA2048_SHA256):
sig_valid = tc::crypto::VerifyRsa2048Pkcs1Sha256(signature.data(), hash.data(), rsa_key);
break;
case (pie::hac::es::sign::SIGN_ID_ECDSA240_SHA256):
case (nn::pki::sign::SIGN_ID_ECDSA240_SHA256):
sig_valid = false;
break;
}
@ -172,14 +174,14 @@ void nstool::PkiValidator::validateSignature(const std::string& issuer, pie::hac
}
void nstool::PkiValidator::makeCertIdent(const pie::hac::es::SignedData<pie::hac::es::CertificateBody>& cert, std::string& ident) const
void nstool::PkiValidator::makeCertIdent(const nn::pki::SignedData<nn::pki::CertificateBody>& cert, std::string& ident) const
{
makeCertIdent(cert.getBody().getIssuer(), cert.getBody().getSubject(), ident);
}
void nstool::PkiValidator::makeCertIdent(const std::string& issuer, const std::string& subject, std::string& ident) const
{
ident = issuer + pie::hac::es::sign::kIdentDelimiter + subject;
ident = issuer + nn::pki::sign::kIdentDelimiter + subject;
ident = ident.substr(0, std::min<size_t>(ident.length(),64));
}
@ -200,7 +202,7 @@ bool nstool::PkiValidator::doesCertExist(const std::string& ident) const
return exists;
}
const pie::hac::es::SignedData<pie::hac::es::CertificateBody>& nstool::PkiValidator::getCert(const std::string& ident) const
const nn::pki::SignedData<nn::pki::CertificateBody>& nstool::PkiValidator::getCert(const std::string& ident) const
{
std::string full_cert_name;
for (size_t i = 0; i < mCertificateBank.size(); i++)

View file

@ -2,8 +2,8 @@
#include "types.h"
#include "KeyBag.h"
#include <pietendo/hac/es/SignedData.h>
#include <pietendo/hac/es/CertificateBody.h>
#include <nn/pki/SignedData.h>
#include <nn/pki/CertificateBody.h>
namespace nstool {
@ -13,22 +13,22 @@ public:
PkiValidator();
void setKeyCfg(const KeyBag& keycfg);
void addCertificates(const std::vector<pie::hac::es::SignedData<pie::hac::es::CertificateBody>>& certs);
void addCertificate(const pie::hac::es::SignedData<pie::hac::es::CertificateBody>& cert);
void addCertificates(const std::vector<nn::pki::SignedData<nn::pki::CertificateBody>>& certs);
void addCertificate(const nn::pki::SignedData<nn::pki::CertificateBody>& cert);
void clearCertificates();
void validateSignature(const std::string& issuer, pie::hac::es::sign::SignatureId signature_id, const tc::ByteData& signature, const tc::ByteData& hash) const;
void validateSignature(const std::string& issuer, nn::pki::sign::SignatureId signature_id, const tc::ByteData& signature, const tc::ByteData& hash) const;
private:
std::string mModuleName;
KeyBag mKeyCfg;
std::vector<pie::hac::es::SignedData<pie::hac::es::CertificateBody>> mCertificateBank;
std::vector<nn::pki::SignedData<nn::pki::CertificateBody>> mCertificateBank;
void makeCertIdent(const pie::hac::es::SignedData<pie::hac::es::CertificateBody>& cert, std::string& ident) const;
void makeCertIdent(const nn::pki::SignedData<nn::pki::CertificateBody>& cert, std::string& ident) const;
void makeCertIdent(const std::string& issuer, const std::string& subject, std::string& ident) const;
bool doesCertExist(const std::string& ident) const;
const pie::hac::es::SignedData<pie::hac::es::CertificateBody>& getCert(const std::string& ident) const;
const nn::pki::SignedData<nn::pki::CertificateBody>& getCert(const std::string& ident) const;
};
}

View file

@ -3,7 +3,7 @@
#include "SdkApiString.h"
#include "ElfSymbolParser.h"
#include <pietendo/hac/define/meta.h>
#include <nn/hac/define/meta.h>
namespace nstool {

View file

@ -2,7 +2,7 @@
#include "util.h"
#include <tc/io/VirtualFileSystem.h>
#include <pietendo/hac/RomFsSnapshotGenerator.h>
#include <nn/hac/RomFsMetaGenerator.h>
nstool::RomfsProcess::RomfsProcess() :
@ -20,7 +20,6 @@ nstool::RomfsProcess::RomfsProcess() :
void nstool::RomfsProcess::process()
{
// state checks
if (mFile == nullptr)
{
throw tc::Exception(mModuleName, "No file reader set.");
@ -30,62 +29,38 @@ void nstool::RomfsProcess::process()
throw tc::NotSupportedException(mModuleName, "Input stream requires read/seek permissions.");
}
tc::ByteData scratch;
// read base header to determine complete header size
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(sizeof(pie::hac::sRomfsHeader)))
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(sizeof(nn::hac::sRomfsHeader)))
{
throw tc::Exception(mModuleName, "Corrupt RomFs: File too small");
}
mFile->seek(0, tc::io::SeekOrigin::Begin);
mFile->read((byte_t*)&mRomfsHeader, sizeof(mRomfsHeader));
if (mRomfsHeader.header_size.unwrap() != sizeof(pie::hac::sRomfsHeader) ||
if (mRomfsHeader.header_size.unwrap() != sizeof(nn::hac::sRomfsHeader) ||
mRomfsHeader.dir_entry.offset.unwrap() != (mRomfsHeader.dir_hash_bucket.offset.unwrap() + mRomfsHeader.dir_hash_bucket.size.unwrap()) ||
mRomfsHeader.data_offset.unwrap() != align<int64_t>(mRomfsHeader.header_size.unwrap(), pie::hac::romfs::kRomfsHeaderAlign))
mRomfsHeader.data_offset.unwrap() != align<int64_t>(mRomfsHeader.header_size.unwrap(), nn::hac::romfs::kRomfsHeaderAlign))
{
throw tc::ArgumentOutOfRangeException(mModuleName, "Corrupt RomFs: RomFsHeader is corrupted.");
}
/*
fmt::print("RomFsHeader:\n");
fmt::print(" > header_size = 0x{:04x}\n", mRomfsHeader.header_size.unwrap());
fmt::print(" > dir_hash_bucket\n");
fmt::print(" > offset = 0x{:04x}\n", mRomfsHeader.dir_hash_bucket.offset.unwrap());
fmt::print(" > size = 0x{:04x}\n", mRomfsHeader.dir_hash_bucket.size.unwrap());
fmt::print(" > dir_entry\n");
fmt::print(" > offset = 0x{:04x}\n", mRomfsHeader.dir_entry.offset.unwrap());
fmt::print(" > size = 0x{:04x}\n", mRomfsHeader.dir_entry.size.unwrap());
fmt::print(" > file_hash_bucket\n");
fmt::print(" > offset = 0x{:04x}\n", mRomfsHeader.file_hash_bucket.offset.unwrap())
fmt::print(" > size = 0x{:04x}\n", mRomfsHeader.file_hash_bucket.size.unwrap());
fmt::print(" > file_entry\n");
fmt::print(" > offset = 0x{:04x}\n", mRomfsHeader.file_entry.offset.unwrap());
fmt::print(" > size = 0x{:04x}\n", mRomfsHeader.file_entry.size.unwrap());
fmt::print(" > data_offset = 0x{:04x}\n", mRomfsHeader.data_offset.unwrap());
*/
// get dir entry ptr
tc::ByteData dir_entry_table = tc::ByteData();
if (mRomfsHeader.dir_entry.size.unwrap() > 0)
{
dir_entry_table = tc::ByteData(tc::io::IOUtil::castInt64ToSize(mRomfsHeader.dir_entry.size.unwrap()));
mFile->seek(mRomfsHeader.dir_entry.offset.unwrap(), tc::io::SeekOrigin::Begin);
mFile->read(dir_entry_table.data(), dir_entry_table.size());
}
tc::ByteData dir_entry_table = tc::ByteData(tc::io::IOUtil::castInt64ToSize(mRomfsHeader.dir_entry.size.unwrap()));
mFile->seek(mRomfsHeader.dir_entry.offset.unwrap(), tc::io::SeekOrigin::Begin);
mFile->read(dir_entry_table.data(), dir_entry_table.size());
// get file entry ptr
tc::ByteData file_entry_table = tc::ByteData();
if (mRomfsHeader.file_entry.size.unwrap() > 0)
{
file_entry_table = tc::ByteData(tc::io::IOUtil::castInt64ToSize(mRomfsHeader.file_entry.size.unwrap()));
mFile->seek(mRomfsHeader.file_entry.offset.unwrap(), tc::io::SeekOrigin::Begin);
mFile->read(file_entry_table.data(), file_entry_table.size());
}
tc::ByteData file_entry_table = tc::ByteData(tc::io::IOUtil::castInt64ToSize(mRomfsHeader.file_entry.size.unwrap()));
mFile->seek(mRomfsHeader.file_entry.offset.unwrap(), tc::io::SeekOrigin::Begin);
mFile->read(file_entry_table.data(), file_entry_table.size());
// count dir num
mDirNum = 0;
for (uint32_t v_addr = 0; size_t(v_addr) < dir_entry_table.size();)
{
uint32_t total_size = sizeof(pie::hac::sRomfsDirEntry) + align<uint32_t>(((pie::hac::sRomfsDirEntry*)(dir_entry_table.data() + v_addr))->name_size.unwrap(), 4);
uint32_t total_size = sizeof(nn::hac::sRomfsDirEntry) + align<uint32_t>(((nn::hac::sRomfsDirEntry*)(dir_entry_table.data() + v_addr))->name_size.unwrap(), 4);
// don't count root directory
if (v_addr != 0)
@ -100,7 +75,7 @@ void nstool::RomfsProcess::process()
mFileNum = 0;
for (uint32_t v_addr = 0; size_t(v_addr) < file_entry_table.size();)
{
uint32_t total_size = sizeof(pie::hac::sRomfsFileEntry) + align<uint32_t>(((pie::hac::sRomfsFileEntry*)(file_entry_table.data() + v_addr))->name_size.unwrap(), 4);
uint32_t total_size = sizeof(nn::hac::sRomfsFileEntry) + align<uint32_t>(((nn::hac::sRomfsFileEntry*)(file_entry_table.data() + v_addr))->name_size.unwrap(), 4);
mFileNum += 1;
@ -108,7 +83,7 @@ void nstool::RomfsProcess::process()
}
// create virtual filesystem
mFileSystem = std::make_shared<tc::io::VirtualFileSystem>(tc::io::VirtualFileSystem(pie::hac::RomFsSnapshotGenerator(mFile)));
mFileSystem = std::make_shared<tc::io::VirtualFileSystem>(tc::io::VirtualFileSystem(nn::hac::RomFsMetaGenerator(mFile)));
mFsProcess.setInputFileSystem(mFileSystem);
// set properties for FsProcess

View file

@ -2,7 +2,7 @@
#include "types.h"
#include "FsProcess.h"
#include <pietendo/hac/define/romfs.h>
#include <nn/hac/define/romfs.h>
namespace nstool {
@ -31,11 +31,11 @@ private:
CliOutputMode mCliOutputMode;
bool mVerify;
pie::hac::sRomfsHeader mRomfsHeader;
nn::hac::sRomfsHeader mRomfsHeader;
size_t mDirNum;
size_t mFileNum;
std::shared_ptr<tc::io::IFileSystem> mFileSystem;
std::shared_ptr<tc::io::IStorage> mFileSystem;
FsProcess mFsProcess;
};

View file

@ -9,24 +9,27 @@
#include <tc/io/FileStream.h>
#include <tc/io/StreamSource.h>
#include <pietendo/hac/ContentArchiveUtil.h>
#include <pietendo/hac/AesKeygen.h>
#include <pietendo/hac/define/gc.h>
#include <pietendo/hac/define/pfs.h>
#include <pietendo/hac/define/nca.h>
#include <pietendo/hac/define/meta.h>
#include <pietendo/hac/define/romfs.h>
#include <pietendo/hac/define/cnmt.h>
#include <pietendo/hac/define/nacp.h>
#include <pietendo/hac/define/nso.h>
#include <pietendo/hac/define/nro.h>
#include <pietendo/hac/define/ini.h>
#include <pietendo/hac/define/kip.h>
#include <pietendo/hac/define/aset.h>
#include <pietendo/hac/es/SignedData.h>
#include <pietendo/hac/es/CertificateBody.h>
#include <pietendo/hac/es/SignUtils.h>
#include <pietendo/hac/es/TicketBody_V2.h>
#include <nn/hac/ContentArchiveUtil.h>
#include <nn/hac/AesKeygen.h>
#include <nn/hac/define/gc.h>
#include <nn/hac/define/pfs.h>
#include <nn/hac/define/nca.h>
#include <nn/hac/define/meta.h>
#include <nn/hac/define/romfs.h>
#include <nn/hac/define/cnmt.h>
#include <nn/hac/define/nacp.h>
#include <nn/hac/define/nso.h>
#include <nn/hac/define/nro.h>
#include <nn/hac/define/ini.h>
#include <nn/hac/define/kip.h>
#include <nn/hac/define/aset.h>
#include <nn/pki/SignedData.h>
#include <nn/pki/CertificateBody.h>
#include <nn/pki/SignUtils.h>
#include <nn/es/TicketBody_V2.h>
class UnkOptionHandler : public tc::cli::OptionParser::IOptionHandler
{
@ -39,11 +42,6 @@ public:
throw tc::InvalidOperationException("getOptionStrings() not defined for UnkOptionHandler.");
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
throw tc::InvalidOperationException("getOptionRegexPatterns() not defined for UnkOptionHandler.");
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
throw tc::Exception(mModuleLabel, "Unrecognized option: \"" + option + "\"");
@ -57,8 +55,7 @@ class DeprecatedOptionHandler : public tc::cli::OptionParser::IOptionHandler
public:
DeprecatedOptionHandler(const std::string& warn_message, const std::vector<std::string>& opts) :
mWarnMessage(warn_message),
mOptStrings(opts),
mOptRegex()
mOptStrings(opts)
{}
const std::vector<std::string>& getOptionStrings() const
@ -66,11 +63,6 @@ public:
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
fmt::print("[WARNING] Option \"{}\" is deprecated.{}{}\n", option, (mWarnMessage.empty() ? "" : " "), mWarnMessage);
@ -78,7 +70,6 @@ public:
private:
std::string mWarnMessage;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class FlagOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -86,8 +77,7 @@ class FlagOptionHandler : public tc::cli::OptionParser::IOptionHandler
public:
FlagOptionHandler(bool& flag, const std::vector<std::string>& opts) :
mFlag(flag),
mOptStrings(opts),
mOptRegex()
mOptStrings(opts)
{}
const std::vector<std::string>& getOptionStrings() const
@ -95,11 +85,6 @@ public:
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() != 0)
@ -112,7 +97,6 @@ public:
private:
bool& mFlag;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class SingleParamStringOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -120,8 +104,7 @@ class SingleParamStringOptionHandler : public tc::cli::OptionParser::IOptionHand
public:
SingleParamStringOptionHandler(tc::Optional<std::string>& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts),
mOptRegex()
mOptStrings(opts)
{}
const std::vector<std::string>& getOptionStrings() const
@ -129,11 +112,6 @@ public:
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() != 1)
@ -146,7 +124,6 @@ public:
private:
tc::Optional<std::string>& mParam;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class SingleParamPathOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -154,8 +131,7 @@ class SingleParamPathOptionHandler : public tc::cli::OptionParser::IOptionHandle
public:
SingleParamPathOptionHandler(tc::Optional<tc::io::Path>& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts),
mOptRegex()
mOptStrings(opts)
{}
const std::vector<std::string>& getOptionStrings() const
@ -163,11 +139,6 @@ public:
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() != 1)
@ -180,7 +151,6 @@ public:
private:
tc::Optional<tc::io::Path>& mParam;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class SingleParamSizetOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -188,8 +158,7 @@ class SingleParamSizetOptionHandler : public tc::cli::OptionParser::IOptionHandl
public:
SingleParamSizetOptionHandler(size_t& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts),
mOptRegex()
mOptStrings(opts)
{}
const std::vector<std::string>& getOptionStrings() const
@ -197,11 +166,6 @@ public:
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() != 1)
@ -214,7 +178,6 @@ public:
private:
size_t& mParam;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class SingleParamAesKeyOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -222,8 +185,7 @@ class SingleParamAesKeyOptionHandler : public tc::cli::OptionParser::IOptionHand
public:
SingleParamAesKeyOptionHandler(tc::Optional<nstool::KeyBag::aes128_key_t>& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts),
mOptRegex()
mOptStrings(opts)
{}
const std::vector<std::string>& getOptionStrings() const
@ -231,11 +193,6 @@ public:
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() != 1)
@ -257,41 +214,6 @@ public:
private:
tc::Optional<nstool::KeyBag::aes128_key_t>& mParam;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class SingleParamPathArrayOptionHandler : public tc::cli::OptionParser::IOptionHandler
{
public:
SingleParamPathArrayOptionHandler(std::vector<tc::io::Path>& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts),
mOptRegex()
{}
const std::vector<std::string>& getOptionStrings() const
{
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() != 1)
{
throw tc::ArgumentOutOfRangeException(fmt::format("Option \"{:s}\" requires a parameter.", option));
}
mParam.push_back(params[0]);
}
private:
std::vector<tc::io::Path>& mParam;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class FileTypeOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -299,8 +221,7 @@ class FileTypeOptionHandler : public tc::cli::OptionParser::IOptionHandler
public:
FileTypeOptionHandler(nstool::Settings::FileType& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts),
mOptRegex()
mOptStrings(opts)
{}
const std::vector<std::string>& getOptionStrings() const
@ -308,11 +229,6 @@ public:
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() != 1)
@ -394,7 +310,6 @@ public:
private:
nstool::Settings::FileType& mParam;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class InstructionTypeOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -402,8 +317,7 @@ class InstructionTypeOptionHandler : public tc::cli::OptionParser::IOptionHandle
public:
InstructionTypeOptionHandler(bool& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts),
mOptRegex()
mOptStrings(opts)
{}
const std::vector<std::string>& getOptionStrings() const
@ -411,11 +325,6 @@ public:
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() != 1)
@ -439,7 +348,6 @@ public:
private:
bool& mParam;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class ExtractDataPathOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -447,8 +355,7 @@ class ExtractDataPathOptionHandler : public tc::cli::OptionParser::IOptionHandle
public:
ExtractDataPathOptionHandler(std::vector<nstool::ExtractJob>& jobs, const std::vector<std::string>& opts) :
mJobs(jobs),
mOptStrings(opts),
mOptRegex()
mOptStrings(opts)
{}
const std::vector<std::string>& getOptionStrings() const
@ -456,11 +363,6 @@ public:
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() == 1)
@ -479,7 +381,6 @@ public:
private:
std::vector<nstool::ExtractJob>& mJobs;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class CustomExtractDataPathOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -488,7 +389,6 @@ public:
CustomExtractDataPathOptionHandler(std::vector<nstool::ExtractJob>& jobs, const std::vector<std::string>& opts, const tc::io::Path& custom_path) :
mJobs(jobs),
mOptStrings(opts),
mOptRegex(),
mCustomPath(custom_path)
{}
@ -497,11 +397,6 @@ public:
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() != 1)
@ -509,6 +404,9 @@ public:
throw tc::ArgumentOutOfRangeException(fmt::format("Option \"{:s}\" requires a parameter.", option));
}
std::string custom_path_str;
tc::io::PathUtil::pathToUnixUTF8(mCustomPath, custom_path_str);
fmt::print("[WARNING] \"{:s} {:s}\" is deprecated. ", option, params[0]);
// if custom path is root path, use the shortened version of -x
if (mCustomPath == tc::io::Path("/"))
@ -517,7 +415,7 @@ public:
}
else
{
fmt::print("Consider using \"-x {:s} {:s}\" instead.\n", mCustomPath.to_string(), params[0]);
fmt::print("Consider using \"-x {:s} {:s}\" instead.\n", custom_path_str, params[0]);
}
@ -526,7 +424,6 @@ public:
private:
std::vector<nstool::ExtractJob>& mJobs;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
tc::io::Path mCustomPath;
};
@ -538,7 +435,7 @@ nstool::SettingsInitializer::SettingsInitializer(const std::vector<std::string>&
mVerbose(false),
mNcaEncryptedContentKey(),
mNcaContentKey(),
mTikPathList(),
mTikPath(),
mCertPath()
{
// parse input arguments
@ -566,16 +463,29 @@ nstool::SettingsInitializer::SettingsInitializer(const std::vector<std::string>&
// locate key file, if not specfied
if (mKeysetPath.isNull())
{
loadKeyFile(mKeysetPath, opt.is_dev ? "dev.keys" : "prod.keys", "Maybe specify it with \"-k <path>\"?\n");
}
// locate title key file, if not specfied
if (mTitleKeysetPath.isNull())
{
loadKeyFile(mTitleKeysetPath, "title.keys", "");
std::string home_path_str;
if (tc::os::getEnvVar("HOME", home_path_str) || tc::os::getEnvVar("USERPROFILE", home_path_str))
{
tc::io::Path keyfile_path = tc::io::Path(home_path_str);
keyfile_path.push_back(".switch");
keyfile_path.push_back(opt.is_dev ? "dev.keys" : "prod.keys");
try {
tc::io::FileStream test = tc::io::FileStream(keyfile_path, tc::io::FileMode::Open, tc::io::FileAccess::Read);
mKeysetPath = keyfile_path;
}
catch (tc::io::FileNotFoundException&) {
fmt::print("[WARNING] Failed to load \"{}\" keyfile. Maybe specify it with \"-k <path>\"?\n", opt.is_dev ? "dev.keys" : "prod.keys");
}
}
else {
fmt::print("[WARNING] Failed to located \"{}\" keyfile. Maybe specify it with \"-k <path>\"?\n", opt.is_dev ? "dev.keys" : "prod.keys");
}
}
// generate keybag
opt.keybag = KeyBagInitializer(opt.is_dev, mKeysetPath, mTitleKeysetPath, mTikPathList, mCertPath);
opt.keybag = KeyBagInitializer(opt.is_dev, mKeysetPath, mTikPath, mCertPath);
opt.keybag.fallback_enc_content_key = mNcaEncryptedContentKey;
opt.keybag.fallback_content_key = mNcaContentKey;
@ -639,10 +549,9 @@ void nstool::SettingsInitializer::parse_args(const std::vector<std::string>& arg
// get user-provided keydata
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(mKeysetPath, {"-k", "--keyset"})));
//opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(mTitleKeysetPath, {"--titlekeyset"})));
opts.registerOptionHandler(std::shared_ptr<SingleParamAesKeyOptionHandler>(new SingleParamAesKeyOptionHandler(mNcaEncryptedContentKey, {"--titlekey"})));
opts.registerOptionHandler(std::shared_ptr<SingleParamAesKeyOptionHandler>(new SingleParamAesKeyOptionHandler(mNcaContentKey, {"--contentkey", "--bodykey"})));
opts.registerOptionHandler(std::shared_ptr<SingleParamPathArrayOptionHandler>(new SingleParamPathArrayOptionHandler(mTikPathList, {"--tik"})));
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(mTikPath, {"--tik"})));
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(mCertPath, {"--cert"})));
// code options
@ -667,8 +576,6 @@ void nstool::SettingsInitializer::parse_args(const std::vector<std::string>& arg
opts.registerOptionHandler(std::shared_ptr<CustomExtractDataPathOptionHandler>(new CustomExtractDataPathOptionHandler(fs.extract_jobs, { "--part2" }, tc::io::Path("/2/"))));
opts.registerOptionHandler(std::shared_ptr<CustomExtractDataPathOptionHandler>(new CustomExtractDataPathOptionHandler(fs.extract_jobs, { "--part3" }, tc::io::Path("/3/"))));
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(nca.base_nca_path, { "--basenca" })));
// kip options
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(kip.extract_path, { "--kipdir" })));
@ -683,7 +590,9 @@ void nstool::SettingsInitializer::parse_args(const std::vector<std::string>& arg
void nstool::SettingsInitializer::determine_filetype()
{
//fmt::print("infile path = \"{}\"\n", infile.path.get().to_string());
//std::string infile_path_str;
//tc::io::PathUtil::pathToUnixUTF8(infile.path.get(), infile_path_str);
//fmt::print("infile path = \"{}\"\n", infile_path_str);
auto file = tc::io::StreamSource(std::make_shared<tc::io::FileStream>(tc::io::FileStream(infile.path.get(), tc::io::FileMode::Open, tc::io::FileAccess::Read)));
@ -695,69 +604,69 @@ void nstool::SettingsInitializer::determine_filetype()
// do easy tests
// detect "scene" XCI
if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sGcHeader_Rsa2048Signed))
&& _TYPE_PTR(pie::hac::sGcHeader_Rsa2048Signed)->header.st_magic.unwrap() == pie::hac::gc::kGcHeaderStructMagic)
if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sGcHeader_Rsa2048Signed))
&& _TYPE_PTR(nn::hac::sGcHeader_Rsa2048Signed)->header.st_magic.unwrap() == nn::hac::gc::kGcHeaderStructMagic)
{
infile.filetype = FILE_TYPE_GAMECARD;
}
// detect "SDK" XCI
else if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sSdkGcHeader))
&& _TYPE_PTR(pie::hac::sSdkGcHeader)->signed_header.header.st_magic.unwrap() == pie::hac::gc::kGcHeaderStructMagic)
else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sSdkGcHeader))
&& _TYPE_PTR(nn::hac::sSdkGcHeader)->signed_header.header.st_magic.unwrap() == nn::hac::gc::kGcHeaderStructMagic)
{
infile.filetype = FILE_TYPE_GAMECARD;
}
// detect PFS0
else if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sPfsHeader))
&& _TYPE_PTR(pie::hac::sPfsHeader)->st_magic.unwrap() == pie::hac::pfs::kPfsStructMagic)
else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sPfsHeader))
&& _TYPE_PTR(nn::hac::sPfsHeader)->st_magic.unwrap() == nn::hac::pfs::kPfsStructMagic)
{
infile.filetype = FILE_TYPE_PARTITIONFS;
}
// detect HFS0
else if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sPfsHeader))
&& _TYPE_PTR(pie::hac::sPfsHeader)->st_magic.unwrap() == pie::hac::pfs::kHashedPfsStructMagic)
else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sPfsHeader))
&& _TYPE_PTR(nn::hac::sPfsHeader)->st_magic.unwrap() == nn::hac::pfs::kHashedPfsStructMagic)
{
infile.filetype = FILE_TYPE_PARTITIONFS;
}
// detect ROMFS
else if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sRomfsHeader))
&& _TYPE_PTR(pie::hac::sRomfsHeader)->header_size.unwrap() == sizeof(pie::hac::sRomfsHeader)
&& _TYPE_PTR(pie::hac::sRomfsHeader)->dir_entry.offset.unwrap() == (_TYPE_PTR(pie::hac::sRomfsHeader)->dir_hash_bucket.offset.unwrap() + _TYPE_PTR(pie::hac::sRomfsHeader)->dir_hash_bucket.size.unwrap()))
else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sRomfsHeader))
&& _TYPE_PTR(nn::hac::sRomfsHeader)->header_size.unwrap() == sizeof(nn::hac::sRomfsHeader)
&& _TYPE_PTR(nn::hac::sRomfsHeader)->dir_entry.offset.unwrap() == (_TYPE_PTR(nn::hac::sRomfsHeader)->dir_hash_bucket.offset.unwrap() + _TYPE_PTR(nn::hac::sRomfsHeader)->dir_hash_bucket.size.unwrap()))
{
infile.filetype = FILE_TYPE_ROMFS;
}
// detect NPDM
else if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sMetaHeader))
&& _TYPE_PTR(pie::hac::sMetaHeader)->st_magic.unwrap() == pie::hac::meta::kMetaStructMagic)
else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sMetaHeader))
&& _TYPE_PTR(nn::hac::sMetaHeader)->st_magic.unwrap() == nn::hac::meta::kMetaStructMagic)
{
infile.filetype = FILE_TYPE_META;
}
// detect NSO
else if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sNsoHeader))
&& _TYPE_PTR(pie::hac::sNsoHeader)->st_magic.unwrap() == pie::hac::nso::kNsoStructMagic)
else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sNsoHeader))
&& _TYPE_PTR(nn::hac::sNsoHeader)->st_magic.unwrap() == nn::hac::nso::kNsoStructMagic)
{
infile.filetype = FILE_TYPE_NSO;
}
// detect NRO
else if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sNroHeader))
&& _TYPE_PTR(pie::hac::sNroHeader)->st_magic.unwrap() == pie::hac::nro::kNroStructMagic)
else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sNroHeader))
&& _TYPE_PTR(nn::hac::sNroHeader)->st_magic.unwrap() == nn::hac::nro::kNroStructMagic)
{
infile.filetype = FILE_TYPE_NRO;
}
// detect INI
else if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sIniHeader))
&& _TYPE_PTR(pie::hac::sIniHeader)->st_magic.unwrap() == pie::hac::ini::kIniStructMagic)
else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sIniHeader))
&& _TYPE_PTR(nn::hac::sIniHeader)->st_magic.unwrap() == nn::hac::ini::kIniStructMagic)
{
infile.filetype = FILE_TYPE_INI;
}
// detect KIP
else if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sKipHeader))
&& _TYPE_PTR(pie::hac::sKipHeader)->st_magic.unwrap() == pie::hac::kip::kKipStructMagic)
else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sKipHeader))
&& _TYPE_PTR(nn::hac::sKipHeader)->st_magic.unwrap() == nn::hac::kip::kKipStructMagic)
{
infile.filetype = FILE_TYPE_KIP;
}
// detect HB ASET
else if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sAssetHeader))
&& _TYPE_PTR(pie::hac::sAssetHeader)->st_magic.unwrap() == pie::hac::aset::kAssetStructMagic)
else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sAssetHeader))
&& _TYPE_PTR(nn::hac::sAssetHeader)->st_magic.unwrap() == nn::hac::aset::kAssetStructMagic)
{
infile.filetype = FILE_TYPE_KIP;
}
@ -820,7 +729,7 @@ void nstool::SettingsInitializer::usage_text() const
fmt::print(" --normal Extract \"normal\" partition to directory. (Alias for \"-x /normal <out path>\")\n");
fmt::print(" --secure Extract \"secure\" partition to directory. (Alias for \"-x /secure <out path>\")\n");
fmt::print("\n NCA (Nintendo Content Archive)\n");
fmt::print(" {:s} [--fstree] [-x [<virtual path>] <out path>] [--bodykey <key> --titlekey <key> -tik <tik path> --basenca <.nca file>] <.nca file>\n", BIN_NAME);
fmt::print(" {:s} [--fstree] [-x [<virtual path>] <out path>] [--bodykey <key> --titlekey <key> -tik <tik path>] <.nca file>\n", BIN_NAME);
fmt::print(" --fstree Print filesystem tree.\n");
fmt::print(" -x, --extract Extract a file or directory to local filesystem.\n");
fmt::print(" --titlekey Specify (encrypted) title key extracted from ticket.\n");
@ -831,7 +740,6 @@ void nstool::SettingsInitializer::usage_text() const
fmt::print(" --part1 Extract partition \"1\" to directory. (Alias for \"-x /1 <out path>\")\n");
fmt::print(" --part2 Extract partition \"2\" to directory. (Alias for \"-x /2 <out path>\")\n");
fmt::print(" --part3 Extract partition \"3\" to directory. (Alias for \"-x /3 <out path>\")\n");
fmt::print(" --basenca Specify base NCA file for update NCA files.\n");
fmt::print("\n NSO (Nintendo Shared Object), NRO (Nintendo Relocatable Object)\n");
fmt::print(" {:s} [--listapi --listsym] [--insttype <inst. type>] <file>\n", BIN_NAME);
fmt::print(" --listapi Print SDK API List.\n");
@ -928,24 +836,24 @@ void nstool::SettingsInitializer::dump_keys() const
fmt::print(" {:s}:\n", itr->first);
fmt::print(" SignType: ");
switch(itr->second.key_type) {
case pie::hac::es::sign::SIGN_ALGO_RSA2048:
case nn::pki::sign::SIGN_ALGO_RSA2048:
fmt::print("RSA-2048\n");
break;
case pie::hac::es::sign::SIGN_ALGO_RSA4096:
case nn::pki::sign::SIGN_ALGO_RSA4096:
fmt::print("RSA-4096\n");
break;
case pie::hac::es::sign::SIGN_ALGO_ECDSA240:
case nn::pki::sign::SIGN_ALGO_ECDSA240:
fmt::print("ECDSA-240\n");
break;
default:
fmt::print("Unknown\n");
}
switch(itr->second.key_type) {
case pie::hac::es::sign::SIGN_ALGO_RSA2048:
case pie::hac::es::sign::SIGN_ALGO_RSA4096:
case nn::pki::sign::SIGN_ALGO_RSA2048:
case nn::pki::sign::SIGN_ALGO_RSA4096:
dump_rsa_key(itr->second.rsa_key, "RsaKey", 6, opt.cli_output_mode.show_extended_info);
break;
case pie::hac::es::sign::SIGN_ALGO_ECDSA240:
case nn::pki::sign::SIGN_ALGO_ECDSA240:
default:
break;
}
@ -989,34 +897,10 @@ void nstool::SettingsInitializer::dump_rsa_key(const KeyBag::rsa_key_t& key, con
}
}
void nstool::SettingsInitializer::loadKeyFile(tc::Optional<tc::io::Path>& keyfile_path, const std::string& keyfile_name, const std::string& cli_hint)
{
std::string home_path_str;
if (tc::os::getEnvVar("HOME", home_path_str) || tc::os::getEnvVar("USERPROFILE", home_path_str))
{
tc::io::Path tmp_path = tc::io::Path(home_path_str);
tmp_path.push_back(".switch");
tmp_path.push_back(keyfile_name);
try {
tc::io::FileStream test = tc::io::FileStream(tmp_path, tc::io::FileMode::Open, tc::io::FileAccess::Read);
keyfile_path = tmp_path;
}
catch (tc::io::FileNotFoundException&) {
fmt::print("[WARNING] Failed to load \"{}\" keyfile.{}\n", keyfile_name, cli_hint);
}
}
else {
fmt::print("[WARNING] Failed to locate \"{}\" keyfile.{}\n", keyfile_name, cli_hint);
}
}
bool nstool::SettingsInitializer::determineValidNcaFromSample(const tc::ByteData& sample) const
{
if (sample.size() < pie::hac::nca::kHeaderSize)
if (sample.size() < nn::hac::nca::kHeaderSize)
{
return false;
}
@ -1027,26 +911,26 @@ bool nstool::SettingsInitializer::determineValidNcaFromSample(const tc::ByteData
return false;
}
pie::hac::detail::aes128_xtskey_t key = opt.keybag.nca_header_key.get();
nn::hac::detail::aes128_xtskey_t key = opt.keybag.nca_header_key.get();
//fmt::print("NCA header key: {} {}\n", tc::cli::FormatUtil::formatBytesAsString(opt.keybag.nca_header_key.get()[0].data(), opt.keybag.nca_header_key.get()[0].size(), true, ""), tc::cli::FormatUtil::formatBytesAsString(opt.keybag.nca_header_key.get()[1].data(), opt.keybag.nca_header_key.get()[1].size(), true, ""));
// init aes-xts
tc::crypto::Aes128XtsEncryptor enc;
enc.initialize(key[0].data(), key[0].size(), key[1].data(), key[1].size(), pie::hac::nca::kSectorSize, false);
enc.initialize(key[0].data(), key[0].size(), key[1].data(), key[1].size(), nn::hac::nca::kSectorSize, false);
// decrypt main header
byte_t raw_hdr[pie::hac::nca::kSectorSize];
enc.decrypt(raw_hdr, sample.data() + pie::hac::ContentArchiveUtil::sectorToOffset(1), pie::hac::nca::kSectorSize, 1);
pie::hac::sContentArchiveHeader* hdr = (pie::hac::sContentArchiveHeader*)(raw_hdr);
byte_t raw_hdr[nn::hac::nca::kSectorSize];
enc.decrypt(raw_hdr, sample.data() + nn::hac::ContentArchiveUtil::sectorToOffset(1), nn::hac::nca::kSectorSize, 1);
nn::hac::sContentArchiveHeader* hdr = (nn::hac::sContentArchiveHeader*)(raw_hdr);
/*
fmt::print("NCA Header Raw:\n");
fmt::print("{:s}\n", tc::cli::FormatUtil::formatBytesAsHxdHexString(sample.data() + pie::hac::ContentArchiveUtil::sectorToOffset(1), pie::hac::nca::kSectorSize));
fmt::print("{:s}\n", tc::cli::FormatUtil::formatBytesAsHxdHexString(raw_hdr, pie::hac::nca::kSectorSize));
fmt::print("{:s}\n", tc::cli::FormatUtil::formatBytesAsHxdHexString(sample.data() + nn::hac::ContentArchiveUtil::sectorToOffset(1), nn::hac::nca::kSectorSize));
fmt::print("{:s}\n", tc::cli::FormatUtil::formatBytesAsHxdHexString(raw_hdr, nn::hac::nca::kSectorSize));
*/
if (hdr->st_magic.unwrap() != pie::hac::nca::kNca2StructMagic && hdr->st_magic.unwrap() != pie::hac::nca::kNca3StructMagic)
if (hdr->st_magic.unwrap() != nn::hac::nca::kNca2StructMagic && hdr->st_magic.unwrap() != nn::hac::nca::kNca3StructMagic)
{
return false;
}
@ -1056,12 +940,12 @@ bool nstool::SettingsInitializer::determineValidNcaFromSample(const tc::ByteData
bool nstool::SettingsInitializer::determineValidCnmtFromSample(const tc::ByteData& sample) const
{
if (sample.size() < sizeof(pie::hac::sContentMetaHeader))
if (sample.size() < sizeof(nn::hac::sContentMetaHeader))
return false;
const pie::hac::sContentMetaHeader* data = (const pie::hac::sContentMetaHeader*)sample.data();
const nn::hac::sContentMetaHeader* data = (const nn::hac::sContentMetaHeader*)sample.data();
size_t minimum_size = sizeof(pie::hac::sContentMetaHeader) + data->exhdr_size.unwrap() + data->content_count.unwrap() * sizeof(pie::hac::sContentInfo) + data->content_meta_count.unwrap() * sizeof(pie::hac::sContentMetaInfo) + pie::hac::cnmt::kDigestLen;
size_t minimum_size = sizeof(nn::hac::sContentMetaHeader) + data->exhdr_size.unwrap() + data->content_count.unwrap() * sizeof(nn::hac::sContentInfo) + data->content_meta_count.unwrap() * sizeof(nn::hac::sContentMetaInfo) + nn::hac::cnmt::kDigestLen;
if (sample.size() < minimum_size)
return false;
@ -1069,37 +953,37 @@ bool nstool::SettingsInitializer::determineValidCnmtFromSample(const tc::ByteDat
// include exthdr/data check if applicable
if (data->exhdr_size.unwrap() > 0)
{
if (data->type == (byte_t)pie::hac::cnmt::ContentMetaType_Application)
if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::Application)
{
const pie::hac::sApplicationMetaExtendedHeader* meta = (const pie::hac::sApplicationMetaExtendedHeader*)(sample.data() + sizeof(pie::hac::sContentMetaHeader));
const nn::hac::sApplicationMetaExtendedHeader* meta = (const nn::hac::sApplicationMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader));
if ((meta->patch_id.unwrap() & data->id.unwrap()) != data->id.unwrap())
return false;
}
else if (data->type == (byte_t)pie::hac::cnmt::ContentMetaType_Patch)
else if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::Patch)
{
const pie::hac::sPatchMetaExtendedHeader* meta = (const pie::hac::sPatchMetaExtendedHeader*)(sample.data() + sizeof(pie::hac::sContentMetaHeader));
const nn::hac::sPatchMetaExtendedHeader* meta = (const nn::hac::sPatchMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader));
if ((meta->application_id.unwrap() & data->id.unwrap()) != meta->application_id.unwrap())
return false;
minimum_size += meta->extended_data_size.unwrap();
}
else if (data->type == (byte_t)pie::hac::cnmt::ContentMetaType_AddOnContent)
else if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::AddOnContent)
{
const pie::hac::sAddOnContentMetaExtendedHeader* meta = (const pie::hac::sAddOnContentMetaExtendedHeader*)(sample.data() + sizeof(pie::hac::sContentMetaHeader));
const nn::hac::sAddOnContentMetaExtendedHeader* meta = (const nn::hac::sAddOnContentMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader));
if ((meta->application_id.unwrap() & data->id.unwrap()) != meta->application_id.unwrap())
return false;
}
else if (data->type == (byte_t)pie::hac::cnmt::ContentMetaType_Delta)
else if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::Delta)
{
const pie::hac::sDeltaMetaExtendedHeader* meta = (const pie::hac::sDeltaMetaExtendedHeader*)(sample.data() + sizeof(pie::hac::sContentMetaHeader));
const nn::hac::sDeltaMetaExtendedHeader* meta = (const nn::hac::sDeltaMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader));
if ((meta->application_id.unwrap() & data->id.unwrap()) != meta->application_id.unwrap())
return false;
minimum_size += meta->extended_data_size.unwrap();
}
else if (data->type == (byte_t)pie::hac::cnmt::ContentMetaType_SystemUpdate)
else if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::SystemUpdate)
{
const pie::hac::sSystemUpdateMetaExtendedHeader* meta = (const pie::hac::sSystemUpdateMetaExtendedHeader*)(sample.data() + sizeof(pie::hac::sContentMetaHeader));
const nn::hac::sSystemUpdateMetaExtendedHeader* meta = (const nn::hac::sSystemUpdateMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader));
minimum_size += meta->extended_data_size.unwrap();
}
@ -1113,12 +997,12 @@ bool nstool::SettingsInitializer::determineValidCnmtFromSample(const tc::ByteDat
bool nstool::SettingsInitializer::determineValidNacpFromSample(const tc::ByteData& sample) const
{
if (sample.size() != sizeof(pie::hac::sApplicationControlProperty))
if (sample.size() != sizeof(nn::hac::sApplicationControlProperty))
return false;
const pie::hac::sApplicationControlProperty* data = (const pie::hac::sApplicationControlProperty*)sample.data();
const nn::hac::sApplicationControlProperty* data = (const nn::hac::sApplicationControlProperty*)sample.data();
if (data->logo_type > (byte_t)pie::hac::nacp::LogoType_Nintendo)
if (data->logo_type > (byte_t)nn::hac::nacp::LogoType::Nintendo)
return false;
if (data->display_version[0] == 0)
@ -1138,7 +1022,7 @@ bool nstool::SettingsInitializer::determineValidNacpFromSample(const tc::ByteDat
bool nstool::SettingsInitializer::determineValidEsCertFromSample(const tc::ByteData& sample) const
{
pie::hac::es::SignatureBlock sign;
nn::pki::SignatureBlock sign;
try
{
@ -1152,7 +1036,7 @@ bool nstool::SettingsInitializer::determineValidEsCertFromSample(const tc::ByteD
if (sign.isLittleEndian() == true)
return false;
if (sign.getSignType() != pie::hac::es::sign::SIGN_ID_RSA4096_SHA256 && sign.getSignType() != pie::hac::es::sign::SIGN_ID_RSA2048_SHA256 && sign.getSignType() != pie::hac::es::sign::SIGN_ID_ECDSA240_SHA256)
if (sign.getSignType() != nn::pki::sign::SIGN_ID_RSA4096_SHA256 && sign.getSignType() != nn::pki::sign::SIGN_ID_RSA2048_SHA256 && sign.getSignType() != nn::pki::sign::SIGN_ID_ECDSA240_SHA256)
return false;
return true;
@ -1160,7 +1044,7 @@ bool nstool::SettingsInitializer::determineValidEsCertFromSample(const tc::ByteD
bool nstool::SettingsInitializer::determineValidEsTikFromSample(const tc::ByteData& sample) const
{
pie::hac::es::SignatureBlock sign;
nn::pki::SignatureBlock sign;
try
{
@ -1174,13 +1058,13 @@ bool nstool::SettingsInitializer::determineValidEsTikFromSample(const tc::ByteDa
if (sign.isLittleEndian() == false)
return false;
if (sign.getSignType() != pie::hac::es::sign::SIGN_ID_RSA2048_SHA256)
if (sign.getSignType() != nn::pki::sign::SIGN_ID_RSA2048_SHA256)
return false;
const pie::hac::es::sTicketBody_v2* body = (const pie::hac::es::sTicketBody_v2*)(sample.data() + sign.getBytes().size());
const nn::es::sTicketBody_v2* body = (const nn::es::sTicketBody_v2*)(sample.data() + sign.getBytes().size());
if ((body->issuer.decode().substr(0, 5) == "Root-"
&& body->issuer.decode().substr(16, 2) == "XS") == false)
if ((body->issuer.str().substr(0, 5) == "Root-"
&& body->issuer.str().substr(16, 2) == "XS") == false)
return false;
return true;

View file

@ -76,7 +76,6 @@ struct Settings
tc::Optional<tc::io::Path> part1_extract_path;
tc::Optional<tc::io::Path> part2_extract_path;
tc::Optional<tc::io::Path> part3_extract_path;
tc::Optional<tc::io::Path> base_nca_path;
} nca;
// KIP options
@ -111,8 +110,6 @@ struct Settings
kip.extract_path = tc::Optional<tc::io::Path>();
nca.base_nca_path = tc::Optional<tc::io::Path>();
aset.icon_extract_path = tc::Optional<tc::io::Path>();
aset.nacp_extract_path = tc::Optional<tc::io::Path>();
}
@ -136,15 +133,11 @@ private:
bool mVerbose;
tc::Optional<tc::io::Path> mKeysetPath;
tc::Optional<tc::io::Path> mTitleKeysetPath;
tc::Optional<KeyBag::aes128_key_t> mNcaEncryptedContentKey;
tc::Optional<KeyBag::aes128_key_t> mNcaContentKey;
std::vector<tc::io::Path> mTikPathList;
//tc::Optional<tc::io::Path> mTikPath;
tc::Optional<tc::io::Path> mTikPath;
tc::Optional<tc::io::Path> mCertPath;
void loadKeyFile(tc::Optional<tc::io::Path>& keyfile_path, const std::string& keyfile_name, const std::string& cli_hint);
bool determineValidNcaFromSample(const tc::ByteData& raw_data) const;
bool determineValidEsCertFromSample(const tc::ByteData& raw_data) const;
bool determineValidEsTikFromSample(const tc::ByteData& raw_data) const;

View file

@ -75,7 +75,6 @@ int umain(const std::vector<std::string>& args, const std::vector<std::string>&
nstool::NcaProcess obj;
obj.setInputFile(infile_stream);
obj.setBaseNcaPath(set.nca.base_nca_path);
obj.setKeyCfg(set.opt.keybag);
obj.setCliOutputMode(set.opt.cli_output_mode);
obj.setVerifyMode(set.opt.verify);

View file

@ -1,7 +1,7 @@
#pragma once
#define APP_NAME "NSTool"
#define BIN_NAME "nstool"
#define VER_MAJOR 0
#define VER_MINOR 0
#define VER_PATCH 0
#define VER_MAJOR 1
#define VER_MINOR 6
#define VER_PATCH 2
#define AUTHORS "jakcron"