Compare commits

...

58 commits

Author SHA1 Message Date
Jack cfb826ca6c Update libtoolchain to v0.8.0 (fixes VS dup issue) 2024-10-14 10:20:20 +09:00
jakcron cfadea2994 Fix bug where KeyAreaEncryptionKeys were not calcd 2024-09-22 23:46:52 +08:00
Jack 69a5f5ed2f update libpietendo to v0.8.0 2024-08-04 12:22:20 +08:00
Jack 8798776405
Merge pull request #112 from jakcron/feature-106-multipletickets
Add support for specifying multiple tickets / title keys
2024-01-20 14:01:37 +08:00
Jack 85dd51f496 Skip bad title.keys rows instead of throwing an exception. 2024-01-20 11:20:56 +08:00
Jack 811334bae5 Misc 2024-01-20 11:17:04 +08:00
Jack 1d680c2098 Update SWITCH_KEYS.md to indicate title.keys is now supported. 2024-01-20 11:16:25 +08:00
Jack e205cb6a4f Change --tik so that it can be invoked multiple times to specify a list of ticket files. Additionally added support for hactool title.keys 2024-01-01 13:22:39 +08:00
Jack 978899780c Test GH Actions tweaks 2023-12-31 22:21:35 +08:00
Jack 4922717ad0 Tweak GH Actions 2023-12-31 22:17:00 +08:00
Jack 17f9298c50 Update libpietendo v0.7.2 2023-12-31 22:11:41 +08:00
Jack 30c8751cfd Update libtoolchain to v0.7.0 2023-12-31 22:11:30 +08:00
Jack 0765ee5502 Update libmbedtls to v2.16.12 2023-12-31 22:10:50 +08:00
Jack 268f56b803 Update liblz4 to v1.9.4 2023-12-31 22:10:38 +08:00
Jack cf4d335be3 Update libfmt to 10.1.1 2023-12-31 19:17:57 +08:00
Jack 25850cd74b Test newer GH Actions Dependencies 2023-12-31 18:15:52 +08:00
Jack 705cf9b4f3 Update makefile to v9 2023-12-31 17:51:19 +08:00
Jack 0d248d1c8e #96 Add instructions for using git submodules 2023-12-31 14:24:19 +08:00
Jack c7fe8bcd0f Fixes #92, skip verifying SaveDataOwnerIdList against ACID as this is never populated. 2023-12-31 14:18:15 +08:00
Jack b4a86fc826 Update libpietendo to v0.7.1 2023-12-31 13:58:42 +08:00
Jack 7abcedb7e5 Fix formatting of NCA Key Area. 2023-05-13 16:45:01 +08:00
Jack bcd4df2eb4 Update libpietendo to v0.7.0 2023-05-13 16:44:46 +08:00
Jack 49e3729d95 Update GitHub actions to reflect new branch names. 2023-05-13 16:43:45 +08:00
Jack 8c284ba98a Reset version to v0.0.0 for development-tip branch. 2023-05-13 16:35:39 +08:00
Jack d87c0fcf1c
Merge pull request #89 from jakcron/v1.7-development
Update NSTool to v1.7.0
2023-01-21 23:14:26 +08:00
Jack e2245c2a9e Add explanation for how to extract Patch NCAs. 2023-01-21 23:05:38 +08:00
Jack 76f1f87c51 Bump version to v1.7.0 2023-01-21 22:51:46 +08:00
Jack 21e48a680b Update makefile to v8 2023-01-21 22:51:21 +08:00
Jack 9d7628a1c9 Fix compiling against libfmt 9.0.0 2023-01-21 22:51:11 +08:00
Jack 85a31c90af Update libtoolchain to v0.6.1 and libpietendo to v0.4.0 2023-01-21 22:43:22 +08:00
Jack 591b270ed4 Update libtoolchain to v0.6 & libfmt v9.0.0 2023-01-21 21:14:50 +08:00
Jack fbf62a4df2 Merge branch 'main' into v1.7-development 2023-01-21 20:42:49 +08:00
Jack df045b5dba Update dependencies 2023-01-21 20:39:18 +08:00
Jack 06b75b41cf [NcaProcess] Properly process HashType_None 2023-01-21 20:10:01 +08:00
Jack 1e81318d54 Add note for future work for compressed/sparse storage 2023-01-21 20:07:42 +08:00
Jack 605b5c70f9 Linting 2023-01-21 20:03:21 +08:00
Jack af41275c80 Add comments for the 3 reader streams in NcaProcess::sPartitionInfo 2023-01-21 19:49:15 +08:00
Jack ccd296d144 Update libpietendo to sagumamugas-bktr 2023-01-15 23:07:22 +08:00
Jack 21e1e33e55
Merge pull request #88 from sagumamugas/nca-patches
Support for nca patches
2023-01-15 22:58:28 +08:00
sagumamugas b5e3fb56b1 Support for nca patches 2023-01-12 23:33:08 +01:00
Jack 80cb738b5a NSTool v1.6.6 2022-11-27 12:37:19 +08:00
Jack 21f8c884f6
Merge pull request #87 from jakcron/v1.6-development
Bug fixes for v1.6
2022-11-27 12:36:31 +08:00
Jack b0a07c061a Fix issue where RomFs with no files could not be processed. 2022-11-27 12:26:44 +08:00
Jack 390b544059 Fixed XCI Header Hey selection. 2022-07-07 20:41:05 +08:00
Jack f17b57d2ed Merge branch 'v1.6-stable' fix URL typo for libpietendo repository 2022-07-02 11:22:33 +08:00
Jack 87459b6f8d Update URL for libpietendo repository 2022-07-02 11:21:31 +08:00
Jack e770a06ad4
Merge pull request #82 from jakcron/v1.6-development
Update NSTool to v1.6.5
2022-07-01 15:45:20 +08:00
Jakcron 26898c7fa3 Include refs to libpietendo in visual studio. 2022-07-01 15:32:50 +08:00
Jack cb46c7c7c3 Update github workflow 2022-06-30 18:41:13 +08:00
Jack 5c1bd2c786 Misc whitespace 2022-06-30 18:36:12 +08:00
Jack ffbcf736d2 Update libpietendo 2022-06-30 18:35:54 +08:00
Jack 4e8fb2d3e2 Bump NSTool version to v1.6.5 2022-06-29 21:20:06 +08:00
Jack 14caec3049 Port code to use new submodules. 2022-06-29 21:19:36 +08:00
Jack 15b082d9d2 Remove submodules for libnintendo* 2022-06-29 21:17:10 +08:00
Jack 10dd907c6e Remove libnintendo* add libpietendo, update libfmt & libtoolchain 2022-06-29 21:14:58 +08:00
Jack 04662e529f
Merge pull request #81 from jakcron/v1.6-stable
Update NSTool to v1.6.4
2022-04-10 15:52:05 +08:00
jakcron 88e56b600d bump version to v1.6.4 2022-04-10 15:42:20 +08:00
jakcron 64528a0956 Update libnintendo-hac(-hb) 2022-04-10 15:41:45 +08:00
56 changed files with 1092 additions and 883 deletions

View file

@ -1,10 +1,10 @@
name: Compile Master Branch
name: Compile Project (Push/PR/Release)
on:
push:
branches: [ master ]
branches: [ development-tip, stable ]
pull_request:
branches: [ master ]
branches: [ development-tip, stable ]
release:
types: [ created ]
@ -20,22 +20,25 @@ 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@v1
- uses: actions/checkout@v4
- 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@v2
- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.prog }}-${{ matrix.dist }}
path: ./bin/${{ matrix.prog }}
path: ./bin/${{ matrix.prog }}${{ matrix.bin_ext }}
build_visualstudio:
name: Compile ${{ matrix.prog }} for ${{ matrix.dist }}
runs-on: ${{ matrix.os }}
@ -49,21 +52,22 @@ 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@v1
- uses: actions/checkout@v4
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v1.1
uses: microsoft/setup-msbuild@v1.3
- 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@v2
- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.prog }}-${{ matrix.dist }}
path: .\build\visualstudio\${{ matrix.build_path }}\${{ matrix.prog }}.exe
path: .\build\visualstudio\${{ matrix.build_path }}\${{ matrix.prog }}${{ matrix.bin_ext }}

29
.gitmodules vendored
View file

@ -1,24 +1,15 @@
[submodule "deps/liblz4"]
path = deps/liblz4
url = https://github.com/jakcron/liblz4.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
url = https://github.com/jakcron/libmbedtls.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
[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

View file

@ -1,4 +1,13 @@
# 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,6 +143,16 @@ 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,4 +203,18 @@ 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
# 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
```

View file

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31229.75
# Visual Studio Version 17
VisualStudioVersion = 17.2.32616.157
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nstool", "nstool\nstool.vcxproj", "{775EF5EB-CA49-4994-8AC4-47B4A5385266}"
EndProject
@ -9,23 +9,14 @@ 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
@ -50,38 +41,6 @@ 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
@ -106,19 +65,24 @@ 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\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>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\include;$(SolutionDir)..\..\deps\liblz4\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libpietendo\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\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>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\include;$(SolutionDir)..\..\deps\liblz4\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libpietendo\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\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>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\include;$(SolutionDir)..\..\deps\liblz4\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libpietendo\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\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>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\include;$(SolutionDir)..\..\deps\liblz4\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libpietendo\include</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
@ -129,24 +129,15 @@
<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 53d084cc0c6ea61bbb535a873299b0ae5ff9a05d
Subproject commit b03b081e026ceb1226b45de926babe629d6c0688

2
deps/liblz4 vendored

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

2
deps/libmbedtls vendored

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

1
deps/libnintendo-es vendored

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

@ -1 +0,0 @@
Subproject commit 74168c5ecdd80eb9ce675e2b9c085ea8a09babb2

@ -1 +0,0 @@
Subproject commit 2d8917913216530c487363f17a4a3c808b54129d

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

1
deps/libpietendo vendored Submodule

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

2
deps/libtoolchain vendored

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

View file

@ -1,6 +1,6 @@
# C++/C Recursive Project Makefile
# (c) Jack
# Version 6 (20211110)
# Version 9 (20231231)
# Project Name
PROJECT_NAME = nstool
@ -23,16 +23,9 @@ 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 = 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
PROJECT_DEPEND = pietendo toolchain fmt lz4 mbedtls
PROJECT_DEPEND_LOCAL_DIR = libpietendo libtoolchain libfmt liblz4 libmbedtls
# Generate compiler flags for including project include path
ifneq ($(PROJECT_INCLUDE_PATH),)
@ -82,45 +75,47 @@ 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 -o
ARFLAGS = cr
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 -o
ARFLAGS = cr
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) $(WARNFLAGS) $(ARCHFLAGS) -fPIC
CFLAGS = -std=c11 $(INC) $(WARNFLAGS) $(ARCHFLAGS) -fPIC
CXXFLAGS = -std=c++11 $(INC) $(DEFINEFLAGS) $(WARNFLAGS) $(ARCHFLAGS) -fPIC
CFLAGS = -std=c11 $(INC) $(DEFINEFLAGS) $(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 static library
# - 'shared_lib' for building shared library
# - 'program' for building the program
# - 'static_lib' for building source as a static library
# - 'program' for building source as executable program
# - 'test_program' for building the test program
# These can typically be used together however *_lib and program should not be used together
# test_program can be used with program or static_lib, but program and static_lib cannot be used together
all: program
clean: clean_object_files remove_binary_dir
@ -158,10 +153,6 @@ 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(nn::hac::sAssetHeader)))
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(sizeof(pie::hac::sAssetHeader)))
{
throw tc::Exception(mModuleName, "Corrupt ASET: file too small");
}
tc::ByteData scratch = tc::ByteData(sizeof(nn::hac::sAssetHeader));
tc::ByteData scratch = tc::ByteData(sizeof(pie::hac::sAssetHeader));
mFile->seek(0, tc::io::SeekOrigin::Begin);
mFile->read(scratch.data(), scratch.size());
@ -85,10 +85,7 @@ void nstool::AssetProcess::processSections()
if ((mHdr.getIconInfo().size + mHdr.getIconInfo().offset) > file_size)
throw tc::Exception(mModuleName, "ASET geometry for icon beyond file size");
std::string icon_extract_path_str;
tc::io::PathUtil::pathToUnixUTF8(mIconExtractPath.get(), icon_extract_path_str);
fmt::print("Saving {:s}...", icon_extract_path_str);
fmt::print("Saving {:s}...", mIconExtractPath.get().to_string());
writeSubStreamToFile(mFile, mHdr.getIconInfo().offset, mHdr.getIconInfo().size, mIconExtractPath.get());
}
@ -99,6 +96,7 @@ 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 <nn/hac/AssetHeader.h>
#include <pietendo/hac/AssetHeader.h>
namespace nstool {
@ -33,7 +33,7 @@ private:
tc::Optional<tc::io::Path> mIconExtractPath;
tc::Optional<tc::io::Path> mNacpExtractPath;
nn::hac::AssetHeader mHdr;
pie::hac::AssetHeader mHdr;
NacpProcess mNacp;
RomfsProcess mRomfs;

View file

@ -1,6 +1,6 @@
#include "CnmtProcess.h"
#include <nn/hac/ContentMetaUtil.h>
#include <pietendo/hac/ContentMetaUtil.h>
nstool::CnmtProcess::CnmtProcess() :
mModuleName("nstool::CnmtProcess"),
@ -33,7 +33,7 @@ void nstool::CnmtProcess::setVerifyMode(bool verify)
mVerify = verify;
}
const nn::hac::ContentMeta& nstool::CnmtProcess::getContentMeta() const
const pie::hac::ContentMeta& nstool::CnmtProcess::getContentMeta() const
{
return mCnmt;
}
@ -67,11 +67,11 @@ void nstool::CnmtProcess::importCnmt()
void nstool::CnmtProcess::displayCnmt()
{
const nn::hac::sContentMetaHeader* cnmt_hdr = (const nn::hac::sContentMetaHeader*)mCnmt.getBytes().data();
const pie::hac::sContentMetaHeader* cnmt_hdr = (const pie::hac::sContentMetaHeader*)mCnmt.getBytes().data();
fmt::print("[ContentMeta]\n");
fmt::print(" TitleId: 0x{:016x}\n", mCnmt.getTitleId());
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(" 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(" 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(nn::hac::ContentMetaUtil::getContentMetaAttributeFlagAsString(nn::hac::cnmt::ContentMetaAttributeFlag(*itr)));
attribute_list.push_back(pie::hac::ContentMetaUtil::getContentMetaAttributeFlagAsString(pie::hac::cnmt::ContentMetaAttributeFlag(*itr)));
}
fmt::print(" [");
@ -95,28 +95,28 @@ void nstool::CnmtProcess::displayCnmt()
}
fmt::print("\n");
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());
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());
switch(mCnmt.getContentMetaType())
{
case (nn::hac::cnmt::ContentMetaType::Application):
case (pie::hac::cnmt::ContentMetaType_Application):
fmt::print(" ApplicationExtendedHeader:\n");
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(" 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(" PatchId: 0x{:016x}\n", mCnmt.getApplicationMetaExtendedHeader().getPatchId());
break;
case (nn::hac::cnmt::ContentMetaType::Patch):
case (pie::hac::cnmt::ContentMetaType_Patch):
fmt::print(" PatchMetaExtendedHeader:\n");
fmt::print(" RequiredSystemVersion: {:s} (v{:d})\n", nn::hac::ContentMetaUtil::getVersionAsString(mCnmt.getPatchMetaExtendedHeader().getRequiredSystemVersion()), mCnmt.getPatchMetaExtendedHeader().getRequiredSystemVersion());
fmt::print(" RequiredSystemVersion: {:s} (v{:d})\n", pie::hac::ContentMetaUtil::getVersionAsString(mCnmt.getPatchMetaExtendedHeader().getRequiredSystemVersion()), mCnmt.getPatchMetaExtendedHeader().getRequiredSystemVersion());
fmt::print(" ApplicationId: 0x{:016x}\n", mCnmt.getPatchMetaExtendedHeader().getApplicationId());
break;
case (nn::hac::cnmt::ContentMetaType::AddOnContent):
case (pie::hac::cnmt::ContentMetaType_AddOnContent):
fmt::print(" AddOnContentMetaExtendedHeader:\n");
fmt::print(" RequiredApplicationVersion: {:s} (v{:d})\n", nn::hac::ContentMetaUtil::getVersionAsString(mCnmt.getAddOnContentMetaExtendedHeader().getRequiredApplicationVersion()), mCnmt.getAddOnContentMetaExtendedHeader().getRequiredApplicationVersion());
fmt::print(" RequiredApplicationVersion: {:s} (v{:d})\n", pie::hac::ContentMetaUtil::getVersionAsString(mCnmt.getAddOnContentMetaExtendedHeader().getRequiredApplicationVersion()), mCnmt.getAddOnContentMetaExtendedHeader().getRequiredApplicationVersion());
fmt::print(" ApplicationId: 0x{:016x}\n", mCnmt.getAddOnContentMetaExtendedHeader().getApplicationId());
break;
case (nn::hac::cnmt::ContentMetaType::Delta):
case (pie::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 nn::hac::ContentInfo& info = mCnmt.getContentInfo()[i];
const pie::hac::ContentInfo& info = mCnmt.getContentInfo()[i];
fmt::print(" {:d}\n", i);
fmt::print(" Type: {:s} ({:d})\n", nn::hac::ContentMetaUtil::getContentTypeAsString(info.getContentType()), (uint32_t)info.getContentType());
fmt::print(" Type: {:s} ({:d})\n", pie::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() == nn::hac::cnmt::ContentMetaType::Patch && mCnmt.getPatchMetaExtendedHeader().getExtendedDataSize() != 0)
if (mCnmt.getContentMetaType() == pie::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() == nn::hac::cnmt::ContentMetaType::Delta && mCnmt.getDeltaMetaExtendedHeader().getExtendedDataSize() != 0)
else if (mCnmt.getContentMetaType() == pie::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() == nn::hac::cnmt::ContentMetaType::SystemUpdate && mCnmt.getSystemUpdateMetaExtendedHeader().getExtendedDataSize() != 0)
else if (mCnmt.getContentMetaType() == pie::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 nn::hac::ContentMetaInfo& content_meta_info, const std::string& prefix)
void nstool::CnmtProcess::displayContentMetaInfo(const pie::hac::ContentMetaInfo& content_meta_info, const std::string& prefix)
{
const nn::hac::sContentMetaInfo* content_meta_info_raw = (const nn::hac::sContentMetaInfo*)content_meta_info.getBytes().data();
const pie::hac::sContentMetaInfo* content_meta_info_raw = (const pie::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, 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}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}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 nn::hac::ContentMetaInfo&
for (auto itr = content_meta_info.getAttribute().begin(); itr != content_meta_info.getAttribute().end(); itr++)
{
attribute_list.push_back(nn::hac::ContentMetaUtil::getContentMetaAttributeFlagAsString(nn::hac::cnmt::ContentMetaAttributeFlag(*itr)));
attribute_list.push_back(pie::hac::ContentMetaUtil::getContentMetaAttributeFlagAsString(pie::hac::cnmt::ContentMetaAttributeFlag(*itr)));
}
fmt::print(" [");
@ -210,11 +210,11 @@ void nstool::CnmtProcess::displayContentMetaInfo(const nn::hac::ContentMetaInfo&
fmt::print("\n");
}
void nstool::CnmtProcess::displayContentMetaInfoList(const std::vector<nn::hac::ContentMetaInfo>& content_meta_info_list, const std::string& prefix)
void nstool::CnmtProcess::displayContentMetaInfoList(const std::vector<pie::hac::ContentMetaInfo>& content_meta_info_list, const std::string& prefix)
{
for (size_t i = 0; i < content_meta_info_list.size(); i++)
{
const nn::hac::ContentMetaInfo& info = mCnmt.getContentMetaInfo()[i];
const pie::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 <nn/hac/ContentMeta.h>
#include <pietendo/hac/ContentMeta.h>
namespace nstool {
@ -16,7 +16,7 @@ public:
void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify);
const nn::hac::ContentMeta& getContentMeta() const;
const pie::hac::ContentMeta& getContentMeta() const;
private:
std::string mModuleName;
@ -24,13 +24,13 @@ private:
CliOutputMode mCliOutputMode;
bool mVerify;
nn::hac::ContentMeta mCnmt;
pie::hac::ContentMeta mCnmt;
void importCnmt();
void displayCnmt();
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);
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);
};
}

View file

@ -2,7 +2,7 @@
#include "PkiValidator.h"
#include "util.h"
#include <nn/pki/SignUtils.h>
#include <pietendo/hac/es/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());
nn::pki::SignedData<nn::pki::CertificateBody> cert;
pie::hac::es::SignedData<pie::hac::es::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 nn::pki::SignedData<nn::pki::CertificateBody>& cert)
void nstool::EsCertProcess::displayCert(const pie::hac::es::SignedData<pie::hac::es::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})", cert.getSignature().getSignType(), getEndiannessStr(cert.getSignature().isLittleEndian()));
fmt::print(" (0x{:x}) ({:s})", (uint32_t)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})", cert.getBody().getPublicKeyType());
fmt::print(" ({:d})", (uint32_t)cert.getBody().getPublicKeyType());
fmt::print("\n");
fmt::print(" CertID: 0x{:x}\n", cert.getBody().getCertId());
if (cert.getBody().getPublicKeyType() == nn::pki::cert::RSA4096)
if (cert.getBody().getPublicKeyType() == pie::hac::es::cert::RSA4096)
{
fmt::print(" PublicKey:\n");
if (mCliOutputMode.show_extended_info)
@ -133,7 +133,7 @@ void nstool::EsCertProcess::displayCert(const nn::pki::SignedData<nn::pki::Certi
fmt::print(" {:s}\n", getTruncatedBytesString(cert.getBody().getRsa4096PublicKey().e.data(), cert.getBody().getRsa4096PublicKey().e.size()));
}
}
else if (cert.getBody().getPublicKeyType() == nn::pki::cert::RSA2048)
else if (cert.getBody().getPublicKeyType() == pie::hac::es::cert::RSA2048)
{
fmt::print(" PublicKey:\n");
if (mCliOutputMode.show_extended_info)
@ -151,7 +151,7 @@ void nstool::EsCertProcess::displayCert(const nn::pki::SignedData<nn::pki::Certi
fmt::print(" {:s}\n", getTruncatedBytesString(cert.getBody().getRsa2048PublicKey().e.data(), cert.getBody().getRsa2048PublicKey().e.size()));
}
}
else if (cert.getBody().getPublicKeyType() == nn::pki::cert::ECDSA240)
else if (cert.getBody().getPublicKeyType() == pie::hac::es::cert::ECDSA240)
{
fmt::print(" PublicKey:\n");
if (mCliOutputMode.show_extended_info)
@ -171,27 +171,27 @@ void nstool::EsCertProcess::displayCert(const nn::pki::SignedData<nn::pki::Certi
}
}
std::string nstool::EsCertProcess::getSignTypeStr(nn::pki::sign::SignatureId type) const
std::string nstool::EsCertProcess::getSignTypeStr(pie::hac::es::sign::SignatureId type) const
{
std::string str;
switch (type)
{
case (nn::pki::sign::SIGN_ID_RSA4096_SHA1):
case (pie::hac::es::sign::SIGN_ID_RSA4096_SHA1):
str = "RSA4096-SHA1";
break;
case (nn::pki::sign::SIGN_ID_RSA2048_SHA1):
case (pie::hac::es::sign::SIGN_ID_RSA2048_SHA1):
str = "RSA2048-SHA1";
break;
case (nn::pki::sign::SIGN_ID_ECDSA240_SHA1):
case (pie::hac::es::sign::SIGN_ID_ECDSA240_SHA1):
str = "ECDSA240-SHA1";
break;
case (nn::pki::sign::SIGN_ID_RSA4096_SHA256):
case (pie::hac::es::sign::SIGN_ID_RSA4096_SHA256):
str = "RSA4096-SHA256";
break;
case (nn::pki::sign::SIGN_ID_RSA2048_SHA256):
case (pie::hac::es::sign::SIGN_ID_RSA2048_SHA256):
str = "RSA2048-SHA256";
break;
case (nn::pki::sign::SIGN_ID_ECDSA240_SHA256):
case (pie::hac::es::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(nn::pki::cert::PublicKeyType type) const
std::string nstool::EsCertProcess::getPublicKeyTypeStr(pie::hac::es::cert::PublicKeyType type) const
{
std::string str;
switch (type)
{
case (nn::pki::cert::RSA4096):
case (pie::hac::es::cert::RSA4096):
str = "RSA4096";
break;
case (nn::pki::cert::RSA2048):
case (pie::hac::es::cert::RSA2048):
str = "RSA2048";
break;
case (nn::pki::cert::ECDSA240):
case (pie::hac::es::cert::ECDSA240):
str = "ECDSA240";
break;
default:

View file

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

View file

@ -1,7 +1,7 @@
#include "EsTikProcess.h"
#include "PkiValidator.h"
#include <nn/pki/SignUtils.h>
#include <pietendo/hac/es/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<nn::pki::SignedData<nn::pki::CertificateBody>>& certs)
void nstool::EsTikProcess::setCertificateChain(const std::vector<pie::hac::es::SignedData<pie::hac::es::CertificateBody>>& certs)
{
mCerts = certs;
}
@ -78,15 +78,15 @@ void nstool::EsTikProcess::verifyTicket()
PkiValidator pki_validator;
tc::ByteData tik_hash;
switch (nn::pki::sign::getHashAlgo(mTik.getSignature().getSignType()))
switch (pie::hac::es::sign::getHashAlgo(mTik.getSignature().getSignType()))
{
case (nn::pki::sign::HASH_ALGO_SHA1):
case (pie::hac::es::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 (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());
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());
break;
}
@ -104,24 +104,24 @@ void nstool::EsTikProcess::verifyTicket()
void nstool::EsTikProcess::displayTicket()
{
const nn::es::TicketBody_V2& body = mTik.getBody();
const pie::hac::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})", mTik.getSignature().getSignType());
fmt::print(" (0x{:x})", (uint32_t)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() == nn::es::ticket::RSA2048)
if (body.getTitleKeyEncType() == pie::hac::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() == nn::es::ticket::AES128_CBC)
else if (body.getTitleKeyEncType() == pie::hac::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)
{
nn::es::sTicketBody_v2* raw_body = (nn::es::sTicketBody_v2*)body.getBytes().data();
pie::hac::es::sTicketBody_v2* raw_body = (pie::hac::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 (nn::pki::sign::SIGN_ID_RSA4096_SHA1):
case (pie::hac::es::sign::SIGN_ID_RSA4096_SHA1):
str = "RSA4096-SHA1";
break;
case (nn::pki::sign::SIGN_ID_RSA2048_SHA1):
case (pie::hac::es::sign::SIGN_ID_RSA2048_SHA1):
str = "RSA2048-SHA1";
break;
case (nn::pki::sign::SIGN_ID_ECDSA240_SHA1):
case (pie::hac::es::sign::SIGN_ID_ECDSA240_SHA1):
str = "ECDSA240-SHA1";
break;
case (nn::pki::sign::SIGN_ID_RSA4096_SHA256):
case (pie::hac::es::sign::SIGN_ID_RSA4096_SHA256):
str = "RSA4096-SHA256";
break;
case (nn::pki::sign::SIGN_ID_RSA2048_SHA256):
case (pie::hac::es::sign::SIGN_ID_RSA2048_SHA256):
str = "RSA2048-SHA256";
break;
case (nn::pki::sign::SIGN_ID_ECDSA240_SHA256):
case (pie::hac::es::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 (nn::es::ticket::AES128_CBC):
case (pie::hac::es::ticket::AES128_CBC):
str = "Generic (AESCBC)";
break;
case (nn::es::ticket::RSA2048):
case (pie::hac::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 (nn::es::ticket::LICENSE_PERMANENT):
case (pie::hac::es::ticket::LICENSE_PERMANENT):
str = "Permanent";
break;
case (nn::es::ticket::LICENSE_DEMO):
case (pie::hac::es::ticket::LICENSE_DEMO):
str = "Demo";
break;
case (nn::es::ticket::LICENSE_TRIAL):
case (pie::hac::es::ticket::LICENSE_TRIAL):
str = "Trial";
break;
case (nn::es::ticket::LICENSE_RENTAL):
case (pie::hac::es::ticket::LICENSE_RENTAL):
str = "Rental";
break;
case (nn::es::ticket::LICENSE_SUBSCRIPTION):
case (pie::hac::es::ticket::LICENSE_SUBSCRIPTION):
str = "Subscription";
break;
case (nn::es::ticket::LICENSE_SERVICE):
case (pie::hac::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 (nn::es::ticket::FLAG_PRE_INSTALL):
case (pie::hac::es::ticket::FLAG_PRE_INSTALL):
str = "PreInstall";
break;
case (nn::es::ticket::FLAG_SHARED_TITLE):
case (pie::hac::es::ticket::FLAG_SHARED_TITLE):
str = "SharedTitle";
break;
case (nn::es::ticket::FLAG_ALLOW_ALL_CONTENT):
case (pie::hac::es::ticket::FLAG_ALLOW_ALL_CONTENT):
str = "AllContent";
break;
case (nn::es::ticket::FLAG_DEVICE_LINK_INDEPENDENT):
case (pie::hac::es::ticket::FLAG_DEVICE_LINK_INDEPENDENT):
str = "DeviceLinkIndependent";
break;
case (nn::es::ticket::FLAG_VOLATILE):
case (pie::hac::es::ticket::FLAG_VOLATILE):
str = "Volatile";
break;
case (nn::es::ticket::FLAG_ELICENSE_REQUIRED):
case (pie::hac::es::ticket::FLAG_ELICENSE_REQUIRED):
str = "ELicenseRequired";
break;
default:

View file

@ -2,9 +2,9 @@
#include "types.h"
#include "KeyBag.h"
#include <nn/pki/SignedData.h>
#include <nn/pki/CertificateBody.h>
#include <nn/es/TicketBody_V2.h>
#include <pietendo/hac/es/SignedData.h>
#include <pietendo/hac/es/CertificateBody.h>
#include <pietendo/hac/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<nn::pki::SignedData<nn::pki::CertificateBody>>& certs);
void setCertificateChain(const std::vector<pie::hac::es::SignedData<pie::hac::es::CertificateBody>>& certs);
void setCliOutputMode(CliOutputMode mode);
void setVerifyMode(bool verify);
private:
@ -28,9 +28,9 @@ private:
CliOutputMode mCliOutputMode;
bool mVerify;
std::vector<nn::pki::SignedData<nn::pki::CertificateBody>> mCerts;
std::vector<pie::hac::es::SignedData<pie::hac::es::CertificateBody>> mCerts;
nn::pki::SignedData<nn::es::TicketBody_V2> mTik;
pie::hac::es::SignedData<pie::hac::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::IStorage>& input_fs)
void nstool::FsProcess::setInputFileSystem(const std::shared_ptr<tc::io::IFileSystem>& input_fs)
{
mInputFs = input_fs;
}
@ -93,15 +93,12 @@ 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", path_str);
//fmt::print("Root Dir Virtual Path: \"{:s}\"\n", itr->virtual_path.to_string());
// root directory extract successful, continue to next job
continue;
@ -112,10 +109,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", path_str);
//fmt::print("Valid File Path: \"{:s}\"\n", itr->virtual_path.to_string());
// the output path for this file will depend on the user specified extract path
std::shared_ptr<tc::io::IStorage> local_fs = std::make_shared<tc::io::LocalStorage>(tc::io::LocalStorage());
std::shared_ptr<tc::io::IFileSystem> local_fs = std::make_shared<tc::io::LocalFileSystem>(tc::io::LocalFileSystem());
// case: the extract_path is a valid path to an existing directory
// behaviour: extract the file, preserving the original filename, to the specified directory
@ -127,10 +124,7 @@ void nstool::FsProcess::extractFs()
tc::io::Path file_extract_path = itr->extract_path + itr->virtual_path.back();
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);
fmt::print("Saving {:s}...\n", file_extract_path.to_string());
writeStreamToFile(file_stream, itr->extract_path + itr->virtual_path.back(), mDataCache);
@ -145,24 +139,18 @@ 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);
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);
fmt::print("Saving {:s} as {:s}...\n", itr->virtual_path.to_string(), itr->extract_path.to_string());
writeStreamToFile(file_stream, itr->extract_path, mDataCache);
@ -173,9 +161,7 @@ void nstool::FsProcess::extractFs()
// extract path could not be determined, inform the user and skip this job
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);
fmt::print("[WARNING] Extract path was invalid, and was skipped: {:s}\n", itr->extract_path.to_string());
continue;
} catch (tc::io::FileNotFoundException&) {
// acceptable exception, just means file didn't exist
@ -186,10 +172,9 @@ 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", path_str);
//fmt::print("Valid Directory Path: \"{:s}\"\n", itr->virtual_path.to_string());
// directory extract successful, continue to next job
continue;
@ -198,14 +183,14 @@ void nstool::FsProcess::extractFs()
// acceptable exception, just means directory didn't exist
}
fmt::print("[WARNING] Failed to extract virtual path: \"{:s}\"\n", path_str);
fmt::print("[WARNING] Failed to extract virtual path: \"{:s}\"\n", itr->virtual_path.to_string());
}
}
void nstool::FsProcess::visitDir(const tc::io::Path& v_path, const tc::io::Path& l_path, bool extract_fs, bool print_fs)
{
tc::io::LocalStorage local_fs;
tc::io::LocalFileSystem local_fs;
// get listing for directory
tc::io::sDirectoryListing info;
@ -227,7 +212,6 @@ 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++)
@ -242,9 +226,8 @@ 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_str);
fmt::print("Saving {:s}...\n", out_path.to_string());
// 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::IStorage>& input_fs);
void setInputFileSystem(const std::shared_ptr<tc::io::IFileSystem>& 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::IStorage> mInputFs;
std::shared_ptr<tc::io::IFileSystem> mInputFs;
// fs info
tc::Optional<std::string> mFsFormatName;

View file

@ -3,11 +3,11 @@
#include <tc/crypto.h>
#include <tc/io/IOUtil.h>
#include <nn/hac/GameCardUtil.h>
#include <nn/hac/ContentMetaUtil.h>
#include <nn/hac/ContentArchiveUtil.h>
#include <pietendo/hac/GameCardUtil.h>
#include <pietendo/hac/ContentMetaUtil.h>
#include <pietendo/hac/ContentArchiveUtil.h>
#include <nn/hac/GameCardFsMetaGenerator.h>
#include <pietendo/hac/GameCardFsSnapshotGenerator.h>
#include "FsProcess.h"
@ -16,10 +16,12 @@ nstool::GameCardProcess::GameCardProcess() :
mFile(),
mCliOutputMode(true, false, false, false),
mVerify(false),
mListFs(false),
mIsTrueSdkXci(false),
mIsSdkXciEncrypted(false),
mGcHeaderOffset(0),
mProccessExtendedHeader(false),
mRootPfs(),
mExtractJobs()
mFileSystem(),
mFsProcess()
{
}
@ -59,14 +61,14 @@ void nstool::GameCardProcess::setVerifyMode(bool verify)
mVerify = verify;
}
void nstool::GameCardProcess::setExtractJobs(const std::vector<nstool::ExtractJob> extract_jobs)
{
mExtractJobs = extract_jobs;
}
void nstool::GameCardProcess::setShowFsTree(bool show_fs_tree)
{
mListFs = show_fs_tree;
mFsProcess.setShowFsTree(show_fs_tree);
}
void nstool::GameCardProcess::setExtractJobs(const std::vector<nstool::ExtractJob> extract_jobs)
{
mFsProcess.setExtractJobs(extract_jobs);
}
void nstool::GameCardProcess::importHeader()
@ -81,25 +83,25 @@ void nstool::GameCardProcess::importHeader()
}
// check stream is large enough for header
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(sizeof(nn::hac::sSdkGcHeader)))
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(sizeof(pie::hac::sSdkGcHeader)))
{
throw tc::Exception(mModuleName, "Corrupt GameCard Image: File too small.");
}
// allocate memory for header
tc::ByteData scratch = tc::ByteData(sizeof(nn::hac::sSdkGcHeader));
tc::ByteData scratch = tc::ByteData(sizeof(pie::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 (((nn::hac::sSdkGcHeader*)scratch.data())->signed_header.header.st_magic.unwrap() == nn::hac::gc::kGcHeaderStructMagic)
if (((pie::hac::sSdkGcHeader*)scratch.data())->signed_header.header.st_magic.unwrap() == pie::hac::gc::kGcHeaderStructMagic)
{
mIsTrueSdkXci = true;
mGcHeaderOffset = sizeof(nn::hac::sGcKeyDataRegion);
mGcHeaderOffset = sizeof(pie::hac::sGcKeyDataRegion);
}
else if (((nn::hac::sGcHeader_Rsa2048Signed*)scratch.data())->header.st_magic.unwrap() == nn::hac::gc::kGcHeaderStructMagic)
else if (((pie::hac::sGcHeader_Rsa2048Signed*)scratch.data())->header.st_magic.unwrap() == pie::hac::gc::kGcHeaderStructMagic)
{
mIsTrueSdkXci = false;
mGcHeaderOffset = 0;
@ -109,33 +111,33 @@ void nstool::GameCardProcess::importHeader()
throw tc::Exception(mModuleName, "Corrupt GameCard Image: Unexpected magic bytes.");
}
nn::hac::sGcHeader_Rsa2048Signed* hdr_ptr = (nn::hac::sGcHeader_Rsa2048Signed*)(scratch.data() + mGcHeaderOffset);
pie::hac::sGcHeader_Rsa2048Signed* hdr_ptr = (pie::hac::sGcHeader_Rsa2048Signed*)(scratch.data() + mGcHeaderOffset);
// generate hash of raw header
tc::crypto::GenerateSha256Hash(mHdrHash.data(), (byte_t*)&hdr_ptr->header, sizeof(nn::hac::sGcHeader));
tc::crypto::GenerateSha2256Hash(mHdrHash.data(), (byte_t*)&hdr_ptr->header, sizeof(pie::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 & 7;
byte_t xci_header_key_index = hdr_ptr->header.key_flag & 0xf;
if (mKeyCfg.xci_header_key.find(xci_header_key_index) != mKeyCfg.xci_header_key.end())
{
nn::hac::GameCardUtil::decryptXciHeader(&hdr_ptr->header, mKeyCfg.xci_header_key[xci_header_key_index].data());
pie::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(nn::hac::sGcHeader));
mHdr.fromBytes((byte_t*)&hdr_ptr->header, sizeof(pie::hac::sGcHeader));
}
void nstool::GameCardProcess::displayHeader()
{
const nn::hac::sGcHeader* raw_hdr = (const nn::hac::sGcHeader*)mHdr.getBytes().data();
const pie::hac::sGcHeader* raw_hdr = (const pie::hac::sGcHeader*)mHdr.getBytes().data();
fmt::print("[GameCard/Header]\n");
fmt::print(" CardHeaderVersion: {:d}\n", mHdr.getCardHeaderVersion());
fmt::print(" RomSize: {:s}", nn::hac::GameCardUtil::getRomSizeAsString((nn::hac::gc::RomSize)mHdr.getRomSizeType()));
fmt::print(" RomSize: {:s}", pie::hac::GameCardUtil::getRomSizeAsString((pie::hac::gc::RomSize)mHdr.getRomSizeType()));
if (mCliOutputMode.show_extended_info)
fmt::print(" (0x{:x})", mHdr.getRomSizeType());
fmt::print("\n");
@ -143,13 +145,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", nn::hac::GameCardUtil::getHeaderFlagsAsString((nn::hac::gc::HeaderFlags)*itr));
fmt::print(" {:s}\n", pie::hac::GameCardUtil::getHeaderFlagsAsString((pie::hac::gc::HeaderFlags)*itr));
}
if (mCliOutputMode.show_extended_info)
{
fmt::print(" KekIndex: {:s} ({:d})\n", nn::hac::GameCardUtil::getKekIndexAsString((nn::hac::gc::KekIndex)mHdr.getKekIndex()), mHdr.getKekIndex());
fmt::print(" KekIndex: {:s} ({:d})\n", pie::hac::GameCardUtil::getKekIndexAsString((pie::hac::gc::KekIndex)mHdr.getKekIndex()), mHdr.getKekIndex());
fmt::print(" TitleKeyDecIndex: {:d}\n", mHdr.getTitleKeyDecIndex());
fmt::print(" InitialData:\n");
fmt::print(" Hash:\n");
@ -167,22 +169,22 @@ void nstool::GameCardProcess::displayHeader()
{
fmt::print(" RomAreaStartPage: 0x{:x}", mHdr.getRomAreaStartPage());
if (mHdr.getRomAreaStartPage() != (uint32_t)(-1))
fmt::print(" (0x{:x})", nn::hac::GameCardUtil::blockToAddr(mHdr.getRomAreaStartPage()));
fmt::print(" (0x{:x})", pie::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})", nn::hac::GameCardUtil::blockToAddr(mHdr.getBackupAreaStartPage()));
fmt::print(" (0x{:x})", pie::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})", nn::hac::GameCardUtil::blockToAddr(mHdr.getValidDataEndPage()));
fmt::print(" (0x{:x})", pie::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})", nn::hac::GameCardUtil::blockToAddr(mHdr.getLimAreaPage()));
fmt::print(" (0x{:x})", pie::hac::GameCardUtil::blockToAddr(mHdr.getLimAreaPage()));
fmt::print("\n");
fmt::print(" PartitionFs Header:\n");
@ -199,17 +201,17 @@ void nstool::GameCardProcess::displayHeader()
if (mProccessExtendedHeader)
{
fmt::print("[GameCard/ExtendedHeader]\n");
fmt::print(" FwVersion: v{:d} ({:s})\n", mHdr.getFwVersion(), nn::hac::GameCardUtil::getCardFwVersionDescriptionAsString((nn::hac::gc::FwVersion)mHdr.getFwVersion()));
fmt::print(" FwVersion: v{:d} ({:s})\n", mHdr.getFwVersion(), pie::hac::GameCardUtil::getCardFwVersionDescriptionAsString((pie::hac::gc::FwVersion)mHdr.getFwVersion()));
fmt::print(" AccCtrl1: 0x{:x}\n", mHdr.getAccCtrl1());
fmt::print(" CardClockRate: {:s}\n", nn::hac::GameCardUtil::getCardClockRateAsString((nn::hac::gc::CardClockRate)mHdr.getAccCtrl1()));
fmt::print(" CardClockRate: {:s}\n", pie::hac::GameCardUtil::getCardClockRateAsString((pie::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", 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(" 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(" Update Partition Info:\n");
fmt::print(" CUP Version: {:s} (v{:d})\n", nn::hac::ContentMetaUtil::getVersionAsString(mHdr.getUppVersion()), mHdr.getUppVersion());
fmt::print(" CUP Version: {:s} (v{:d})\n", pie::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, ""));
}
@ -223,14 +225,14 @@ bool nstool::GameCardProcess::validateRegionOfFile(int64_t offset, int64_t len,
mFile->read(scratch.data(), scratch.size());
// update hash
tc::crypto::Sha256Generator sha256_gen;
tc::crypto::Sha2256Generator sha256_gen;
sha256_gen.initialize();
sha256_gen.update(scratch.data(), scratch.size());
if (use_salt)
sha256_gen.update(&salt, sizeof(salt));
// calculate hash
nn::hac::detail::sha256_hash_t calc_hash;
pie::hac::detail::sha256_hash_t calc_hash;
sha256_gen.getHash(calc_hash.data());
return memcmp(calc_hash.data(), test_hash, calc_hash.size()) == 0;
@ -245,7 +247,7 @@ void nstool::GameCardProcess::validateXciSignature()
{
if (mKeyCfg.xci_header_sign_key.isSet())
{
if (tc::crypto::VerifyRsa2048Pkcs1Sha256(mHdrSignature.data(), mHdrHash.data(), mKeyCfg.xci_header_sign_key.get()) == false)
if (tc::crypto::VerifyRsa2048Pkcs1Sha2256(mHdrSignature.data(), mHdrHash.data(), mKeyCfg.xci_header_sign_key.get()) == false)
{
fmt::print("[WARNING] GameCard Header Signature: FAIL\n");
}
@ -258,29 +260,24 @@ void nstool::GameCardProcess::validateXciSignature()
void nstool::GameCardProcess::processRootPfs()
{
if (mVerify && validateRegionOfFile(mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize(), mHdr.getPartitionFsHash().data(), mHdr.getCompatibilityType() != nn::hac::gc::COMPAT_GLOBAL, mHdr.getCompatibilityType()) == false)
if (mVerify && validateRegionOfFile(mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize(), mHdr.getPartitionFsHash().data(), mHdr.getCompatibilityType() != pie::hac::gc::CompatibilityType_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(), nn::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(), pie::hac::GameCardUtil::blockToAddr(mHdr.getValidDataEndPage()+1) - mHdr.getPartitionFsAddress()));
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) );
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) );
FsProcess fs_proc;
fs_proc.setInputFileSystem(gc_vfs);
fs_proc.setFsFormatName("PartitionFs");
fs_proc.setFsProperties({
mFsProcess.setInputFileSystem(mFileSystem);
mFsProcess.setFsFormatName("PartitionFs");
mFsProcess.setFsProperties({
fmt::format("Type: Nested HFS0"),
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())
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())
});
fs_proc.setShowFsInfo(mCliOutputMode.show_basic_info);
fs_proc.setShowFsTree(mListFs);
fs_proc.setFsRootLabel(kXciMountPointName);
fs_proc.setExtractJobs(mExtractJobs);
fs_proc.process();
mFsProcess.setShowFsInfo(mCliOutputMode.show_basic_info);
mFsProcess.setFsRootLabel(kXciMountPointName);
mFsProcess.process();
}

View file

@ -3,7 +3,7 @@
#include "KeyBag.h"
#include "PfsProcess.h"
#include <nn/hac/GameCardHeader.h>
#include <pietendo/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;
nn::hac::detail::rsa2048_signature_t mHdrSignature;
nn::hac::detail::sha256_hash_t mHdrHash;
nn::hac::GameCardHeader mHdr;
pie::hac::detail::rsa2048_signature_t mHdrSignature;
pie::hac::detail::sha256_hash_t mHdrHash;
pie::hac::GameCardHeader mHdr;
PfsProcess mRootPfs;
std::vector<nstool::ExtractJob> mExtractJobs;
// fs processing
std::shared_ptr<tc::io::IFileSystem> mFileSystem;
FsProcess mFsProcess;
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(nn::hac::sIniHeader))
if (tc::io::IOUtil::castInt64ToSize(mFile->length()) < sizeof(pie::hac::sIniHeader))
{
throw tc::Exception(mModuleName, "Corrupt INI: file too small.");
}
// read ini
tc::ByteData scratch = tc::ByteData(sizeof(nn::hac::sIniHeader));
tc::ByteData scratch = tc::ByteData(sizeof(pie::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(nn::hac::sIniHeader));
int64_t kip_pos = tc::io::IOUtil::castSizeToInt64(sizeof(pie::hac::sIniHeader));
int64_t kip_size = 0;
// tmp data to determine size
nn::hac::sKipHeader hdr_raw;
nn::hac::KernelInitialProcessHeader hdr;
pie::hac::sKipHeader hdr_raw;
pie::hac::KernelInitialProcessHeader hdr;
for (size_t i = 0; i < mHdr.getKipNum(); i++)
{
@ -121,12 +121,11 @@ void nstool::IniProcess::extractKipList()
tc::ByteData cache = tc::ByteData(kCacheSize);
// make extract dir
tc::io::LocalStorage local_fs;
tc::io::LocalFileSystem 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++)
@ -134,17 +133,15 @@ 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_str);
fmt::print("Saving {:s}...\n", out_path.to_string());
writeStreamToFile(itr->stream, out_path, cache);
}
}
int64_t nstool::IniProcess::getKipSizeFromHeader(const nn::hac::KernelInitialProcessHeader& hdr) const
int64_t nstool::IniProcess::getKipSizeFromHeader(const pie::hac::KernelInitialProcessHeader& hdr) const
{
// the order of elements in a KIP are sequential, there are no file offsets
return int64_t(sizeof(nn::hac::sKipHeader)) + int64_t(hdr.getTextSegmentInfo().file_layout.size + hdr.getRoSegmentInfo().file_layout.size + hdr.getDataSegmentInfo().file_layout.size);
return int64_t(sizeof(pie::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 <nn/hac/IniHeader.h>
#include <nn/hac/KernelInitialProcessHeader.h>
#include <pietendo/hac/IniHeader.h>
#include <pietendo/hac/KernelInitialProcessHeader.h>
namespace nstool {
@ -29,10 +29,10 @@ private:
tc::Optional<tc::io::Path> mKipExtractPath;
nn::hac::IniHeader mHdr;
pie::hac::IniHeader mHdr;
struct InnerKipInfo
{
nn::hac::KernelInitialProcessHeader hdr;
pie::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 nn::hac::KernelInitialProcessHeader& hdr) const;
int64_t getKipSizeFromHeader(const pie::hac::KernelInitialProcessHeader& hdr) const;
};
}

View file

@ -3,28 +3,33 @@
#include "util.h"
#include <tc/cli/FormatUtil.h>
#include <nn/hac/define/types.h>
#include <nn/hac/define/gc.h>
#include <nn/hac/AesKeygen.h>
#include <pietendo/hac/define/types.h>
#include <pietendo/hac/define/gc.h>
#include <pietendo/hac/AesKeygen.h>
#include <nn/pki/SignUtils.h>
#include <nn/pki/SignedData.h>
#include <nn/pki/CertificateBody.h>
#include <nn/es/TicketBody_V2.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>
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)
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)
{
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.isSet())
if (!tik_path_list.empty())
{
importTicket(tik_path.get());
for (auto itr = tik_path_list.begin(); itr != tik_path_list.end(); itr++)
importTicket(*itr);
}
// this will populate known keys if they aren't supplied by the user provided keyfiles.
@ -352,7 +357,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 ? nn::hac::gc::KEK_DEV : nn::hac::gc::KEK_PROD]);
_SAVE_AES128KEY(fmt::format("{:s}_{:s}", kXciHeaderBase[name_idx], kKeyStr), xci_header_key[isDev ? pie::hac::gc::KekIndex_Dev : pie::hac::gc::KekIndex_Prod]);
// xci header sign key
//fmt::print("{:s}_{:s}_{:s}\n", kXciHeaderBase[name_idx], kSignKey, kPrivateStr);
@ -404,22 +409,22 @@ void nstool::KeyBagInitializer::importBaseKeyFile(const tc::io::Path& keyfile_pa
if (nca_header_key.isNull())
{
aes128_key_t nca_header_kek_tmp;
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());
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());
aes128_xtskey_t nca_header_key_tmp;
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());
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());
nca_header_key = nca_header_key_tmp;
}
}
for (size_t keak_idx = 0; keak_idx < nn::hac::nca::kKeyAreaEncryptionKeyNum; keak_idx++)
for (size_t keak_idx = 0; keak_idx < pie::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;
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());
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());
nca_key_area_encryption_key[keak_idx][itr->first] = nca_key_area_encryption_key_tmp;
}
}
@ -427,13 +432,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;
nn::hac::AesKeygen::generateKey(etik_common_key_tmp.data(), ticket_titlekek_source.get().data(), itr->second.data());
pie::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;
nn::hac::AesKeygen::generateKey(pkg2_key_tmp.data(), package2_key_source.get().data(), itr->second.data());
pie::hac::AesKeygen::generateKey(pkg2_key_tmp.data(), package2_key_source.get().data(), itr->second.data());
pkg2_key[itr->first] = pkg2_key_tmp;
}
}
@ -441,28 +446,58 @@ 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(), nn::pki::sign::SIGN_ALGO_RSA4096, pki_root_sign_key.get() };
broadon_signer["Root"] = { tc::ByteData(), pie::hac::es::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_str, e.error());
fmt::print("[WARNING] Failed to open certificate file \"{:s}\" ({:s}).\n", cert_path.to_string(), e.error());
return;
}
@ -470,7 +505,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_str);
fmt::print("[WARNING] Certificate file \"{:s}\" was too large.\n", cert_path.to_string());
return;
}
@ -479,7 +514,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());
nn::pki::SignedData<nn::pki::CertificateBody> cert;
pie::hac::es::SignedData<pie::hac::es::CertificateBody> cert;
try {
for (size_t f_pos = 0; f_pos < cert_raw.size(); f_pos += cert.getBytes().size())
{
@ -488,14 +523,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 nn::pki::cert::PublicKeyType::RSA2048:
broadon_signer[cert_identity] = { cert.getBytes(), nn::pki::sign::SIGN_ALGO_RSA2048, cert.getBody().getRsa2048PublicKey() };
case pie::hac::es::cert::PublicKeyType::RSA2048:
broadon_signer[cert_identity] = { cert.getBytes(), pie::hac::es::sign::SIGN_ALGO_RSA2048, cert.getBody().getRsa2048PublicKey() };
break;
case nn::pki::cert::PublicKeyType::RSA4096:
broadon_signer[cert_identity] = { cert.getBytes(), nn::pki::sign::SIGN_ALGO_RSA4096, cert.getBody().getRsa4096PublicKey() };
case pie::hac::es::cert::PublicKeyType::RSA4096:
broadon_signer[cert_identity] = { cert.getBytes(), pie::hac::es::sign::SIGN_ALGO_RSA4096, cert.getBody().getRsa4096PublicKey() };
break;
case nn::pki::cert::PublicKeyType::ECDSA240:
// broadon_signer[cert_identity] = { cert.getBytes(), nn::pki::sign::SIGN_ALGO_ECDSA240, cert.getBody().getRsa4096PublicKey() };
case pie::hac::es::cert::PublicKeyType::ECDSA240:
// broadon_signer[cert_identity] = { cert.getBytes(), pie::hac::es::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:
@ -504,24 +539,20 @@ 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_str, e.error());
fmt::print("[WARNING] Certificate file \"{:s}\" is corrupted ({:s}).\n", cert_path.to_string(), 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_str, e.error());
fmt::print("[WARNING] Failed to open ticket \"{:s}\" ({:s}).\n", tik_path.to_string(), e.error());
return;
}
@ -529,7 +560,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_str);
fmt::print("[WARNING] Ticket \"{:s}\" was too large.\n", tik_path.to_string());
return;
}
@ -538,7 +569,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());
nn::pki::SignedData<nn::es::TicketBody_V2> tik;
pie::hac::es::SignedData<pie::hac::es::TicketBody_V2> tik;
try {
// de serialise ticket
tik.fromBytes(tik_raw.data(), tik_raw.size());
@ -548,7 +579,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() != nn::es::ticket::AES128_CBC)
if (tik.getBody().getTitleKeyEncType() != pie::hac::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;
@ -559,10 +590,7 @@ 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
if (fallback_enc_content_key.isNull())
{
fallback_enc_content_key = enc_title_key;
}
external_enc_content_keys[rights_id] = enc_title_key;
// determine key to decrypt title key
byte_t common_key_index = tik.getBody().getCommonKeyId();
@ -577,7 +605,7 @@ void nstool::KeyBagInitializer::importTicket(const tc::io::Path& tik_path)
}
// convert key_generation
common_key_index = nn::hac::AesKeygen::getMasterKeyRevisionFromKeyGeneration(common_key_index);
common_key_index = pie::hac::AesKeygen::getMasterKeyRevisionFromKeyGeneration(common_key_index);
if (etik_common_key.find(common_key_index) == etik_common_key.end())
{
@ -589,19 +617,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 key dict
// add to decrypted 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_str, e.error());
fmt::print("[WARNING] Ticket \"{:s}\" is corrupted ({:s}).\n", tik_path.to_string(), e.error());
return;
}
}
void nstool::KeyBagInitializer::importKnownKeys(bool isDev)
{
static const nn::hac::detail::rsa2048_block_t kXciHeaderSignModulus = {
static const pie::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,
@ -620,7 +648,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 nn::hac::detail::rsa2048_block_t kXciCertSignModulus = {
static const pie::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,
@ -641,7 +669,7 @@ void nstool::KeyBagInitializer::importKnownKeys(bool isDev)
/* Keydata for very early beta NCA0 archives' RSA-OAEP. */
/*
static const nn::hac::detail::rsa2048_block_t beta_nca0_modulus = {
static const pie::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,
@ -660,7 +688,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 nn::hac::detail::sha256_hash_t beta_nca0_label_hash = {
static const pie::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
};
@ -668,10 +696,10 @@ void nstool::KeyBagInitializer::importKnownKeys(bool isDev)
struct sRsaKeyForGeneration {
byte_t generation;
nn::hac::detail::rsa2048_block_t modulus;
pie::hac::detail::rsa2048_block_t modulus;
};
static const nn::hac::detail::rsa2048_block_t kProdPackage2HeaderModulus = {
static const pie::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,
@ -774,7 +802,7 @@ void nstool::KeyBagInitializer::importKnownKeys(bool isDev)
},
};
static const nn::hac::detail::rsa2048_block_t kDevPackage2HeaderModulus = {
static const pie::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,
@ -880,7 +908,7 @@ void nstool::KeyBagInitializer::importKnownKeys(bool isDev)
struct sBroadOnRsaKeyAndCert
{
std::string issuer;
nn::pki::sign::SignatureAlgo key_type;
pie::hac::es::sign::SignatureAlgo key_type;
tc::ByteData modulus;
tc::ByteData certificate;
};
@ -889,31 +917,31 @@ void nstool::KeyBagInitializer::importKnownKeys(bool isDev)
{
{
"Root",
nn::pki::sign::SIGN_ALGO_RSA4096,
pie::hac::es::sign::SIGN_ALGO_RSA4096,
tc::cli::FormatUtil::hexStringToBytes("F8246C58BAE7500301FBB7C2EBE0010571DA922378F0514EC0031DD0D21ED3D07EFC852069B5DE9BB951A8BC90A244926D379295AE9436AAA6A302510C7B1DEDD5FB20869D7F3016F6BE65D383A16DB3321B95351890B17002937EE193F57E99A2474E9D3824C7AEE38541F567E7518C7A0E38E7EBAF41191BCFF17B42A6B4EDE6CE8DE7318F7F5204B3990E226745AFD485B24493008B08C7F6B7E56B02B3E8FE0C9D859CB8B68223B8AB27EE5F6538078B2DB91E2A153E85818072A23B6DD93281054F6FB0F6F5AD283ECA0B7AF35455E03DA7B68326F3EC834AF314048AC6DF20D28508673CAB62A2C7BC131A533E0B66806B1C30664B372331BDC4B0CAD8D11EE7BBD9285548AAEC1F66E821B3C8A0476900C5E688E80CCE3C61D69CBBA137C6604F7A72DD8C7B3E3D51290DAA6A597B081F9D3633A3467A356109ACA7DD7D2E2FB2C1AEB8E20F4892D8B9F8B46F4E3C11F4F47D8B757DFEFEA3899C33595C5EFDEBCBABE8413E3A9A803C69356EB2B2AD5CC4C858455EF5F7B30644B47C64068CDF809F76025A2DB446E03D7CF62F34E702457B02A4CF5D9DD53CA53A7CA629788C67CA08BFECCA43A957AD16C94E1CD875CA107DCE7E0118F0DF6BFEE51DDBD991C26E60CD4858AA592C820075F29F526C917C6FE5403EA7D4A50CEC3B7384DE886E82D2EB4D4E42B5F2B149A81EA7CE7144DC2994CFC44E1F91CBD495"),
tc::ByteData()
},
{
"Root-CA00000003",
nn::pki::sign::SIGN_ALGO_RSA2048,
pie::hac::es::sign::SIGN_ALGO_RSA2048,
tc::cli::FormatUtil::hexStringToBytes("B279C9E2EEE121C6EAF44FF639F88F078B4B77ED9F9560B0358281B50E55AB721115A177703C7A30FE3AE9EF1C60BC1D974676B23A68CC04B198525BC968F11DE2DB50E4D9E7F071E562DAE2092233E9D363F61DD7C19FF3A4A91E8F6553D471DD7B84B9F1B8CE7335F0F5540563A1EAB83963E09BE901011F99546361287020E9CC0DAB487F140D6626A1836D27111F2068DE4772149151CF69C61BA60EF9D949A0F71F5499F2D39AD28C7005348293C431FFBD33F6BCA60DC7195EA2BCC56D200BAF6D06D09C41DB8DE9C720154CA4832B69C08C69CD3B073A0063602F462D338061A5EA6C915CD5623579C3EB64CE44EF586D14BAAA8834019B3EEBEED379"),
tc::cli::FormatUtil::hexStringToBytes("00010003704138EFBBBDA16A987DD901326D1C9459484C88A2861B91A312587AE70EF6237EC50E1032DC39DDE89A96A8E859D76A98A6E7E36A0CFE352CA893058234FF833FCB3B03811E9F0DC0D9A52F8045B4B2F9411B67A51C44B5EF8CE77BD6D56BA75734A1856DE6D4BED6D3A242C7C8791B3422375E5C779ABF072F7695EFA0F75BCB83789FC30E3FE4CC8392207840638949C7F688565F649B74D63D8D58FFADDA571E9554426B1318FC468983D4C8A5628B06B6FC5D507C13E7A18AC1511EB6D62EA5448F83501447A9AFB3ECC2903C9DD52F922AC9ACDBEF58C6021848D96E208732D3D1D9D9EA440D91621C7A99DB8843C59C1F2E2C7D9B577D512C166D6F7E1AAD4A774A37447E78FE2021E14A95D112A068ADA019F463C7A55685AABB6888B9246483D18B9C806F474918331782344A4B8531334B26303263D9D2EB4F4BB99602B352F6AE4046C69A5E7E8E4A18EF9BC0A2DED61310417012FD824CC116CFB7C4C1F7EC7177A17446CBDE96F3EDD88FCD052F0B888A45FDAF2B631354F40D16E5FA9C2C4EDA98E798D15E6046DC5363F3096B2C607A9D8DD55B1502A6AC7D3CC8D8C575998E7D796910C804C495235057E91ECD2637C9C1845151AC6B9A0490AE3EC6F47740A0DB0BA36D075956CEE7354EA3E9A4F2720B26550C7D394324BC0CB7E9317D8A8661F42191FF10B08256CE3FD25B745E5194906B4D61CB4C2E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000526F6F7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001434130303030303030330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007BE8EF6CB279C9E2EEE121C6EAF44FF639F88F078B4B77ED9F9560B0358281B50E55AB721115A177703C7A30FE3AE9EF1C60BC1D974676B23A68CC04B198525BC968F11DE2DB50E4D9E7F071E562DAE2092233E9D363F61DD7C19FF3A4A91E8F6553D471DD7B84B9F1B8CE7335F0F5540563A1EAB83963E09BE901011F99546361287020E9CC0DAB487F140D6626A1836D27111F2068DE4772149151CF69C61BA60EF9D949A0F71F5499F2D39AD28C7005348293C431FFBD33F6BCA60DC7195EA2BCC56D200BAF6D06D09C41DB8DE9C720154CA4832B69C08C69CD3B073A0063602F462D338061A5EA6C915CD5623579C3EB64CE44EF586D14BAAA8834019B3EEBEED3790001000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
},
{
"Root-CA00000003-XS00000020",
nn::pki::sign::SIGN_ALGO_RSA2048,
pie::hac::es::sign::SIGN_ALGO_RSA2048,
tc::cli::FormatUtil::hexStringToBytes("D21D3CE67C1069DA049D5E5310E76B907E18EEC80B337C4723E339573F4C664907DB2F0832D03DF5EA5F160A4AF24100D71AFAC2E3AE75AFA1228012A9A21616597DF71EAFCB65941470D1B40F5EF83A597E179FCB5B57C2EE17DA3BC3769864CB47856767229D67328141FC9AB1DF149E0C5C15AEB80BC58FC71BE18966642D68308B506934B8EF779F78E4DDF30A0DCF93FCAFBFA131A8839FD641949F47EE25CEECF814D55B0BE6E5677C1EFFEC6F29871EF29AA3ED9197B0D83852E050908031EF1ABBB5AFC8B3DD937A076FF6761AB362405C3F7D86A3B17A6170A659C16008950F7F5E06A5DE3E5998895EFA7DEEA060BE9575668F78AB1907B3BA1B7D"),
tc::cli::FormatUtil::hexStringToBytes("00010004969FE8288DA6B9DD52C7BD63642A4A9AE5F053ECCB93613FDA37992087BD9199DA5E6797618D77098133FD5B05CD8288139E2E975CD2608003878CDAF020F51A0E5B7692780845561B31C61808E8A47C3462224D94F736E9A14E56ACBF71B7F11BBDEE38DDB846D6BD8F0AB4E4948C5434EAF9BF26529B7EB83671D3CE60A6D7A850DBE6801EC52A7B7A3E5A27BC675BA3C53377CFC372EBCE02062F59F37003AA23AE35D4880E0E4B69F982FB1BAC806C2F75BA29587F2815FD7783998C354D52B19E3FAD9FBEF444C48579288DB0978116AFC82CE54DACB9ED7E1BFD50938F22F85EECF3A4F426AE5FEB15B72F022FB36ECCE9314DAD131429BFC9675F58EE000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000526F6F742D4341303030303030303300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015853303030303030323000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000D21D3CE67C1069DA049D5E5310E76B907E18EEC80B337C4723E339573F4C664907DB2F0832D03DF5EA5F160A4AF24100D71AFAC2E3AE75AFA1228012A9A21616597DF71EAFCB65941470D1B40F5EF83A597E179FCB5B57C2EE17DA3BC3769864CB47856767229D67328141FC9AB1DF149E0C5C15AEB80BC58FC71BE18966642D68308B506934B8EF779F78E4DDF30A0DCF93FCAFBFA131A8839FD641949F47EE25CEECF814D55B0BE6E5677C1EFFEC6F29871EF29AA3ED9197B0D83852E050908031EF1ABBB5AFC8B3DD937A076FF6761AB362405C3F7D86A3B17A6170A659C16008950F7F5E06A5DE3E5998895EFA7DEEA060BE9575668F78AB1907B3BA1B7D0001000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
},
{
"Root-CA00000003-XS00000022",
nn::pki::sign::SIGN_ALGO_RSA2048,
pie::hac::es::sign::SIGN_ALGO_RSA2048,
tc::cli::FormatUtil::hexStringToBytes("E29775264ADC30C0FDE2DEFCFBBAC406A3B1C2ADDC2644C4C3E46DAD11E4F1ED7BC8B6E8CDBBE87E01020DF807520CE8A8F88BB53BE82CAFF4A1AF7FC5CD69EB34E24BEA74781203B611D09EBF56F82E3F21A494549F407FABA948545B34B64F487E1F27B031A83D337CE40496A3034AC6A2DB9E9353A1967EC7A07A4B3672B5B3F7934FF166D90EC131D8A75DC925ED629F8381A586589A82790489D4BF170F29F8E4BE50811ECBA9564D5517362D8DE777B01FC0A0AD8DED692CEAFD028A468CD6A6BF18A2767801AF8BB954EDB4DA3CED78337F3E9B6A1602B94752C85A53993678FDFA0300A4200CA752FA0D94E5A4B74B726FB61876146E49EC148508F5"),
tc::cli::FormatUtil::hexStringToBytes("0001000458C7FFCDB0A1758925286C3C5029942683A8ED614A4E5C24EECE90548F99A0E59429C3D7D9CA37910CC1F5974E3AA2D7438627FBE456C9C830E5BF5B4440013CD41AA6F0AE02307E3EDEF3EDE0E6404A87234786FED37878F4BF4D964C2290C66AF167AC94869DC2F8378FA3FE0B764F776F9CE479B9E7A4EAE77FCA924B84035C9C06075F5F23BBF3A202AC1AF6A640C62BEEE4603925534783642663238A803D5FC87C5BEA58E09B0669CE9273509A87FACEDA94333FC6264D095708C18F9A50963F0E02A0771AEBC7174D4A89BE158C6CF407BD11658363E924F2808B15C7FE00267565CBD386E576540C906F9B2FFB3AFC64BA1198FA711A48F107E6A9AD000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000526F6F742D4341303030303030303300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015853303030303030323200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E29775264ADC30C0FDE2DEFCFBBAC406A3B1C2ADDC2644C4C3E46DAD11E4F1ED7BC8B6E8CDBBE87E01020DF807520CE8A8F88BB53BE82CAFF4A1AF7FC5CD69EB34E24BEA74781203B611D09EBF56F82E3F21A494549F407FABA948545B34B64F487E1F27B031A83D337CE40496A3034AC6A2DB9E9353A1967EC7A07A4B3672B5B3F7934FF166D90EC131D8A75DC925ED629F8381A586589A82790489D4BF170F29F8E4BE50811ECBA9564D5517362D8DE777B01FC0A0AD8DED692CEAFD028A468CD6A6BF18A2767801AF8BB954EDB4DA3CED78337F3E9B6A1602B94752C85A53993678FDFA0300A4200CA752FA0D94E5A4B74B726FB61876146E49EC148508F50001000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
},
{
"Root-CA00000003-XS00000024",
nn::pki::sign::SIGN_ALGO_RSA2048,
pie::hac::es::sign::SIGN_ALGO_RSA2048,
tc::cli::FormatUtil::hexStringToBytes("C694562BBDC74E83069876608EAD1EE7B1BC715036E9A6BDF58A6D22FD660ABD9CF360AA893D7746C92C5B9D20E480EAD1387786739956E060EBA79BD6ED7C06B2FCC6DBC1734ED12999AFEE5396FEE722FE3B96846D903F00A32671AC0CEDAAAB0C933C950304650A76152ED1B69547031793755599939B42F075CDF137F8C16D35870DE90D1BACBDB4B746F814AED0D3CB7F7C1B789A1FDF9947717B641BA972A6460D3258F5561CAA1D8E20085E8E3B9EBC92C9B6DCBB872A2AE02D74577F65EFA5AAFF29FD52EAA400D1408B2815C5C96CD2B54DF0F6708A755FB1DFA694A7794C4A0422F1BF8FAFE9E6870578133D50FD3D5356506CFCEC94EF79D6B639"),
tc::cli::FormatUtil::hexStringToBytes("000100046EEED0424FF97D659DA43F85DF01E0997BA1FD1593997145BDE95703AABBDB7EFDE315F8CFE8AEC0F710FFF002938AEF8CEF7EBF90F725B6AC4EDA66DCF85132435E974DDBBE8F8C725CD114CE38C83404DFC0123BB4137C676C5C86EB4E211B7C35A03AB0C7E7637F1BF2486FDF0A5CCE5B047483841B5EA6BDC09AE770951ACA79EFB5497C46750585CF6C3FE4159ACE1CDFAB1BA8C00AB2446B57383F2F063344052E48E1557BD60BF973B252AC5AB4F5A12323AFCC1B06718775F3EDA4DD580A47A04D8063844235DC35D21A4FDED5A44EA401519920B73D15C66FDDF9F8286CF9122795EB9D5EA95C6E51603F6E62AA1631549EBE9E272B4BC3AEBC0D89000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000526F6F742D4341303030303030303300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015853303030303030323400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C694562BBDC74E83069876608EAD1EE7B1BC715036E9A6BDF58A6D22FD660ABD9CF360AA893D7746C92C5B9D20E480EAD1387786739956E060EBA79BD6ED7C06B2FCC6DBC1734ED12999AFEE5396FEE722FE3B96846D903F00A32671AC0CEDAAAB0C933C950304650A76152ED1B69547031793755599939B42F075CDF137F8C16D35870DE90D1BACBDB4B746F814AED0D3CB7F7C1B789A1FDF9947717B641BA972A6460D3258F5561CAA1D8E20085E8E3B9EBC92C9B6DCBB872A2AE02D74577F65EFA5AAFF29FD52EAA400D1408B2815C5C96CD2B54DF0F6708A755FB1DFA694A7794C4A0422F1BF8FAFE9E6870578133D50FD3D5356506CFCEC94EF79D6B6390001000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
}
@ -923,31 +951,31 @@ void nstool::KeyBagInitializer::importKnownKeys(bool isDev)
{
{
"Root",
nn::pki::sign::SIGN_ALGO_RSA4096,
pie::hac::es::sign::SIGN_ALGO_RSA4096,
tc::cli::FormatUtil::hexStringToBytes("D01FE100D43556B24B56DAE971B5A5D384B93003BE1BBF28A2305B060645467D5B0251D2561A274F9E9F9CEC646150AB3D2AE3366866ACA4BAE81AE3D79AA6B04A8BCBA7E6FB648945EBDFDB85BA091FD7D114B5A3A780E3A22E6ECD87B5A4C6F910E4032208814B0CEEA1A17DF739695F617EF63528DB949637A056037F7B32413895C0A8F1982E1565E38EEDC22E590EE2677B8609F48C2E303FBC405CAC18042F822084E4936803DA7F41349248562B8EE12F78F803246330BC7BE7EE724AF458A472E7AB46A1A7C10C2F18FA07C3DDD89806A11C9CC130B247A33C8D47DE67F29E5577B11C43493D5BBA7634A7E4E71531B7DF5981FE24A114554CBD8F005CE1DB35085CCFC77806B6DE254068A26CB5492D4580438FE1E5A9ED75C5ED451DCE789439CCC3BA28A2312A1B8719EF0F73B713950C02591A7462A607F37C0AA7A18FA943A36D752A5F4192F0136100AA9CB41BBE14BEB1F9FC692FDFA09446DE5A9DDE2CA5F68C1C0C21429287CB2DAAA3D263752F73E09FAF4479D2817429F69800AFDE6B592DC19882BDF581CCABF2CB91029EF35C4CFDBBFF49C1FA1B2FE31DE7A560ECB47EBCFE32425B956F81B69917487E3B789151DB2E78B1FD2EBE7E626B3EA165B4FB00CCB751AF507329C4A3939EA6DD9C50A0E7386B0145796B41AF61F78555944F3BC22DC3BD0D00F8798A42B1AAA08320659AC7395AB4F329"),
tc::ByteData()
},
{
"Root-CA00000004",
nn::pki::sign::SIGN_ALGO_RSA2048,
pie::hac::es::sign::SIGN_ALGO_RSA2048,
tc::cli::FormatUtil::hexStringToBytes("C9CC2DC4DF2930E4DF3F8C70A078948775AD5E9AA604C5B4D8EAFF2AA1D214676564EFCA28CC00154554A1A3EA1379E9E6CAACED1593FE88D89AC6B8ACCCAB6E207CEB7CCA29809E2980440662B7D4382A15DA43085745A9AAE59AA05BDB32F66869A2DD4295386C87ECDD3508A2CF60D01E23EC2FE698F470D6001549A2F06759131E534C7006057DEF1D18A83F0AC79CFE80FF5A91F2BED4A0837061190A0329902165403C9A908FB615739F3CE33BF1BAEA16C25BCED7963FACC9D24D9C0AD76FC020B2C4B84C10A741A2CC7D9BAC3AACCCA3529BAC316A9AA75D2A26C7D7D288CBA466C5FE5F454AE679744A90A15772DB3B0E47A49AF031D16DBEAB332B"),
tc::cli::FormatUtil::hexStringToBytes("000100031949429D1E58A62E7E8B56D1B76AE302FD8B97491F778745F75388C4DD0BEB1DF122FB9642151497764A53CF78151845E42CA8FDE486FD2A4F53F8A1BA008A7485FF73B3BF7E3C980729D0656B693219ADE835EB5FFFFCCB7CBB5E307FE0688B888EF2D2053FB7E791E985FD15EF10D79CCA88D6BB15E8E4714A98EE09BF7B8AF053232B6450E6D5FDFFC20A6D1EA6A23812E1014525D56D4082703B86986959A73CD1A14364D2C2DAEA96B095F76C46E4FF4155465E70EF1ED31053D97011E010CC93E7914013687FA3A802996D1E557B1CCC7A7E8F5865C1742E28E26DEF38A93AB5D82D43ECCCBF0BEF22E1FD57E2864333582FEDEABC012F986DDFC3E9447973470308455BDC57AA170B84427F73A29B48F6DA135F66C745C142A84AFB0E6A5EED85D7B9719936F8CE2B621F395F40DC03BEF8854C1117FF0C128641CC7843B97B4346DB226F6026ACB56C278B8E0EA79A2D65EF798E1078AD80ED4B9604D2F08B2CD64A23A3DB270833B402F80851F35BED3EE4577C6660FBF16D9413E09C917A49D42C6DA375BC27F0230DB98F8973AB027B522CD57EC03D25E8B3FC3494C97FB108FE18C68A4336E46C26B6F280D27E34BE287C3E4687BC9D776B76D928D1B6352EC0347D7294AA9360268D26F5F652064AF240D7D00C7C5EA3C32DE62D9B5C4B4CAB6FD7BD371D57C2166095910E4AD8E9ED181EF761936153892D77000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000526F6F74000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014341303030303030303400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000081122A46C9CC2DC4DF2930E4DF3F8C70A078948775AD5E9AA604C5B4D8EAFF2AA1D214676564EFCA28CC00154554A1A3EA1379E9E6CAACED1593FE88D89AC6B8ACCCAB6E207CEB7CCA29809E2980440662B7D4382A15DA43085745A9AAE59AA05BDB32F66869A2DD4295386C87ECDD3508A2CF60D01E23EC2FE698F470D6001549A2F06759131E534C7006057DEF1D18A83F0AC79CFE80FF5A91F2BED4A0837061190A0329902165403C9A908FB615739F3CE33BF1BAEA16C25BCED7963FACC9D24D9C0AD76FC020B2C4B84C10A741A2CC7D9BAC3AACCCA3529BAC316A9AA75D2A26C7D7D288CBA466C5FE5F454AE679744A90A15772DB3B0E47A49AF031D16DBEAB332B0001000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
},
{
"Root-CA00000004-XS00000020",
nn::pki::sign::SIGN_ALGO_RSA2048,
pie::hac::es::sign::SIGN_ALGO_RSA2048,
tc::cli::FormatUtil::hexStringToBytes("BA278428765D879A7F215404C6EE4E0A0D3F66C33BC7F8A32FD898E52CB7B63443CED8B00527D89DEDC6BBF60AD1C5C9923021DD555F9BAD4BE0C0C406D3702915E5B34AC2D2ABE503C32A3A23B43834C9157B9A0AF2E4E9C03BEDE2B4C115F5353DFC66BD04A6C079970E38CBDD5A50A2B98FF2D765FCF83381E9E0E849C3573578378FF65951613E95F75EE8EF26183A40AAE4A76D7384EA478D2CDCE80FBA0321A6BF8D69983C3AA7AE5443B72BFE410BF1323CBD88C3560EA13D17D38A2E34041DE7AAF389DE4375225CA87EE349C760C7D99BE7E737C6261CC74E25AE46527AC9619F939057088D7435A6DE7B25AB82DD5410F2579CAEF1491A909D302B"),
tc::cli::FormatUtil::hexStringToBytes("00010004603483F7F4EF3C863FF7B46821E9D83983EFB0BA29C45B10DFB2E8A268AE06084DFEB0B9680B6D40D6DF82CAE7D651E28F31364F5AB567DD9DCCFCBB5EFF8F1CEA92489C046E8BED2AF0D7F9CA0BD50F683633D681B08D1AF417D7B7F8762AD88E3AF0D1C45DAC5407B9D8F24F167AEDC7C5DBCF4E0E176EC341D4F9BA8ADFE749CF37F45688653886566A9045ED89AD353DD289E32631867BDFD7FC67738BDF0E1E858F3BF9DEE25B02206F0B7FFB61F866DA4D862D77DDBDA9668BB61CBDEFACB2583CE5C9FAB22FC90EF8EB06954743E5A32A37A3513C6C795BC8E0C65E2F170B435A8C447765381C4050427F88E9828E6E94144D28441C7F9C7F6D92FE5B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000526F6F742D4341303030303030303400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015853303030303030323000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000BA278428765D879A7F215404C6EE4E0A0D3F66C33BC7F8A32FD898E52CB7B63443CED8B00527D89DEDC6BBF60AD1C5C9923021DD555F9BAD4BE0C0C406D3702915E5B34AC2D2ABE503C32A3A23B43834C9157B9A0AF2E4E9C03BEDE2B4C115F5353DFC66BD04A6C079970E38CBDD5A50A2B98FF2D765FCF83381E9E0E849C3573578378FF65951613E95F75EE8EF26183A40AAE4A76D7384EA478D2CDCE80FBA0321A6BF8D69983C3AA7AE5443B72BFE410BF1323CBD88C3560EA13D17D38A2E34041DE7AAF389DE4375225CA87EE349C760C7D99BE7E737C6261CC74E25AE46527AC9619F939057088D7435A6DE7B25AB82DD5410F2579CAEF1491A909D302B0001000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
},
{
"Root-CA00000004-XS00000021",
nn::pki::sign::SIGN_ALGO_RSA2048,
pie::hac::es::sign::SIGN_ALGO_RSA2048,
tc::cli::FormatUtil::hexStringToBytes("CA303087732E88FB2736A4644B6A84DF02393786EBE3DBE914F92224126AB3C38D7CA67322B7D3107B9AC0E00AED9AF13DEDDC62BCB8AC889A47B07196B45BC97AC5DD333CC63E872E30CDB52BD35E055FBA56C2521AFC8BBFC8B06390522E99699750B457C8647A42D6318BE5EAA192ADA35DA7023FC348215613141919821FD5599B93497893CA58E7A88C8D6E6E9EB0A57567BF8C12EB25241BB6082BED7A696658A58DDB66E7CC2562F2EA061E5373E6A5397BF6299F7EA9065B0047AA408F24A5D6F6E4050B99DA86831F663792E08D96F182400182D9BECB917AE315A238CA89741B6AEAF52E238590CDA60FC5B74DC638F9D6FCAF95D2CA7AE005A7B1"),
tc::cli::FormatUtil::hexStringToBytes("000100041282394569ED63B5C4E54747B31E3B32C68B0EB90712E3C04662101CA77A551A0394CC36CB28E369DFBBB9FD78C9C503C3B1F184729C2B05B4D1691581A877AF82F8EC3D70E95B27F459039B65D8221D4864CCB282FF721EBDD6C46863F8C95591C1BF36D0AC118C0027FA3E2D434821A5FEF123C65F17885321F9A520C22B9EE6FC533EEF582706A95DD0CEABACE87B0169E136336E2E9CC0399637CE4CC77B6DA418671A277614F80A0A909569018F624DE0C5E1A67DB134C63F1FFE30BB64C201FDD8DAD42F4C88B247C1C6133CC554DE6B15684320D6AA1E09CB59EAD15F37140C9DD4BE69D87CC90DD8F733C946FBA6C576C70533601AF4E8294A3B5DD4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000526F6F742D4341303030303030303400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015853303030303030323100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000CA303087732E88FB2736A4644B6A84DF02393786EBE3DBE914F92224126AB3C38D7CA67322B7D3107B9AC0E00AED9AF13DEDDC62BCB8AC889A47B07196B45BC97AC5DD333CC63E872E30CDB52BD35E055FBA56C2521AFC8BBFC8B06390522E99699750B457C8647A42D6318BE5EAA192ADA35DA7023FC348215613141919821FD5599B93497893CA58E7A88C8D6E6E9EB0A57567BF8C12EB25241BB6082BED7A696658A58DDB66E7CC2562F2EA061E5373E6A5397BF6299F7EA9065B0047AA408F24A5D6F6E4050B99DA86831F663792E08D96F182400182D9BECB917AE315A238CA89741B6AEAF52E238590CDA60FC5B74DC638F9D6FCAF95D2CA7AE005A7B10001000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
},
{
"Root-CA00000004-XS00000024",
nn::pki::sign::SIGN_ALGO_RSA2048,
pie::hac::es::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 <nn/pki/SignUtils.h>
#include <nn/hac/define/types.h>
#include <nn/hac/define/nca.h>
#include <pietendo/hac/es/SignUtils.h>
#include <pietendo/hac/define/types.h>
#include <pietendo/hac/define/nca.h>
namespace nstool {
struct KeyBag
{
using aes128_key_t = nn::hac::detail::aes128_key_t;
using aes128_xtskey_t = nn::hac::detail::aes128_xtskey_t;
using aes128_key_t = pie::hac::detail::aes128_key_t;
using aes128_xtskey_t = pie::hac::detail::aes128_xtskey_t;
using rsa_key_t = tc::crypto::RsaKey;
//using ecc_key_t = tc::crypto::EccKey;
using rights_id_t = nn::hac::detail::rights_id_t;
using rights_id_t = pie::hac::detail::rights_id_t;
using key_generation_t = byte_t;
using broadon_issuer_t = std::string;
static const size_t kNcaKeakNum = nn::hac::nca::kKeyAreaEncryptionKeyNum;
static const size_t kNcaKeakNum = pie::hac::nca::kKeyAreaEncryptionKeyNum;
// acid
@ -39,6 +39,7 @@ 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)
@ -60,7 +61,7 @@ struct KeyBag
{
tc::ByteData certificate;
nn::pki::sign::SignatureAlgo key_type;
pie::hac::es::sign::SignatureAlgo key_type;
rsa_key_t rsa_key;
// ecc_key_t ecc_key;
};
@ -70,7 +71,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>& tik_path, 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>& titlekeyfile_path, const std::vector<tc::io::Path>& tik_path_list, const tc::Optional<tc::io::Path>& cert_path);
private:
KeyBagInitializer();

View file

@ -1,6 +1,6 @@
#include "KipProcess.h"
#include <nn/hac/KernelCapabilityUtil.h>
#include <pietendo/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(nn::hac::sKipHeader))
if (tc::io::IOUtil::castInt64ToSize(mFile->length()) < sizeof(pie::hac::sKipHeader))
{
throw tc::Exception(mModuleName, "Corrupt KIP: file too small.");
}
// read kip
tc::ByteData scratch = tc::ByteData(sizeof(nn::hac::sKipHeader));
tc::ByteData scratch = tc::ByteData(sizeof(pie::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 nn::hac::KernelCapabilityControl& kern)
void nstool::KipProcess::displayKernelCap(const pie::hac::KernelCapabilityControl& kern)
{
fmt::print("[Kernel Capabilities]\n");
if (kern.getThreadInfo().isSet())
{
nn::hac::ThreadInfoHandler threadInfo = kern.getThreadInfo();
pie::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 nn::hac::KernelCapabilityControl
for (size_t syscall_id = 0; syscall_id < syscall_ids.size(); syscall_id++)
{
if (syscall_ids.test(syscall_id))
syscall_names.push_back(nn::hac::KernelCapabilityUtil::getSystemCallIdAsString(nn::hac::kc::SystemCallId(syscall_id)));
syscall_names.push_back(pie::hac::KernelCapabilityUtil::getSystemCallIdAsString(pie::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 nn::hac::KernelCapabilityControl
}
if (kern.getMiscParams().isSet())
{
fmt::print(" ProgramType: {:s} ({:d})\n", nn::hac::KernelCapabilityUtil::getProgramTypeAsString(kern.getMiscParams().getProgramType()), kern.getMiscParams().getProgramType());
fmt::print(" ProgramType: {:s} ({:d})\n", pie::hac::KernelCapabilityUtil::getProgramTypeAsString(kern.getMiscParams().getProgramType()), (uint32_t)kern.getMiscParams().getProgramType());
}
if (kern.getKernelVersion().isSet())
{
@ -261,13 +261,13 @@ void nstool::KipProcess::displayKernelCap(const nn::hac::KernelCapabilityControl
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(nn::hac::KernelCapabilityUtil::getMiscFlagsBitAsString(nn::hac::kc::MiscFlagsBit(misc_flags_bit)));
misc_flags_names.push_back(pie::hac::KernelCapabilityUtil::getMiscFlagsBitAsString(pie::hac::kc::MiscFlagsBit(misc_flags_bit)));
}
fmt::print("{:s}", tc::cli::FormatUtil::formatListWithLineLimit(misc_flags_names, 60, 4));
}
}
std::string nstool::KipProcess::formatMappingAsString(const nn::hac::MemoryMappingHandler::sMemoryMapping& map) const
std::string nstool::KipProcess::formatMappingAsString(const pie::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), nn::hac::KernelCapabilityUtil::getMemoryPermissionAsString(map.perm), nn::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), pie::hac::KernelCapabilityUtil::getMemoryPermissionAsString(map.perm), pie::hac::KernelCapabilityUtil::getMappingTypeAsString(map.type));
}

View file

@ -1,7 +1,7 @@
#pragma once
#include "types.h"
#include <nn/hac/KernelInitialProcessHeader.h>
#include <pietendo/hac/KernelInitialProcessHeader.h>
namespace nstool {
@ -22,16 +22,16 @@ private:
CliOutputMode mCliOutputMode;
bool mVerify;
nn::hac::KernelInitialProcessHeader mHdr;
pie::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 nn::hac::KernelCapabilityControl& kern);
void displayKernelCap(const pie::hac::KernelCapabilityControl& kern);
std::string formatMappingAsString(const nn::hac::MemoryMappingHandler::sMemoryMapping& map) const;
std::string formatMappingAsString(const pie::hac::MemoryMappingHandler::sMemoryMapping& map) const;
};
}

View file

@ -1,9 +1,9 @@
#include "MetaProcess.h"
#include <nn/hac/AccessControlInfoUtil.h>
#include <nn/hac/FileSystemAccessUtil.h>
#include <nn/hac/KernelCapabilityUtil.h>
#include <nn/hac/MetaUtil.h>
#include <pietendo/hac/AccessControlInfoUtil.h>
#include <pietendo/hac/FileSystemAccessUtil.h>
#include <pietendo/hac/KernelCapabilityUtil.h>
#include <pietendo/hac/MetaUtil.h>
nstool::MetaProcess::MetaProcess() :
mModuleName("nstool::MetaProcess"),
@ -65,7 +65,7 @@ void nstool::MetaProcess::setVerifyMode(bool verify)
mVerify = verify;
}
const nn::hac::Meta& nstool::MetaProcess::getMeta() const
const pie::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 nn::hac::AccessControlInfoDesc& acid, byte_t key_generation)
void nstool::MetaProcess::validateAcidSignature(const pie::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 nn::hac::AccessControlInfo
}
void nstool::MetaProcess::validateAciFromAcid(const nn::hac::AccessControlInfo& aci, const nn::hac::AccessControlInfoDesc& acid)
void nstool::MetaProcess::validateAciFromAcid(const pie::hac::AccessControlInfo& aci, const pie::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 nn::hac::AccessControlInfo&
if (rightFound == false)
{
fmt::print("[WARNING] ACI/FAC FsaRights: FAIL ({:s} not permitted)\n", nn::hac::FileSystemAccessUtil::getFsAccessFlagAsString(fs_access[i]));
fmt::print("[WARNING] ACI/FAC FsaRights: FAIL ({:s} not permitted)\n", pie::hac::FileSystemAccessUtil::getFsAccessFlagAsString(fs_access[i]));
}
}
@ -157,6 +157,9 @@ void nstool::MetaProcess::validateAciFromAcid(const nn::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;
@ -169,9 +172,10 @@ void nstool::MetaProcess::validateAciFromAcid(const nn::hac::AccessControlInfo&
if (rightFound == false)
{
fmt::print("[WARNING] ACI/FAC SaveDataOwnerId: FAIL (0x{:016x} ({:d}) not permitted)\n", aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].id, aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].access_type);
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);
}
}
#endif
// check SAC
for (size_t i = 0; i < aci.getServiceAccessControl().getServiceList().size(); i++)
@ -214,7 +218,7 @@ void nstool::MetaProcess::validateAciFromAcid(const nn::hac::AccessControlInfo&
{
if (syscall_ids.test(i) && desc_syscall_ids.test(i) == false)
{
fmt::print("[WARNING] ACI/KC SystemCallList: FAIL ({:s} not permitted)\n", nn::hac::KernelCapabilityUtil::getSystemCallIdAsString(nn::hac::kc::SystemCallId(i)));
fmt::print("[WARNING] ACI/KC SystemCallList: FAIL ({:s} not permitted)\n", pie::hac::KernelCapabilityUtil::getSystemCallIdAsString(pie::hac::kc::SystemCallId(i)));
}
}
// check memory maps
@ -268,7 +272,7 @@ void nstool::MetaProcess::validateAciFromAcid(const nn::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", aci.getKernelCapabilities().getMiscParams().getProgramType());
fmt::print("[WARNING] ACI/KC ProgramType: FAIL ({:d} not permitted)\n", (uint32_t)aci.getKernelCapabilities().getMiscParams().getProgramType());
}
// check kernel version
uint32_t aciKernelVersion = (uint32_t)aci.getKernelCapabilities().getKernelVersion().getVerMajor() << 16 | (uint32_t)aci.getKernelCapabilities().getKernelVersion().getVerMinor();
@ -289,18 +293,18 @@ void nstool::MetaProcess::validateAciFromAcid(const nn::hac::AccessControlInfo&
{
if (misc_flags.test(i) && desc_misc_flags.test(i) == false)
{
fmt::print("[WARNING] ACI/KC MiscFlag: FAIL ({:s} not permitted)\n", nn::hac::KernelCapabilityUtil::getMiscFlagsBitAsString(nn::hac::kc::MiscFlagsBit(i)));
fmt::print("[WARNING] ACI/KC MiscFlag: FAIL ({:s} not permitted)\n", pie::hac::KernelCapabilityUtil::getMiscFlagsBitAsString(pie::hac::kc::MiscFlagsBit(i)));
}
}
}
void nstool::MetaProcess::displayMetaHeader(const nn::hac::Meta& hdr)
void nstool::MetaProcess::displayMetaHeader(const pie::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", nn::hac::MetaUtil::getProcessAddressSpaceAsString(hdr.getProcessAddressSpace()));
fmt::print(" ProcessAddressSpace: {:s}\n", pie::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");
@ -316,25 +320,25 @@ void nstool::MetaProcess::displayMetaHeader(const nn::hac::Meta& hdr)
}
}
void nstool::MetaProcess::displayAciHdr(const nn::hac::AccessControlInfo& aci)
void nstool::MetaProcess::displayAciHdr(const pie::hac::AccessControlInfo& aci)
{
fmt::print("[Access Control Info]\n");
fmt::print(" ProgramID: 0x{:016x}\n", aci.getProgramId());
}
void nstool::MetaProcess::displayAciDescHdr(const nn::hac::AccessControlInfoDesc& acid)
void nstool::MetaProcess::displayAciDescHdr(const pie::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", nn::hac::AccessControlInfoUtil::getMemoryRegionAsString(acid.getMemoryRegion()), acid.getMemoryRegion());
fmt::print(" Memory Region: {:s} ({:d})\n", pie::hac::AccessControlInfoUtil::getMemoryRegionAsString(acid.getMemoryRegion()), (uint32_t)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 nn::hac::FileSystemAccessControl& fac)
void nstool::MetaProcess::displayFac(const pie::hac::FileSystemAccessControl& fac)
{
fmt::print("[FS Access Control]\n");
fmt::print(" Format Version: {:d}\n", fac.getFormatVersion());
@ -344,10 +348,10 @@ void nstool::MetaProcess::displayFac(const nn::hac::FileSystemAccessControl& fac
std::vector<std::string> fs_access_str_list;
for (auto itr = fac.getFsAccess().begin(); itr != fac.getFsAccess().end(); itr++)
{
std::string flag_string = nn::hac::FileSystemAccessUtil::getFsAccessFlagAsString(nn::hac::fac::FsAccessFlag(*itr));
std::string flag_string = pie::hac::FileSystemAccessUtil::getFsAccessFlagAsString(pie::hac::fac::FsAccessFlag(*itr));
if (mCliOutputMode.show_extended_info)
{
fs_access_str_list.push_back(fmt::format("{:s} (bit {:d})", flag_string, *itr));
fs_access_str_list.push_back(fmt::format("{:s} (bit {:d})", flag_string, (uint32_t)*itr));
}
else
{
@ -374,12 +378,12 @@ void nstool::MetaProcess::displayFac(const nn::hac::FileSystemAccessControl& fac
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, nn::hac::FileSystemAccessUtil::getSaveDataOwnerAccessModeAsString(fac.getSaveDataOwnerIdList()[i].access_type));
fmt::print(" 0x{:016x} ({:s})\n", fac.getSaveDataOwnerIdList()[i].id, pie::hac::FileSystemAccessUtil::getSaveDataOwnerAccessModeAsString(fac.getSaveDataOwnerIdList()[i].access_type));
}
}
}
void nstool::MetaProcess::displaySac(const nn::hac::ServiceAccessControl& sac)
void nstool::MetaProcess::displaySac(const pie::hac::ServiceAccessControl& sac)
{
fmt::print("[Service Access Control]\n");
fmt::print(" Service List:\n");
@ -391,12 +395,12 @@ void nstool::MetaProcess::displaySac(const nn::hac::ServiceAccessControl& sac)
fmt::print("{:s}", tc::cli::FormatUtil::formatListWithLineLimit(service_name_list, 60, 4));
}
void nstool::MetaProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern)
void nstool::MetaProcess::displayKernelCap(const pie::hac::KernelCapabilityControl& kern)
{
fmt::print("[Kernel Capabilities]\n");
if (kern.getThreadInfo().isSet())
{
nn::hac::ThreadInfoHandler threadInfo = kern.getThreadInfo();
pie::hac::ThreadInfoHandler threadInfo = kern.getThreadInfo();
fmt::print(" Thread Priority:\n");
fmt::print(" Min: {:d}\n", threadInfo.getMinPriority());
fmt::print(" Max: {:d}\n", threadInfo.getMaxPriority());
@ -413,7 +417,7 @@ void nstool::MetaProcess::displayKernelCap(const nn::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(nn::hac::KernelCapabilityUtil::getSystemCallIdAsString(nn::hac::kc::SystemCallId(syscall_id)));
syscall_names.push_back(pie::hac::KernelCapabilityUtil::getSystemCallIdAsString(pie::hac::kc::SystemCallId(syscall_id)));
}
fmt::print("{:s}", tc::cli::FormatUtil::formatListWithLineLimit(syscall_names, 60, 4));
}
@ -445,7 +449,7 @@ void nstool::MetaProcess::displayKernelCap(const nn::hac::KernelCapabilityContro
}
if (kern.getMiscParams().isSet())
{
fmt::print(" ProgramType: {:s} ({:d})\n", nn::hac::KernelCapabilityUtil::getProgramTypeAsString(kern.getMiscParams().getProgramType()), kern.getMiscParams().getProgramType());
fmt::print(" ProgramType: {:s} ({:d})\n", pie::hac::KernelCapabilityUtil::getProgramTypeAsString(kern.getMiscParams().getProgramType()), (uint32_t)kern.getMiscParams().getProgramType());
}
if (kern.getKernelVersion().isSet())
{
@ -463,13 +467,13 @@ void nstool::MetaProcess::displayKernelCap(const nn::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(nn::hac::KernelCapabilityUtil::getMiscFlagsBitAsString(nn::hac::kc::MiscFlagsBit(misc_flags_bit)));
misc_flags_names.push_back(pie::hac::KernelCapabilityUtil::getMiscFlagsBitAsString(pie::hac::kc::MiscFlagsBit(misc_flags_bit)));
}
fmt::print("{:s}", tc::cli::FormatUtil::formatListWithLineLimit(misc_flags_names, 60, 4));
}
}
std::string nstool::MetaProcess::formatMappingAsString(const nn::hac::MemoryMappingHandler::sMemoryMapping& map) const
std::string nstool::MetaProcess::formatMappingAsString(const pie::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), nn::hac::KernelCapabilityUtil::getMemoryPermissionAsString(map.perm), nn::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), pie::hac::KernelCapabilityUtil::getMemoryPermissionAsString(map.perm), pie::hac::KernelCapabilityUtil::getMappingTypeAsString(map.type));
}

View file

@ -2,7 +2,7 @@
#include "types.h"
#include "KeyBag.h"
#include <nn/hac/Meta.h>
#include <pietendo/hac/Meta.h>
namespace nstool {
@ -18,7 +18,7 @@ public:
void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify);
const nn::hac::Meta& getMeta() const;
const pie::hac::Meta& getMeta() const;
private:
std::string mModuleName;
@ -28,21 +28,21 @@ private:
CliOutputMode mCliOutputMode;
bool mVerify;
nn::hac::Meta mMeta;
pie::hac::Meta mMeta;
void importMeta();
void validateAcidSignature(const nn::hac::AccessControlInfoDesc& acid, byte_t key_generation);
void validateAciFromAcid(const nn::hac::AccessControlInfo& aci, const nn::hac::AccessControlInfoDesc& acid);
void validateAcidSignature(const pie::hac::AccessControlInfoDesc& acid, byte_t key_generation);
void validateAciFromAcid(const pie::hac::AccessControlInfo& aci, const pie::hac::AccessControlInfoDesc& acid);
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);
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);
std::string formatMappingAsString(const nn::hac::MemoryMappingHandler::sMemoryMapping& map) const;
std::string formatMappingAsString(const pie::hac::MemoryMappingHandler::sMemoryMapping& map) const;
};
}

View file

@ -1,6 +1,6 @@
#include "NacpProcess.h"
#include <nn/hac/ApplicationControlPropertyUtil.h>
#include <pietendo/hac/ApplicationControlPropertyUtil.h>
nstool::NacpProcess::NacpProcess() :
mModuleName("nstool::NacpProcess"),
@ -33,7 +33,7 @@ void nstool::NacpProcess::setVerifyMode(bool verify)
mVerify = verify;
}
const nn::hac::ApplicationControlProperty& nstool::NacpProcess::getApplicationControlProperty() const
const pie::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(nn::hac::sApplicationControlProperty))
if (file_size != sizeof(pie::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", nn::hac::ApplicationControlPropertyUtil::getLanguageAsString(itr->language));
fmt::print(" {:s}:\n", pie::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() != nn::hac::nacp::StartupUserAccount::None || mCliOutputMode.show_extended_info)
if (mNacp.getStartupUserAccount() != pie::hac::nacp::StartupUserAccount_None || mCliOutputMode.show_extended_info)
{
fmt::print(" StartupUserAccount: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getStartupUserAccountAsString(mNacp.getStartupUserAccount()));
fmt::print(" StartupUserAccount: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getStartupUserAccountAsString(mNacp.getStartupUserAccount()));
}
// UserAccountSwitchLock
if (mNacp.getUserAccountSwitchLock() != nn::hac::nacp::UserAccountSwitchLock::Disable || mCliOutputMode.show_extended_info)
if (mNacp.getUserAccountSwitchLock() != pie::hac::nacp::UserAccountSwitchLock_Disable || mCliOutputMode.show_extended_info)
{
fmt::print(" UserAccountSwitchLock: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getUserAccountSwitchLockAsString(mNacp.getUserAccountSwitchLock()));
fmt::print(" UserAccountSwitchLock: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getUserAccountSwitchLockAsString(mNacp.getUserAccountSwitchLock()));
}
// AddOnContentRegistrationType
if (mNacp.getAddOnContentRegistrationType() != nn::hac::nacp::AddOnContentRegistrationType::AllOnLaunch || mCliOutputMode.show_extended_info)
if (mNacp.getAddOnContentRegistrationType() != pie::hac::nacp::AddOnContentRegistrationType_AllOnLaunch || mCliOutputMode.show_extended_info)
{
fmt::print(" AddOnContentRegistrationType: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getAddOnContentRegistrationTypeAsString(mNacp.getAddOnContentRegistrationType()));
fmt::print(" AddOnContentRegistrationType: {:s}\n", pie::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", nn::hac::ApplicationControlPropertyUtil::getAttributeFlagAsString(*itr));
fmt::print(" {:s}\n", pie::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", nn::hac::ApplicationControlPropertyUtil::getLanguageAsString(*itr));
fmt::print(" {:s}\n", pie::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", nn::hac::ApplicationControlPropertyUtil::getParentalControlFlagAsString(*itr));
fmt::print(" {:s}\n", pie::hac::ApplicationControlPropertyUtil::getParentalControlFlagAsString(*itr));
}
}
else if (mCliOutputMode.show_extended_info)
@ -155,27 +155,27 @@ void nstool::NacpProcess::displayNacp()
}
// Screenshot
if (mNacp.getScreenshot() != nn::hac::nacp::Screenshot::Allow || mCliOutputMode.show_extended_info)
if (mNacp.getScreenshot() != pie::hac::nacp::Screenshot_Allow || mCliOutputMode.show_extended_info)
{
fmt::print(" Screenshot: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getScreenshotAsString(mNacp.getScreenshot()));
fmt::print(" Screenshot: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getScreenshotAsString(mNacp.getScreenshot()));
}
// VideoCapture
if (mNacp.getVideoCapture() != nn::hac::nacp::VideoCapture::Disable || mCliOutputMode.show_extended_info)
if (mNacp.getVideoCapture() != pie::hac::nacp::VideoCapture_Disable || mCliOutputMode.show_extended_info)
{
fmt::print(" VideoCapture: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getVideoCaptureAsString(mNacp.getVideoCapture()));
fmt::print(" VideoCapture: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getVideoCaptureAsString(mNacp.getVideoCapture()));
}
// DataLossConfirmation
if (mNacp.getDataLossConfirmation() != nn::hac::nacp::DataLossConfirmation::None || mCliOutputMode.show_extended_info)
if (mNacp.getDataLossConfirmation() != pie::hac::nacp::DataLossConfirmation_None || mCliOutputMode.show_extended_info)
{
fmt::print(" DataLossConfirmation: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getDataLossConfirmationAsString(mNacp.getDataLossConfirmation()));
fmt::print(" DataLossConfirmation: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getDataLossConfirmationAsString(mNacp.getDataLossConfirmation()));
}
// PlayLogPolicy
if (mNacp.getPlayLogPolicy() != nn::hac::nacp::PlayLogPolicy::All || mCliOutputMode.show_extended_info)
if (mNacp.getPlayLogPolicy() != pie::hac::nacp::PlayLogPolicy_All || mCliOutputMode.show_extended_info)
{
fmt::print(" PlayLogPolicy: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getPlayLogPolicyAsString(mNacp.getPlayLogPolicy()));
fmt::print(" PlayLogPolicy: {:s}\n", pie::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", nn::hac::ApplicationControlPropertyUtil::getOrganisationAsString(itr->organisation));
fmt::print(" {:s}:\n", pie::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", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataSize().size));
fmt::print(" UserAccountSaveDataSize: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataSize().size));
}
// UserAccountSaveDataJournalSize
if (mNacp.getUserAccountSaveDataSize().journal_size != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" UserAccountSaveDataJournalSize: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataSize().journal_size));
fmt::print(" UserAccountSaveDataJournalSize: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataSize().journal_size));
}
// DeviceSaveDataSize
if (mNacp.getDeviceSaveDataSize().size != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" DeviceSaveDataSize: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataSize().size));
fmt::print(" DeviceSaveDataSize: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataSize().size));
}
// DeviceSaveDataJournalSize
if (mNacp.getDeviceSaveDataSize().journal_size != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" DeviceSaveDataJournalSize: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataSize().journal_size));
fmt::print(" DeviceSaveDataJournalSize: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataSize().journal_size));
}
// BcatDeliveryCacheStorageSize
if (mNacp.getBcatDeliveryCacheStorageSize() != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" BcatDeliveryCacheStorageSize: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getBcatDeliveryCacheStorageSize()));
fmt::print(" BcatDeliveryCacheStorageSize: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getBcatDeliveryCacheStorageSize()));
}
// ApplicationErrorCodeCategory
@ -277,39 +277,39 @@ void nstool::NacpProcess::displayNacp()
}
// LogoType
//if (mNacp.getLogoType() != nn::hac::nacp::LogoType::Nintendo || mCliOutputMode.show_extended_info)
//if (mNacp.getLogoType() != pie::hac::nacp::LogoType_Nintendo || mCliOutputMode.show_extended_info)
//{
fmt::print(" LogoType: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getLogoTypeAsString(mNacp.getLogoType()));
fmt::print(" LogoType: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getLogoTypeAsString(mNacp.getLogoType()));
//}
// LogoHandling
if (mNacp.getLogoHandling() != nn::hac::nacp::LogoHandling::Auto || mCliOutputMode.show_extended_info)
if (mNacp.getLogoHandling() != pie::hac::nacp::LogoHandling_Auto || mCliOutputMode.show_extended_info)
{
fmt::print(" LogoHandling: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getLogoHandlingAsString(mNacp.getLogoHandling()));
fmt::print(" LogoHandling: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getLogoHandlingAsString(mNacp.getLogoHandling()));
}
// RuntimeAddOnContentInstall
if (mNacp.getRuntimeAddOnContentInstall() != nn::hac::nacp::RuntimeAddOnContentInstall::Deny || mCliOutputMode.show_extended_info)
if (mNacp.getRuntimeAddOnContentInstall() != pie::hac::nacp::RuntimeAddOnContentInstall_Deny || mCliOutputMode.show_extended_info)
{
fmt::print(" RuntimeAddOnContentInstall: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getRuntimeAddOnContentInstallAsString(mNacp.getRuntimeAddOnContentInstall()));
fmt::print(" RuntimeAddOnContentInstall: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getRuntimeAddOnContentInstallAsString(mNacp.getRuntimeAddOnContentInstall()));
}
// RuntimeParameterDelivery
if (mNacp.getRuntimeParameterDelivery() != nn::hac::nacp::RuntimeParameterDelivery::Always || mCliOutputMode.show_extended_info)
if (mNacp.getRuntimeParameterDelivery() != pie::hac::nacp::RuntimeParameterDelivery_Always || mCliOutputMode.show_extended_info)
{
fmt::print(" RuntimeParameterDelivery: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getRuntimeParameterDeliveryAsString(mNacp.getRuntimeParameterDelivery()));
fmt::print(" RuntimeParameterDelivery: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getRuntimeParameterDeliveryAsString(mNacp.getRuntimeParameterDelivery()));
}
// CrashReport
if (mNacp.getCrashReport() != nn::hac::nacp::CrashReport::Deny || mCliOutputMode.show_extended_info)
if (mNacp.getCrashReport() != pie::hac::nacp::CrashReport_Deny || mCliOutputMode.show_extended_info)
{
fmt::print(" CrashReport: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getCrashReportAsString(mNacp.getCrashReport()));
fmt::print(" CrashReport: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getCrashReportAsString(mNacp.getCrashReport()));
}
// Hdcp
if (mNacp.getHdcp() != nn::hac::nacp::Hdcp::None || mCliOutputMode.show_extended_info)
if (mNacp.getHdcp() != pie::hac::nacp::Hdcp_None || mCliOutputMode.show_extended_info)
{
fmt::print(" Hdcp: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getHdcpAsString(mNacp.getHdcp()));
fmt::print(" Hdcp: {:s}\n", pie::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", nn::hac::ApplicationControlPropertyUtil::getStartupUserAccountOptionFlagAsString(*itr));
fmt::print(" {:s}\n", pie::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", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataMax().size));
fmt::print(" UserAccountSaveDataSizeMax: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataMax().size));
}
// UserAccountSaveDataJournalSizeMax
if (mNacp.getUserAccountSaveDataMax().journal_size != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" UserAccountSaveDataJournalSizeMax: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataMax().journal_size));
fmt::print(" UserAccountSaveDataJournalSizeMax: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataMax().journal_size));
}
// DeviceSaveDataSizeMax
if (mNacp.getDeviceSaveDataMax().size != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" DeviceSaveDataSizeMax: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataMax().size));
fmt::print(" DeviceSaveDataSizeMax: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataMax().size));
}
// DeviceSaveDataJournalSizeMax
if (mNacp.getDeviceSaveDataMax().journal_size != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" DeviceSaveDataJournalSizeMax: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataMax().journal_size));
fmt::print(" DeviceSaveDataJournalSizeMax: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataMax().journal_size));
}
// TemporaryStorageSize
if (mNacp.getTemporaryStorageSize() != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" TemporaryStorageSize: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getTemporaryStorageSize()));
fmt::print(" TemporaryStorageSize: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getTemporaryStorageSize()));
}
// CacheStorageSize
if (mNacp.getCacheStorageSize().size != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" CacheStorageSize: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageSize().size));
fmt::print(" CacheStorageSize: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageSize().size));
}
// CacheStorageJournalSize
if (mNacp.getCacheStorageSize().journal_size != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" CacheStorageJournalSize: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageSize().journal_size));
fmt::print(" CacheStorageJournalSize: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageSize().journal_size));
}
// CacheStorageDataAndJournalSizeMax
if (mNacp.getCacheStorageDataAndJournalSizeMax() != 0 || mCliOutputMode.show_extended_info)
{
fmt::print(" CacheStorageDataAndJournalSizeMax: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageDataAndJournalSizeMax()));
fmt::print(" CacheStorageDataAndJournalSizeMax: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageDataAndJournalSizeMax()));
}
// CacheStorageIndexMax
@ -411,9 +411,9 @@ void nstool::NacpProcess::displayNacp()
}
// PlayLogQueryCapability
if (mNacp.getPlayLogQueryCapability() != nn::hac::nacp::PlayLogQueryCapability::None || mCliOutputMode.show_extended_info)
if (mNacp.getPlayLogQueryCapability() != pie::hac::nacp::PlayLogQueryCapability_None || mCliOutputMode.show_extended_info)
{
fmt::print(" PlayLogQueryCapability: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getPlayLogQueryCapabilityAsString(mNacp.getPlayLogQueryCapability()));
fmt::print(" PlayLogQueryCapability: {:s}\n", pie::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", nn::hac::ApplicationControlPropertyUtil::getRepairFlagAsString(*itr));
fmt::print(" {:s}\n", pie::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", nn::hac::ApplicationControlPropertyUtil::getRequiredNetworkServiceLicenseOnLaunchFlagAsString(*itr));
fmt::print(" {:s}\n", pie::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 < nn::hac::nacp::kReceivableGroupConfigurationCount; i++)
for (size_t i = 0; i < pie::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() != nn::hac::nacp::PlayReportPermission::None || mCliOutputMode.show_extended_info)
if (mNacp.getPlayReportPermission() != pie::hac::nacp::PlayReportPermission_None || mCliOutputMode.show_extended_info)
{
fmt::print(" PlayReportPermission: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getPlayReportPermissionAsString(mNacp.getPlayReportPermission()));
fmt::print(" PlayReportPermission: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getPlayReportPermissionAsString(mNacp.getPlayReportPermission()));
}
// CrashScreenshotForProd
if (mNacp.getCrashScreenshotForProd() != nn::hac::nacp::CrashScreenshotForProd::Deny || mCliOutputMode.show_extended_info)
if (mNacp.getCrashScreenshotForProd() != pie::hac::nacp::CrashScreenshotForProd_Deny || mCliOutputMode.show_extended_info)
{
fmt::print(" CrashScreenshotForProd: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getCrashScreenshotForProdAsString(mNacp.getCrashScreenshotForProd()));
fmt::print(" CrashScreenshotForProd: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getCrashScreenshotForProdAsString(mNacp.getCrashScreenshotForProd()));
}
// CrashScreenshotForDev
if (mNacp.getCrashScreenshotForDev() != nn::hac::nacp::CrashScreenshotForDev::Deny || mCliOutputMode.show_extended_info)
if (mNacp.getCrashScreenshotForDev() != pie::hac::nacp::CrashScreenshotForDev_Deny || mCliOutputMode.show_extended_info)
{
fmt::print(" CrashScreenshotForDev: {:s}\n", nn::hac::ApplicationControlPropertyUtil::getCrashScreenshotForDevAsString(mNacp.getCrashScreenshotForDev()));
fmt::print(" CrashScreenshotForDev: {:s}\n", pie::hac::ApplicationControlPropertyUtil::getCrashScreenshotForDevAsString(mNacp.getCrashScreenshotForDev()));
}
// AccessibleLaunchRequiredVersion

View file

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

View file

@ -2,15 +2,14 @@
#include "MetaProcess.h"
#include "util.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>
#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>
nstool::NcaProcess::NcaProcess() :
mModuleName("nstool::NcaProcess"),
@ -50,6 +49,11 @@ 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;
@ -80,7 +84,7 @@ void nstool::NcaProcess::setExtractJobs(const std::vector<nstool::ExtractJob>& e
mFsProcess.setExtractJobs(extract_jobs);
}
const std::shared_ptr<tc::io::IStorage>& nstool::NcaProcess::getFileSystem() const
const std::shared_ptr<tc::io::IFileSystem>& nstool::NcaProcess::getFileSystem() const
{
return mFileSystem;
}
@ -97,25 +101,25 @@ void nstool::NcaProcess::importHeader()
}
// read header block
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(sizeof(nn::hac::sContentArchiveHeaderBlock)))
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(sizeof(pie::hac::sContentArchiveHeaderBlock)))
{
throw tc::Exception(mModuleName, "Corrupt NCA: File too small.");
}
mFile->seek(0, tc::io::SeekOrigin::Begin);
mFile->read((byte_t*)(&mHdrBlock), sizeof(nn::hac::sContentArchiveHeaderBlock));
mFile->read((byte_t*)(&mHdrBlock), sizeof(pie::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)");
}
nn::hac::ContentArchiveUtil::decryptContentArchiveHeader((byte_t*)&mHdrBlock, (byte_t*)&mHdrBlock, mKeyCfg.nca_header_key.get());
pie::hac::ContentArchiveUtil::decryptContentArchiveHeader((byte_t*)&mHdrBlock, (byte_t*)&mHdrBlock, mKeyCfg.nca_header_key.get());
// generate header hash
tc::crypto::GenerateSha256Hash(mHdrHash.data(), (byte_t*)&mHdrBlock.header, sizeof(nn::hac::sContentArchiveHeader));
tc::crypto::GenerateSha2256Hash(mHdrHash.data(), (byte_t*)&mHdrBlock.header, sizeof(pie::hac::sContentArchiveHeader));
// proccess main header
mHdr.fromBytes((byte_t*)&mHdrBlock.header, sizeof(nn::hac::sContentArchiveHeader));
mHdr.fromBytes((byte_t*)&mHdrBlock.header, sizeof(pie::hac::sContentArchiveHeader));
}
void nstool::NcaProcess::generateNcaBodyEncryptionKeys()
@ -125,7 +129,7 @@ void nstool::NcaProcess::generateNcaBodyEncryptionKeys()
memset(zero_aesctr_key.data(), 0, zero_aesctr_key.size());
// get key data from header
byte_t masterkey_rev = nn::hac::AesKeygen::getMasterKeyRevisionFromKeyGeneration(mHdr.getKeyGeneration());
byte_t masterkey_rev = pie::hac::AesKeygen::getMasterKeyRevisionFromKeyGeneration(mHdr.getKeyGeneration());
byte_t keak_index = mHdr.getKeyAreaEncryptionKeyIndex();
// process key area
@ -141,13 +145,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;
nn::hac::AesKeygen::generateKey(kak.dec.data(), kak.enc.data(), mKeyCfg.nca_key_area_encryption_key[keak_index][masterkey_rev].data());
pie::hac::AesKeygen::generateKey(kak.dec.data(), kak.enc.data(), mKeyCfg.nca_key_area_encryption_key[keak_index][masterkey_rev].data());
}
// 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())
// 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())
{
kak.decrypted = true;
nn::hac::AesKeygen::generateKey(kak.dec.data(), kak.enc.data(), mKeyCfg.nca_key_area_encryption_key_hw[keak_index][masterkey_rev].data());
pie::hac::AesKeygen::generateKey(kak.dec.data(), kak.enc.data(), mKeyCfg.nca_key_area_encryption_key_hw[keak_index][masterkey_rev].data());
}
else
{
@ -158,7 +162,7 @@ void nstool::NcaProcess::generateNcaBodyEncryptionKeys()
}
// clear content key
mContentKey.aes_ctr = tc::Optional<nn::hac::detail::aes128_key_t>();
mContentKey.aes_ctr = tc::Optional<pie::hac::detail::aes128_key_t>();
// if this has a rights id, the key needs to be sourced from a ticket
if (mHdr.hasRightsId() == true)
@ -172,12 +176,21 @@ 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())
{
nn::hac::AesKeygen::generateKey(tmp_key.data(), tmp_key.data(), mKeyCfg.etik_common_key[masterkey_rev].data());
pie::hac::AesKeygen::generateKey(tmp_key.data(), tmp_key.data(), mKeyCfg.etik_common_key[masterkey_rev].data());
mContentKey.aes_ctr = tmp_key;
}
}
@ -187,7 +200,7 @@ void nstool::NcaProcess::generateNcaBodyEncryptionKeys()
{
for (size_t i = 0; i < mContentKey.kak_list.size(); i++)
{
if (mContentKey.kak_list[i].index == nn::hac::nca::KEY_AESCTR && mContentKey.kak_list[i].decrypted)
if (mContentKey.kak_list[i].index == pie::hac::nca::KeyBankIndex_AesCtr && mContentKey.kak_list[i].decrypted)
{
mContentKey.aes_ctr = mContentKey.kak_list[i].dec;
}
@ -213,44 +226,72 @@ 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 nn::hac::ContentArchiveHeader::sPartitionEntry& partition = mHdr.getPartitionEntryList()[i];
nn::hac::sContentArchiveFsHeader& fs_header = mHdrBlock.fs_header[partition.header_index];
const pie::hac::ContentArchiveHeader::sPartitionEntry& partition = mHdr.getPartitionEntryList()[i];
pie::hac::sContentArchiveFsHeader& fs_header = mHdrBlock.fs_header[partition.header_index];
// output structure
sPartitionInfo& info = mPartitions[partition.header_index];
// validate header hash
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));
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));
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() != nn::hac::nca::kDefaultFsHeaderVersion)
if (fs_header.version.unwrap() != pie::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
nn::hac::ContentArchiveUtil::getNcaPartitionAesCtr(&fs_header, info.aes_ctr.data());
pie::hac::ContentArchiveUtil::getNcaPartitionAesCtr(&fs_header, info.aes_ctr.data());
// save partition configinfo
info.offset = partition.offset;
info.size = partition.size;
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.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.hierarchicalsha256_hdr.fromBytes(fs_header.hash_info.data(), fs_header.hash_info.size());
}
else if (info.hash_type == nn::hac::nca::HashType::HierarchicalIntegrity)
else if (info.hash_type == pie::hac::nca::HashType_HierarchicalIntegrity)
{
info.hierarchicalintegrity_hdr.fromBytes(fs_header.hash_info.data(), fs_header.hash_info.size());
}
@ -266,68 +307,106 @@ void nstool::NcaProcess::generatePartitionConfiguration()
else
{
// create raw partition
info.reader = std::make_shared<tc::io::SubStream>(tc::io::SubStream(mFile, info.offset, info.size));
info.raw_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 == nn::hac::nca::EncryptionType::None)
if (info.enc_type == pie::hac::nca::EncryptionType_None)
{
// no encryption so do nothing
//info.reader = info.reader;
info.decrypt_reader = info.raw_reader;
}
else if (info.enc_type == nn::hac::nca::EncryptionType::AesCtr)
else if (info.enc_type == pie::hac::nca::EncryptionType_AesCtr)
{
if (mContentKey.aes_ctr.isNull())
throw tc::Exception(mModuleName, "AES-CTR Key was not determined");
// get partition key
nn::hac::detail::aes128_key_t partition_key = mContentKey.aes_ctr.get();
pie::hac::detail::aes128_key_t partition_key = mContentKey.aes_ctr.get();
// get partition counter
nn::hac::detail::aes_iv_t partition_ctr = info.aes_ctr;
tc::crypto::detail::incr_counter<16>(partition_ctr.data(), info.offset>>4);
pie::hac::detail::aes_iv_t partition_ctr = info.aes_ctr;
tc::crypto::IncrementCounterAes128Ctr(partition_ctr.data(), info.offset >> 4);
// create decryption stream
info.reader = std::make_shared<tc::crypto::Aes128CtrEncryptedStream>(tc::crypto::Aes128CtrEncryptedStream(info.reader, partition_key, partition_ctr));
info.decrypt_reader = std::make_shared<tc::crypto::Aes128CtrEncryptedStream>(tc::crypto::Aes128CtrEncryptedStream(info.raw_reader, partition_key, partition_ctr));
}
else if (info.enc_type == nn::hac::nca::EncryptionType::AesXts || info.enc_type == nn::hac::nca::EncryptionType::AesCtrEx)
else if (info.enc_type == pie::hac::nca::EncryptionType_AesCtrEx)
{
throw tc::Exception(mModuleName, fmt::format("EncryptionType({:s}): UNSUPPORTED", nn::hac::ContentArchiveUtil::getEncryptionTypeAsString(info.enc_type)));
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)));
}
else
{
throw tc::Exception(mModuleName, fmt::format("EncryptionType({:s}): UNKNOWN", nn::hac::ContentArchiveUtil::getEncryptionTypeAsString(info.enc_type)));
throw tc::Exception(mModuleName, fmt::format("EncryptionType({:s}): UNKNOWN", pie::hac::ContentArchiveUtil::getEncryptionTypeAsString(info.enc_type)));
}
}
// filter out unrecognised hash types, and hash based readers
switch (info.hash_type)
{
case (nn::hac::nca::HashType::None):
case (pie::hac::nca::HashType_None):
// no hash layer, do nothing
info.reader = info.decrypt_reader;
break;
case (nn::hac::nca::HashType::HierarchicalSha256):
info.reader = std::make_shared<nn::hac::HierarchicalSha256Stream>(nn::hac::HierarchicalSha256Stream(info.reader, info.hierarchicalsha256_hdr));
case (pie::hac::nca::HashType_HierarchicalSha256):
info.reader = std::make_shared<pie::hac::HierarchicalSha256Stream>(pie::hac::HierarchicalSha256Stream(info.decrypt_reader, info.hierarchicalsha256_hdr));
break;
case (nn::hac::nca::HashType::HierarchicalIntegrity):
info.reader = std::make_shared<nn::hac::HierarchicalIntegrityStream>(nn::hac::HierarchicalIntegrityStream(info.reader, info.hierarchicalintegrity_hdr));
case (pie::hac::nca::HashType_HierarchicalIntegrity):
info.reader = std::make_shared<pie::hac::HierarchicalIntegrityStream>(pie::hac::HierarchicalIntegrityStream(info.decrypt_reader, info.hierarchicalintegrity_hdr));
break;
default:
throw tc::Exception(mModuleName, fmt::format("HashType({:s}): UNKNOWN", nn::hac::ContentArchiveUtil::getHashTypeAsString(info.hash_type)));
throw tc::Exception(mModuleName, fmt::format("HashType({:s}): UNKNOWN", pie::hac::ContentArchiveUtil::getHashTypeAsString(info.hash_type)));
}
// filter out unrecognised format types
switch (info.format_type)
{
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));
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));
break;
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));
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));
break;
default:
throw tc::Exception(mModuleName, fmt::format("FormatType({:s}): UNKNOWN", nn::hac::ContentArchiveUtil::getFormatTypeAsString(info.format_type)));
throw tc::Exception(mModuleName, fmt::format("FormatType({:s}): UNKNOWN", pie::hac::ContentArchiveUtil::getFormatTypeAsString(info.format_type)));
}
}
catch (const tc::Exception& e)
@ -342,7 +421,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::VerifyRsa2048PssSha256(mHdrBlock.signature_main.data(), mHdrHash.data(), mKeyCfg.nca_header_sign0_key[mHdr.getSignatureKeyGeneration()]) == false)
if (tc::crypto::VerifyRsa2048PssSha2256(mHdrBlock.signature_main.data(), mHdrHash.data(), mKeyCfg.nca_header_sign0_key[mHdr.getSignatureKeyGeneration()]) == false)
{
fmt::print("[WARNING] NCA Header Main Signature: FAIL\n");
}
@ -354,16 +433,16 @@ void nstool::NcaProcess::validateNcaSignatures()
// validate signature[1]
if (mHdr.getContentType() == nn::hac::nca::ContentType::Program)
if (mHdr.getContentType() == pie::hac::nca::ContentType_Program)
{
try {
if (mPartitions[nn::hac::nca::PARTITION_CODE].format_type == nn::hac::nca::FormatType::PartitionFs)
if (mPartitions[pie::hac::nca::ProgramContentPartitionIndex_Code].format_type == pie::hac::nca::FormatType_PartitionFs)
{
if (mPartitions[nn::hac::nca::PARTITION_CODE].fs_reader != nullptr)
if (mPartitions[pie::hac::nca::ProgramContentPartitionIndex_Code].fs_reader != nullptr)
{
std::shared_ptr<tc::io::IStream> npdm_file;
try {
mPartitions[nn::hac::nca::PARTITION_CODE].fs_reader->openFile(tc::io::Path(kNpdmExefsPath), tc::io::FileMode::Open, tc::io::FileAccess::Read, npdm_file);
mPartitions[pie::hac::nca::ProgramContentPartitionIndex_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));
@ -376,7 +455,7 @@ void nstool::NcaProcess::validateNcaSignatures()
npdm.setCliOutputMode(CliOutputMode(false, false, false, false));
npdm.process();
if (tc::crypto::VerifyRsa2048PssSha256(mHdrBlock.signature_acid.data(), mHdrHash.data(), npdm.getMeta().getAccessControlInfoDesc().getContentArchiveHeaderSignature2Key()) == false)
if (tc::crypto::VerifyRsa2048PssSha2256(mHdrBlock.signature_acid.data(), mHdrHash.data(), npdm.getMeta().getAccessControlInfoDesc().getContentArchiveHeaderSignature2Key()) == false)
{
throw tc::Exception("Bad signature");
}
@ -400,16 +479,16 @@ void nstool::NcaProcess::validateNcaSignatures()
void nstool::NcaProcess::displayHeader()
{
fmt::print("[NCA Header]\n");
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(" 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(" Key Generation: {:d}\n", mHdr.getKeyGeneration());
fmt::print(" Sig. Generation: {:d}\n", mHdr.getSignatureKeyGeneration());
fmt::print(" Kaek Index: {:s} ({:d})\n", nn::hac::ContentArchiveUtil::getKeyAreaEncryptionKeyIndexAsString((nn::hac::nca::KeyAreaEncryptionKeyIndex)mHdr.getKeyAreaEncryptionKeyIndex()), mHdr.getKeyAreaEncryptionKeyIndex());
fmt::print(" Kaek Index: {:s} ({:d})\n", pie::hac::ContentArchiveUtil::getKeyAreaEncryptionKeyIndexAsString((pie::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", nn::hac::ContentArchiveUtil::getSdkAddonVersionAsString(mHdr.getSdkAddonVersion()), mHdr.getSdkAddonVersion());
fmt::print(" SdkAddon Ver.: {:s} (v{:d})\n", pie::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, ""));
@ -418,22 +497,18 @@ 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++)
{
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, ""));
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>";
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(" | {:3d} | {:32s} | {:32s} |\n", mContentKey.kak_list[i].index, enc_key, dec_key);
}
fmt::print(" <--------------------------------------------------------------------------------------------------------->\n");
fmt::print(" <--------------------------------------------------------------------------->\n");
}
if (mCliOutputMode.show_layout)
@ -448,18 +523,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", 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)
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)
{
nn::hac::detail::aes_iv_t aes_ctr;
pie::hac::detail::aes_iv_t aes_ctr;
memcpy(aes_ctr.data(), info.aes_ctr.data(), aes_ctr.size());
tc::crypto::detail::incr_counter<16>(aes_ctr.data(), info.offset>>4);
tc::crypto::IncrementCounterAes128Ctr(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 == nn::hac::nca::HashType::HierarchicalIntegrity)
if (info.hash_type == pie::hac::nca::HashType_HierarchicalIntegrity)
{
auto hash_hdr = info.hierarchicalintegrity_hdr;
fmt::print(" HierarchicalIntegrity Header:\n");
@ -484,7 +559,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 == nn::hac::nca::HashType::HierarchicalSha256)
else if (info.hash_type == pie::hac::nca::HashType_HierarchicalSha256)
{
auto hash_hdr = info.hierarchicalsha256_hdr;
fmt::print(" HierarchicalSha256 Header:\n");
@ -513,7 +588,7 @@ void nstool::NcaProcess::displayHeader()
void nstool::NcaProcess::processPartitions()
{
std::vector<nn::hac::CombinedFsMetaGenerator::MountPointInfo> mount_points;
std::vector<pie::hac::CombinedFsSnapshotGenerator::MountPointInfo> mount_points;
for (size_t i = 0; i < mHdr.getPartitionEntryList().size(); i++)
{
@ -534,9 +609,9 @@ void nstool::NcaProcess::processPartitions()
std::string mount_point_name;
/*
if (mHdr.getContentType() == nn::hac::nca::ContentType::Program)
if (mHdr.getContentType() == pie::hac::nca::ContentType_Program)
{
mount_point_name = nn::hac::ContentArchiveUtil::getProgramContentParititionIndexAsString((nn::hac::nca::ProgramContentPartitionIndex)index);
mount_point_name = pie::hac::ContentArchiveUtil::getProgramContentParititionIndexAsString((pie::hac::nca::ProgramContentPartitionIndex)index);
}
else
*/
@ -544,12 +619,12 @@ void nstool::NcaProcess::processPartitions()
mount_point_name = fmt::format("{:d}", index);
}
mount_points.push_back( { mount_point_name, partition.fs_meta } );
mount_points.push_back( { mount_point_name, partition.fs_snapshot } );
}
tc::io::VirtualFileSystem::FileSystemMeta fs_meta = nn::hac::CombinedFsMetaGenerator(mount_points);
tc::io::VirtualFileSystem::FileSystemSnapshot fs_snapshot = pie::hac::CombinedFsSnapshotGenerator(mount_points);
std::shared_ptr<tc::io::IStorage> nca_fs = std::make_shared<tc::io::VirtualFileSystem>(tc::io::VirtualFileSystem(fs_meta));
std::shared_ptr<tc::io::IFileSystem> nca_fs = std::make_shared<tc::io::VirtualFileSystem>(tc::io::VirtualFileSystem(fs_snapshot));
mFsProcess.setInputFileSystem(nca_fs);
mFsProcess.setFsFormatName("ContentArchive");
@ -557,28 +632,28 @@ void nstool::NcaProcess::processPartitions()
mFsProcess.process();
}
std::string nstool::NcaProcess::getContentTypeForMountStr(nn::hac::nca::ContentType cont_type) const
std::string nstool::NcaProcess::getContentTypeForMountStr(pie::hac::nca::ContentType cont_type) const
{
std::string str;
switch (cont_type)
{
case (nn::hac::nca::ContentType::Program):
case (pie::hac::nca::ContentType_Program):
str = "program";
break;
case (nn::hac::nca::ContentType::Meta):
case (pie::hac::nca::ContentType_Meta):
str = "meta";
break;
case (nn::hac::nca::ContentType::Control):
case (pie::hac::nca::ContentType_Control):
str = "control";
break;
case (nn::hac::nca::ContentType::Manual):
case (pie::hac::nca::ContentType_Manual):
str = "manual";
break;
case (nn::hac::nca::ContentType::Data):
case (pie::hac::nca::ContentType_Data):
str = "data";
break;
case (nn::hac::nca::ContentType::PublicData):
case (pie::hac::nca::ContentType_PublicData):
str = "publicdata";
break;
default:

View file

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

View file

@ -1,7 +1,5 @@
#include "NroProcess.h"
#include <nn/hac/define/nro-hb.h>
nstool::NroProcess::NroProcess() :
mModuleName("nstool::NroProcess"),
mFile(),
@ -91,13 +89,13 @@ void nstool::NroProcess::importHeader()
}
// check if file_size is smaller than NRO header size
if (tc::io::IOUtil::castInt64ToSize(mFile->length()) < sizeof(nn::hac::sNroHeader))
if (tc::io::IOUtil::castInt64ToSize(mFile->length()) < sizeof(pie::hac::sNroHeader))
{
throw tc::Exception(mModuleName, "Corrupt NRO: file too small.");
}
// read nro
tc::ByteData scratch = tc::ByteData(sizeof(nn::hac::sNroHeader));
tc::ByteData scratch = tc::ByteData(sizeof(pie::hac::sNroHeader));
mFile->seek(0, tc::io::SeekOrigin::Begin);
mFile->read(scratch.data(), scratch.size());
@ -105,10 +103,10 @@ void nstool::NroProcess::importHeader()
mHdr.fromBytes(scratch.data(), scratch.size());
// setup homebrew extension
nn::hac::sNroHeader* raw_hdr = (nn::hac::sNroHeader*)scratch.data();
pie::hac::sNroHeader* raw_hdr = (pie::hac::sNroHeader*)scratch.data();
int64_t file_size = mFile->length();
if (((tc::bn::le64<uint64_t>*)raw_hdr->reserved_0.data())->unwrap() == nn::hac::nro::kNroHomebrewStructMagic && file_size > int64_t(mHdr.getNroSize()))
if (((tc::bn::le64<uint64_t>*)raw_hdr->reserved_0.data())->unwrap() == pie::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 <nn/hac/NroHeader.h>
#include <pietendo/hac/NroHeader.h>
namespace nstool {
@ -36,7 +36,7 @@ private:
CliOutputMode mCliOutputMode;
bool mVerify;
nn::hac::NroHeader mHdr;
pie::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(nn::hac::sNsoHeader))
if (file_size < sizeof(pie::hac::sNsoHeader))
{
throw tc::Exception(mModuleName, "Corrupt NSO: file too small.");
}
// read nso
tc::ByteData scratch = tc::ByteData(sizeof(nn::hac::sNsoHeader));
tc::ByteData scratch = tc::ByteData(sizeof(pie::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;
nn::hac::detail::sha256_hash_t calc_hash;
pie::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::GenerateSha256Hash(calc_hash.data(), mTextBlob.data(), mTextBlob.size());
tc::crypto::GenerateSha2256Hash(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::GenerateSha256Hash(calc_hash.data(), mRoBlob.data(), mRoBlob.size());
tc::crypto::GenerateSha2256Hash(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::GenerateSha256Hash(calc_hash.data(), mDataBlob.data(), mDataBlob.size());
tc::crypto::GenerateSha2256Hash(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 <nn/hac/define/meta.h>
#include <nn/hac/NsoHeader.h>
#include <pietendo/hac/define/meta.h>
#include <pietendo/hac/NsoHeader.h>
namespace nstool {
@ -33,7 +33,7 @@ private:
bool mListApi;
bool mListSymbols;
nn::hac::NsoHeader mHdr;
pie::hac::NsoHeader mHdr;
tc::ByteData mTextBlob, mRoBlob, mDataBlob;
nstool::RoMetadataProcess mRoMeta;

View file

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

View file

@ -2,7 +2,7 @@
#include "types.h"
#include "FsProcess.h"
#include <nn/hac/PartitionFsHeader.h>
#include <pietendo/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 nn::hac::PartitionFsHeader& getPfsHeader() const;
const std::shared_ptr<tc::io::IStorage>& getFileSystem() const;
const pie::hac::PartitionFsHeader& getPfsHeader() const;
const std::shared_ptr<tc::io::IFileSystem>& getFileSystem() const;
private:
static const size_t kCacheSize = 0x10000;
@ -36,13 +36,13 @@ private:
CliOutputMode mCliOutputMode;
bool mVerify;
nn::hac::PartitionFsHeader mPfs;
pie::hac::PartitionFsHeader mPfs;
std::shared_ptr<tc::io::IStorage> mFileSystem;
std::shared_ptr<tc::io::IFileSystem> mFileSystem;
FsProcess mFsProcess;
size_t determineHeaderSize(const nn::hac::sPfsHeader* hdr);
bool validateHeaderMagic(const nn::hac::sPfsHeader* hdr);
size_t determineHeaderSize(const pie::hac::sPfsHeader* hdr);
bool validateHeaderMagic(const pie::hac::sPfsHeader* hdr);
};
}

View file

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

View file

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

View file

@ -2,7 +2,7 @@
#include "util.h"
#include <tc/io/VirtualFileSystem.h>
#include <nn/hac/RomFsMetaGenerator.h>
#include <pietendo/hac/RomFsSnapshotGenerator.h>
nstool::RomfsProcess::RomfsProcess() :
@ -20,6 +20,7 @@ nstool::RomfsProcess::RomfsProcess() :
void nstool::RomfsProcess::process()
{
// state checks
if (mFile == nullptr)
{
throw tc::Exception(mModuleName, "No file reader set.");
@ -29,38 +30,62 @@ 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(nn::hac::sRomfsHeader)))
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(sizeof(pie::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(nn::hac::sRomfsHeader) ||
if (mRomfsHeader.header_size.unwrap() != sizeof(pie::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(), nn::hac::romfs::kRomfsHeaderAlign))
mRomfsHeader.data_offset.unwrap() != align<int64_t>(mRomfsHeader.header_size.unwrap(), pie::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(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();
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());
}
// get file entry ptr
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());
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());
}
// count dir num
mDirNum = 0;
for (uint32_t v_addr = 0; size_t(v_addr) < dir_entry_table.size();)
{
uint32_t total_size = sizeof(nn::hac::sRomfsDirEntry) + align<uint32_t>(((nn::hac::sRomfsDirEntry*)(dir_entry_table.data() + v_addr))->name_size.unwrap(), 4);
uint32_t total_size = sizeof(pie::hac::sRomfsDirEntry) + align<uint32_t>(((pie::hac::sRomfsDirEntry*)(dir_entry_table.data() + v_addr))->name_size.unwrap(), 4);
// don't count root directory
if (v_addr != 0)
@ -75,7 +100,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(nn::hac::sRomfsFileEntry) + align<uint32_t>(((nn::hac::sRomfsFileEntry*)(file_entry_table.data() + v_addr))->name_size.unwrap(), 4);
uint32_t total_size = sizeof(pie::hac::sRomfsFileEntry) + align<uint32_t>(((pie::hac::sRomfsFileEntry*)(file_entry_table.data() + v_addr))->name_size.unwrap(), 4);
mFileNum += 1;
@ -83,7 +108,7 @@ void nstool::RomfsProcess::process()
}
// create virtual filesystem
mFileSystem = std::make_shared<tc::io::VirtualFileSystem>(tc::io::VirtualFileSystem(nn::hac::RomFsMetaGenerator(mFile)));
mFileSystem = std::make_shared<tc::io::VirtualFileSystem>(tc::io::VirtualFileSystem(pie::hac::RomFsSnapshotGenerator(mFile)));
mFsProcess.setInputFileSystem(mFileSystem);
// set properties for FsProcess

View file

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

View file

@ -9,27 +9,24 @@
#include <tc/io/FileStream.h>
#include <tc/io/StreamSource.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>
#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>
class UnkOptionHandler : public tc::cli::OptionParser::IOptionHandler
{
@ -42,6 +39,11 @@ 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 + "\"");
@ -55,7 +57,8 @@ 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)
mOptStrings(opts),
mOptRegex()
{}
const std::vector<std::string>& getOptionStrings() const
@ -63,6 +66,11 @@ 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);
@ -70,6 +78,7 @@ public:
private:
std::string mWarnMessage;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class FlagOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -77,7 +86,8 @@ class FlagOptionHandler : public tc::cli::OptionParser::IOptionHandler
public:
FlagOptionHandler(bool& flag, const std::vector<std::string>& opts) :
mFlag(flag),
mOptStrings(opts)
mOptStrings(opts),
mOptRegex()
{}
const std::vector<std::string>& getOptionStrings() const
@ -85,6 +95,11 @@ 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)
@ -97,6 +112,7 @@ public:
private:
bool& mFlag;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class SingleParamStringOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -104,7 +120,8 @@ class SingleParamStringOptionHandler : public tc::cli::OptionParser::IOptionHand
public:
SingleParamStringOptionHandler(tc::Optional<std::string>& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts)
mOptStrings(opts),
mOptRegex()
{}
const std::vector<std::string>& getOptionStrings() const
@ -112,6 +129,11 @@ 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)
@ -124,6 +146,7 @@ public:
private:
tc::Optional<std::string>& mParam;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class SingleParamPathOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -131,7 +154,8 @@ 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)
mOptStrings(opts),
mOptRegex()
{}
const std::vector<std::string>& getOptionStrings() const
@ -139,6 +163,11 @@ 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)
@ -151,6 +180,7 @@ 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
@ -158,7 +188,8 @@ class SingleParamSizetOptionHandler : public tc::cli::OptionParser::IOptionHandl
public:
SingleParamSizetOptionHandler(size_t& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts)
mOptStrings(opts),
mOptRegex()
{}
const std::vector<std::string>& getOptionStrings() const
@ -166,6 +197,11 @@ 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)
@ -178,6 +214,7 @@ public:
private:
size_t& mParam;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class SingleParamAesKeyOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -185,7 +222,8 @@ 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)
mOptStrings(opts),
mOptRegex()
{}
const std::vector<std::string>& getOptionStrings() const
@ -193,6 +231,11 @@ 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,6 +257,41 @@ 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
@ -221,7 +299,8 @@ class FileTypeOptionHandler : public tc::cli::OptionParser::IOptionHandler
public:
FileTypeOptionHandler(nstool::Settings::FileType& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts)
mOptStrings(opts),
mOptRegex()
{}
const std::vector<std::string>& getOptionStrings() const
@ -229,6 +308,11 @@ 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)
@ -310,6 +394,7 @@ public:
private:
nstool::Settings::FileType& mParam;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class InstructionTypeOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -317,7 +402,8 @@ class InstructionTypeOptionHandler : public tc::cli::OptionParser::IOptionHandle
public:
InstructionTypeOptionHandler(bool& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts)
mOptStrings(opts),
mOptRegex()
{}
const std::vector<std::string>& getOptionStrings() const
@ -325,6 +411,11 @@ 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)
@ -348,6 +439,7 @@ public:
private:
bool& mParam;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class ExtractDataPathOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -355,7 +447,8 @@ class ExtractDataPathOptionHandler : public tc::cli::OptionParser::IOptionHandle
public:
ExtractDataPathOptionHandler(std::vector<nstool::ExtractJob>& jobs, const std::vector<std::string>& opts) :
mJobs(jobs),
mOptStrings(opts)
mOptStrings(opts),
mOptRegex()
{}
const std::vector<std::string>& getOptionStrings() const
@ -363,6 +456,11 @@ 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)
@ -381,6 +479,7 @@ public:
private:
std::vector<nstool::ExtractJob>& mJobs;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class CustomExtractDataPathOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -389,6 +488,7 @@ 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)
{}
@ -397,6 +497,11 @@ 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)
@ -404,9 +509,6 @@ 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("/"))
@ -415,7 +517,7 @@ public:
}
else
{
fmt::print("Consider using \"-x {:s} {:s}\" instead.\n", custom_path_str, params[0]);
fmt::print("Consider using \"-x {:s} {:s}\" instead.\n", mCustomPath.to_string(), params[0]);
}
@ -424,6 +526,7 @@ public:
private:
std::vector<nstool::ExtractJob>& mJobs;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
tc::io::Path mCustomPath;
};
@ -435,7 +538,7 @@ nstool::SettingsInitializer::SettingsInitializer(const std::vector<std::string>&
mVerbose(false),
mNcaEncryptedContentKey(),
mNcaContentKey(),
mTikPath(),
mTikPathList(),
mCertPath()
{
// parse input arguments
@ -463,29 +566,16 @@ nstool::SettingsInitializer::SettingsInitializer(const std::vector<std::string>&
// locate key file, if not specfied
if (mKeysetPath.isNull())
{
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");
}
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", "");
}
// generate keybag
opt.keybag = KeyBagInitializer(opt.is_dev, mKeysetPath, mTikPath, mCertPath);
opt.keybag = KeyBagInitializer(opt.is_dev, mKeysetPath, mTitleKeysetPath, mTikPathList, mCertPath);
opt.keybag.fallback_enc_content_key = mNcaEncryptedContentKey;
opt.keybag.fallback_content_key = mNcaContentKey;
@ -549,9 +639,10 @@ 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<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(mTikPath, {"--tik"})));
opts.registerOptionHandler(std::shared_ptr<SingleParamPathArrayOptionHandler>(new SingleParamPathArrayOptionHandler(mTikPathList, {"--tik"})));
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(mCertPath, {"--cert"})));
// code options
@ -576,6 +667,8 @@ 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" })));
@ -590,9 +683,7 @@ void nstool::SettingsInitializer::parse_args(const std::vector<std::string>& arg
void nstool::SettingsInitializer::determine_filetype()
{
//std::string infile_path_str;
//tc::io::PathUtil::pathToUnixUTF8(infile.path.get(), infile_path_str);
//fmt::print("infile path = \"{}\"\n", infile_path_str);
//fmt::print("infile path = \"{}\"\n", infile.path.get().to_string());
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)));
@ -604,69 +695,69 @@ void nstool::SettingsInitializer::determine_filetype()
// do easy tests
// detect "scene" XCI
if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sGcHeader_Rsa2048Signed))
&& _TYPE_PTR(nn::hac::sGcHeader_Rsa2048Signed)->header.st_magic.unwrap() == nn::hac::gc::kGcHeaderStructMagic)
if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sGcHeader_Rsa2048Signed))
&& _TYPE_PTR(pie::hac::sGcHeader_Rsa2048Signed)->header.st_magic.unwrap() == pie::hac::gc::kGcHeaderStructMagic)
{
infile.filetype = FILE_TYPE_GAMECARD;
}
// detect "SDK" XCI
else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sSdkGcHeader))
&& _TYPE_PTR(nn::hac::sSdkGcHeader)->signed_header.header.st_magic.unwrap() == nn::hac::gc::kGcHeaderStructMagic)
else if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sSdkGcHeader))
&& _TYPE_PTR(pie::hac::sSdkGcHeader)->signed_header.header.st_magic.unwrap() == pie::hac::gc::kGcHeaderStructMagic)
{
infile.filetype = FILE_TYPE_GAMECARD;
}
// detect PFS0
else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sPfsHeader))
&& _TYPE_PTR(nn::hac::sPfsHeader)->st_magic.unwrap() == nn::hac::pfs::kPfsStructMagic)
else if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sPfsHeader))
&& _TYPE_PTR(pie::hac::sPfsHeader)->st_magic.unwrap() == pie::hac::pfs::kPfsStructMagic)
{
infile.filetype = FILE_TYPE_PARTITIONFS;
}
// detect HFS0
else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sPfsHeader))
&& _TYPE_PTR(nn::hac::sPfsHeader)->st_magic.unwrap() == nn::hac::pfs::kHashedPfsStructMagic)
else if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sPfsHeader))
&& _TYPE_PTR(pie::hac::sPfsHeader)->st_magic.unwrap() == pie::hac::pfs::kHashedPfsStructMagic)
{
infile.filetype = FILE_TYPE_PARTITIONFS;
}
// detect ROMFS
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()))
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()))
{
infile.filetype = FILE_TYPE_ROMFS;
}
// detect NPDM
else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sMetaHeader))
&& _TYPE_PTR(nn::hac::sMetaHeader)->st_magic.unwrap() == nn::hac::meta::kMetaStructMagic)
else if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sMetaHeader))
&& _TYPE_PTR(pie::hac::sMetaHeader)->st_magic.unwrap() == pie::hac::meta::kMetaStructMagic)
{
infile.filetype = FILE_TYPE_META;
}
// detect NSO
else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sNsoHeader))
&& _TYPE_PTR(nn::hac::sNsoHeader)->st_magic.unwrap() == nn::hac::nso::kNsoStructMagic)
else if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sNsoHeader))
&& _TYPE_PTR(pie::hac::sNsoHeader)->st_magic.unwrap() == pie::hac::nso::kNsoStructMagic)
{
infile.filetype = FILE_TYPE_NSO;
}
// detect NRO
else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sNroHeader))
&& _TYPE_PTR(nn::hac::sNroHeader)->st_magic.unwrap() == nn::hac::nro::kNroStructMagic)
else if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sNroHeader))
&& _TYPE_PTR(pie::hac::sNroHeader)->st_magic.unwrap() == pie::hac::nro::kNroStructMagic)
{
infile.filetype = FILE_TYPE_NRO;
}
// detect INI
else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sIniHeader))
&& _TYPE_PTR(nn::hac::sIniHeader)->st_magic.unwrap() == nn::hac::ini::kIniStructMagic)
else if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sIniHeader))
&& _TYPE_PTR(pie::hac::sIniHeader)->st_magic.unwrap() == pie::hac::ini::kIniStructMagic)
{
infile.filetype = FILE_TYPE_INI;
}
// detect KIP
else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sKipHeader))
&& _TYPE_PTR(nn::hac::sKipHeader)->st_magic.unwrap() == nn::hac::kip::kKipStructMagic)
else if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sKipHeader))
&& _TYPE_PTR(pie::hac::sKipHeader)->st_magic.unwrap() == pie::hac::kip::kKipStructMagic)
{
infile.filetype = FILE_TYPE_KIP;
}
// detect HB ASET
else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sAssetHeader))
&& _TYPE_PTR(nn::hac::sAssetHeader)->st_magic.unwrap() == nn::hac::aset::kAssetStructMagic)
else if (_ASSERT_FILE_SIZE(sizeof(pie::hac::sAssetHeader))
&& _TYPE_PTR(pie::hac::sAssetHeader)->st_magic.unwrap() == pie::hac::aset::kAssetStructMagic)
{
infile.filetype = FILE_TYPE_KIP;
}
@ -729,7 +820,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>] <.nca file>\n", BIN_NAME);
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(" --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");
@ -740,6 +831,7 @@ 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");
@ -836,24 +928,24 @@ void nstool::SettingsInitializer::dump_keys() const
fmt::print(" {:s}:\n", itr->first);
fmt::print(" SignType: ");
switch(itr->second.key_type) {
case nn::pki::sign::SIGN_ALGO_RSA2048:
case pie::hac::es::sign::SIGN_ALGO_RSA2048:
fmt::print("RSA-2048\n");
break;
case nn::pki::sign::SIGN_ALGO_RSA4096:
case pie::hac::es::sign::SIGN_ALGO_RSA4096:
fmt::print("RSA-4096\n");
break;
case nn::pki::sign::SIGN_ALGO_ECDSA240:
case pie::hac::es::sign::SIGN_ALGO_ECDSA240:
fmt::print("ECDSA-240\n");
break;
default:
fmt::print("Unknown\n");
}
switch(itr->second.key_type) {
case nn::pki::sign::SIGN_ALGO_RSA2048:
case nn::pki::sign::SIGN_ALGO_RSA4096:
case pie::hac::es::sign::SIGN_ALGO_RSA2048:
case pie::hac::es::sign::SIGN_ALGO_RSA4096:
dump_rsa_key(itr->second.rsa_key, "RsaKey", 6, opt.cli_output_mode.show_extended_info);
break;
case nn::pki::sign::SIGN_ALGO_ECDSA240:
case pie::hac::es::sign::SIGN_ALGO_ECDSA240:
default:
break;
}
@ -897,10 +989,34 @@ 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() < nn::hac::nca::kHeaderSize)
if (sample.size() < pie::hac::nca::kHeaderSize)
{
return false;
}
@ -911,26 +1027,26 @@ bool nstool::SettingsInitializer::determineValidNcaFromSample(const tc::ByteData
return false;
}
nn::hac::detail::aes128_xtskey_t key = opt.keybag.nca_header_key.get();
pie::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(), nn::hac::nca::kSectorSize, false);
enc.initialize(key[0].data(), key[0].size(), key[1].data(), key[1].size(), pie::hac::nca::kSectorSize, false);
// decrypt main header
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);
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);
/*
fmt::print("NCA Header Raw:\n");
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));
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));
*/
if (hdr->st_magic.unwrap() != nn::hac::nca::kNca2StructMagic && hdr->st_magic.unwrap() != nn::hac::nca::kNca3StructMagic)
if (hdr->st_magic.unwrap() != pie::hac::nca::kNca2StructMagic && hdr->st_magic.unwrap() != pie::hac::nca::kNca3StructMagic)
{
return false;
}
@ -940,12 +1056,12 @@ bool nstool::SettingsInitializer::determineValidNcaFromSample(const tc::ByteData
bool nstool::SettingsInitializer::determineValidCnmtFromSample(const tc::ByteData& sample) const
{
if (sample.size() < sizeof(nn::hac::sContentMetaHeader))
if (sample.size() < sizeof(pie::hac::sContentMetaHeader))
return false;
const nn::hac::sContentMetaHeader* data = (const nn::hac::sContentMetaHeader*)sample.data();
const pie::hac::sContentMetaHeader* data = (const pie::hac::sContentMetaHeader*)sample.data();
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;
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;
if (sample.size() < minimum_size)
return false;
@ -953,37 +1069,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)nn::hac::cnmt::ContentMetaType::Application)
if (data->type == (byte_t)pie::hac::cnmt::ContentMetaType_Application)
{
const nn::hac::sApplicationMetaExtendedHeader* meta = (const nn::hac::sApplicationMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader));
const pie::hac::sApplicationMetaExtendedHeader* meta = (const pie::hac::sApplicationMetaExtendedHeader*)(sample.data() + sizeof(pie::hac::sContentMetaHeader));
if ((meta->patch_id.unwrap() & data->id.unwrap()) != data->id.unwrap())
return false;
}
else if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::Patch)
else if (data->type == (byte_t)pie::hac::cnmt::ContentMetaType_Patch)
{
const nn::hac::sPatchMetaExtendedHeader* meta = (const nn::hac::sPatchMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader));
const pie::hac::sPatchMetaExtendedHeader* meta = (const pie::hac::sPatchMetaExtendedHeader*)(sample.data() + sizeof(pie::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)nn::hac::cnmt::ContentMetaType::AddOnContent)
else if (data->type == (byte_t)pie::hac::cnmt::ContentMetaType_AddOnContent)
{
const nn::hac::sAddOnContentMetaExtendedHeader* meta = (const nn::hac::sAddOnContentMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader));
const pie::hac::sAddOnContentMetaExtendedHeader* meta = (const pie::hac::sAddOnContentMetaExtendedHeader*)(sample.data() + sizeof(pie::hac::sContentMetaHeader));
if ((meta->application_id.unwrap() & data->id.unwrap()) != meta->application_id.unwrap())
return false;
}
else if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::Delta)
else if (data->type == (byte_t)pie::hac::cnmt::ContentMetaType_Delta)
{
const nn::hac::sDeltaMetaExtendedHeader* meta = (const nn::hac::sDeltaMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader));
const pie::hac::sDeltaMetaExtendedHeader* meta = (const pie::hac::sDeltaMetaExtendedHeader*)(sample.data() + sizeof(pie::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)nn::hac::cnmt::ContentMetaType::SystemUpdate)
else if (data->type == (byte_t)pie::hac::cnmt::ContentMetaType_SystemUpdate)
{
const nn::hac::sSystemUpdateMetaExtendedHeader* meta = (const nn::hac::sSystemUpdateMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader));
const pie::hac::sSystemUpdateMetaExtendedHeader* meta = (const pie::hac::sSystemUpdateMetaExtendedHeader*)(sample.data() + sizeof(pie::hac::sContentMetaHeader));
minimum_size += meta->extended_data_size.unwrap();
}
@ -997,12 +1113,12 @@ bool nstool::SettingsInitializer::determineValidCnmtFromSample(const tc::ByteDat
bool nstool::SettingsInitializer::determineValidNacpFromSample(const tc::ByteData& sample) const
{
if (sample.size() != sizeof(nn::hac::sApplicationControlProperty))
if (sample.size() != sizeof(pie::hac::sApplicationControlProperty))
return false;
const nn::hac::sApplicationControlProperty* data = (const nn::hac::sApplicationControlProperty*)sample.data();
const pie::hac::sApplicationControlProperty* data = (const pie::hac::sApplicationControlProperty*)sample.data();
if (data->logo_type > (byte_t)nn::hac::nacp::LogoType::Nintendo)
if (data->logo_type > (byte_t)pie::hac::nacp::LogoType_Nintendo)
return false;
if (data->display_version[0] == 0)
@ -1022,7 +1138,7 @@ bool nstool::SettingsInitializer::determineValidNacpFromSample(const tc::ByteDat
bool nstool::SettingsInitializer::determineValidEsCertFromSample(const tc::ByteData& sample) const
{
nn::pki::SignatureBlock sign;
pie::hac::es::SignatureBlock sign;
try
{
@ -1036,7 +1152,7 @@ bool nstool::SettingsInitializer::determineValidEsCertFromSample(const tc::ByteD
if (sign.isLittleEndian() == true)
return false;
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)
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)
return false;
return true;
@ -1044,7 +1160,7 @@ bool nstool::SettingsInitializer::determineValidEsCertFromSample(const tc::ByteD
bool nstool::SettingsInitializer::determineValidEsTikFromSample(const tc::ByteData& sample) const
{
nn::pki::SignatureBlock sign;
pie::hac::es::SignatureBlock sign;
try
{
@ -1058,13 +1174,13 @@ bool nstool::SettingsInitializer::determineValidEsTikFromSample(const tc::ByteDa
if (sign.isLittleEndian() == false)
return false;
if (sign.getSignType() != nn::pki::sign::SIGN_ID_RSA2048_SHA256)
if (sign.getSignType() != pie::hac::es::sign::SIGN_ID_RSA2048_SHA256)
return false;
const nn::es::sTicketBody_v2* body = (const nn::es::sTicketBody_v2*)(sample.data() + sign.getBytes().size());
const pie::hac::es::sTicketBody_v2* body = (const pie::hac::es::sTicketBody_v2*)(sample.data() + sign.getBytes().size());
if ((body->issuer.str().substr(0, 5) == "Root-"
&& body->issuer.str().substr(16, 2) == "XS") == false)
if ((body->issuer.decode().substr(0, 5) == "Root-"
&& body->issuer.decode().substr(16, 2) == "XS") == false)
return false;
return true;

View file

@ -76,6 +76,7 @@ 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
@ -110,6 +111,8 @@ 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>();
}
@ -133,11 +136,15 @@ 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;
tc::Optional<tc::io::Path> mTikPath;
std::vector<tc::io::Path> mTikPathList;
//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,6 +75,7 @@ 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 1
#define VER_MINOR 6
#define VER_PATCH 3
#define VER_MAJOR 0
#define VER_MINOR 0
#define VER_PATCH 0
#define AUTHORS "jakcron"