From fe6f4422dd6a6228b72c0e801c12aec63fca8537 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Tue, 5 Apr 2022 18:23:46 -0700 Subject: [PATCH] Support reading the initial data/key area of xci files --- build/CodeGen/results.csv | 123 +++++--- src/LibHac/Common/FixedArrays/Array192.cs | 31 ++ src/LibHac/Common/FixedArrays/Array452.cs | 33 +++ src/LibHac/Common/FixedArrays/Array464.cs | 33 +++ src/LibHac/Common/Keys/DefaultKeySet.cs | 1 + src/LibHac/Common/Keys/KeySet.cs | 4 + src/LibHac/Fs/AccessLog.cs | 71 ++++- src/LibHac/Fs/GameCard.cs | 10 +- src/LibHac/Fs/ResultFs.cs | 336 +++++++++++++--------- src/LibHac/FsSrv/EmulatedGameCard.cs | 3 +- src/LibHac/Gc/Impl/GameCardImplTypes.cs | 120 ++++++++ src/LibHac/Tools/Fs/Xci.cs | 7 +- src/LibHac/Tools/Fs/XciHeader.cs | 137 ++++++++- src/hactoolnet/IndentingStringBuilder.cs | 173 +++++++++++ src/hactoolnet/ProcessXci.cs | 126 +++++--- tests/LibHac.Tests/Gc/TypeLayoutTests.cs | 121 ++++++++ 16 files changed, 1103 insertions(+), 226 deletions(-) create mode 100644 src/LibHac/Common/FixedArrays/Array192.cs create mode 100644 src/LibHac/Common/FixedArrays/Array452.cs create mode 100644 src/LibHac/Common/FixedArrays/Array464.cs create mode 100644 src/hactoolnet/IndentingStringBuilder.cs diff --git a/build/CodeGen/results.csv b/build/CodeGen/results.csv index 64b9689a..49f9eaf2 100644 --- a/build/CodeGen/results.csv +++ b/build/CodeGen/results.csv @@ -164,23 +164,28 @@ Module,DescriptionStart,DescriptionEnd,Flags,Namespace,Name,Summary 2,2499,,,,PortSdCardUnexpected, 2,2500,2999,,,GameCardAccessFailed, +2,2501,,,,GameCardUnknown, +2,2502,,,,GameCardUnexpectedDeadCode, 2,2503,,,,GameCardPreconditionViolation, 2,2504,,,,GameCardNotImplemented, -2,2510,,,,GameCardNoAvailableLockers, -2,2511,,,,GameCardLockerIndexOutOfRange, +2,2510,,,,GameCardQueueFullFailure, +2,2511,,,,GameCardLockerOutOfRange, +2,2516,,,,GameCardFailedIoMappingForGpio, 2,2520,,,,GameCardCardNotInserted, -2,2521,,,,InvalidGameCardIdInSpecificData, +2,2521,,,,GameCardCardIdMismatch, 2,2522,,,,GameCardCardNotActivated, -2,2523,,,,InvalidCommandForDeactivatedGameCardAsic, +2,2523,,,,GameCardNotAwakened, +2,2530,2559,,,GameCardCardAccessFailure, 2,2531,,,,GameCardCardAccessTimeout, -2,2532,,,,GameCardStatusFatalError, -2,2533,,,,GameCardReadFailure, -2,2536,,,,GameCardRetryLimitHit, -2,2537,,,,GameCardStatusRefreshRequested, -2,2538,,,,GameCardStatusCrcErrorAndRefreshRequested, +2,2532,,,,GameCardCardFatal, +2,2533,,,,GameCardCardNeedRetry, +2,2534,,,,GameCardCardRetryFailure, +2,2536,,,,GameCardRetryLimitOut, +2,2537,2538,,,GameCardNeedRefresh, +2,2538,,,,GameCardNeedRefreshAndCardNeedRetry, 2,2540,,,,GameCardInvalidSecureAccess, 2,2541,,,,GameCardInvalidNormalAccess, @@ -196,39 +201,48 @@ Module,DescriptionStart,DescriptionEnd,Flags,Namespace,Name,Summary 2,2552,,,,GameCardCardReinitializeFailure, 2,2553,,,,GameCardInvalidChallengeCardExistenceMode, 2,2554,,,,GameCardInvalidCardHeader, -2,2555,,,,GameCardInvalidCardCertificate, +2,2555,,,,GameCardInvalidT1CardCertificate, -2,2557,,,,, -2,2558,,,,, +2,2557,,,,GameCardInvalidCa10Certificate, +2,2558,,,,GameCardInvalidCa10CardHeader, 2,2565,2595,,,GameCardCommunicationFailure, +2,2566,,,,GameCardFinishOperationFailed, -2,2599,,,,GameCardInvalidStateTransition, -2,2600,,,,GameCardAsicInvalidTransitionToNormalMode, -2,2601,,,,GameCardAsicInvalidTransitionToSecureMode, -2,2602,,,,GameCardAsicInvalidTransitionToWriteMode, +2,2597,2627,,,GameCardStateTransitionFailure, +2,2598,,,,GameCardAlreadyTransitionedState, +2,2599,,,,GameCardShouldTransitFromAsicInitialToSecure, +2,2600,,,,GameCardShouldTransitFromInitialToNormal, +2,2601,,,,GameCardShouldTransitFromNormalModeToSecure, +2,2602,,,,GameCardShouldTransitFromNormalModeToDebug, -2,2629,,,,GameCardAsicInitializationFailureForWriterFirmware, -2,2630,2669,,,GameCardAsicInitializationFailure, -2,2631,,,,GameCardAsicGetDeviceStatusFailure, -2,2632,,,,GameCardAsicActivationFailure, -2,2634,,,,GameCardAsicSetUserAsicFirmwareFailure, -2,2637,,,,GameCardAsicGetAsicCertFailure, +2,2629,2669,,,GameCardInitializeAsicFailure, +2,2630,,,,GameCardAlreadyInitializedAsic, +2,2631,2632,,,GameCardActivateAsicFailure, +2,2632,,,,GameCardAsicBootFailure, +2,2634,,,,GameCardSendFirmwareFailure, + +2,2636,2641,,,GameCardVerifyCertificateFailure, +2,2637,,,,GameCardReceiveCertificateFailure, 2,2638,,,,GameCardParseCertificateFailure, -2,2639,,,,InvalidGameCardAsicCertificate, -2,2640,,,,GameCardAsicSetEmmcEmbeddedSocCertificateFailure, -2,2645,,,,GameCardAsicGetAsicEncryptedMessageFailure, -2,2646,,,,GameCardAsicSetLibraryEncryptedMessageFailure, +2,2639,,,,GameCardInvalidCertificate, +2,2640,,,,GameCardSendSocCertificateFailure, -2,2651,,,,GameCardAsicGetAsicAuthenticationDataFailure, -2,2652,,,,GameCardAsicSetAsicAuthenticationDataHashFailure, -2,2653,,,,GameCardAsicSetLibraryAuthenticationDataFailure, -2,2654,,,,GameCardAsicGetLibraryAuthenticationDataHashFailure, -2,2655,,,,GameCardInvalidLibraryAuthenticationDataHash, -2,2658,,,,GameCardAsicEnterSecureAsicModeFailure, -2,2659,,,,GameCardAsicExchangeRandomValuesInSecureModeFailure, +2,2644,2647,,,GameCardGenerateCommonKeyFailure, +2,2645,,,,GameCardReceiveRandomValueFailure, +2,2646,,,,GameCardSendRandomValueFailure, +2,2647,,,,GameCardDecryptRandomValueFailure, + +2,2650,2655,,,GameCardAuthenticateMutuallyFailure, +2,2651,,,,GameCardReceiveDeviceChallengeFailure, +2,2652,,,,GameCardRespondDeviceChallengeFailure, +2,2653,,,,GameCardSendHostChallengeFailure, +2,2654,,,,GameCardReceiveChallengeResponseFailure, +2,2655,,,,GameCardChallengeAndResponseFailure, +2,2658,,,,GameCardChangeModeToSecureFailure, +2,2659,,,,GameCardExchangeRandomValuesFailure, 2,2660,,,,GameCardAsicChallengeCardExistenceFailure, -2,2663,,,,GameCardAsicActivationTimeout, +2,2663,,,,GameCardInitializeAsicTimeOut, 2,2665,2669,,,GameCardSplFailure, 2,2666,,,,GameCardSplDecryptAesKeyFailure, @@ -236,33 +250,49 @@ Module,DescriptionStart,DescriptionEnd,Flags,Namespace,Name,Summary 2,2668,,,,GameCardSplGenerateRandomBytesFailure, 2,2669,,,,GameCardSplDecryptGcMessageFailure, -2,2671,,,,GameCardAsicReadAsicRegisterFailure, -2,2672,,,,GameCardAsicWriteAsicRegisterFailure, -2,2673,,,,GameCardAsicEnableCardBusFailure, -2,2674,,,,GameCardAsicGetCardHeaderFailure, +2,2671,,,,GameCardReadRegisterFailure, +2,2672,,,,GameCardWriteRegisterFailure, +2,2673,,,,GameCardEnableCardBusFailure, +2,2674,,,,GameCardGetCardHeaderFailure, 2,2675,,,,GameCardAsicStatusError, -2,2676,,,,GameCardAsicGetCardKeyAreaFailure, -2,2677,,,,GameCardAsicChangeDebugModeFailure, -2,2678,,,,GameCardAsicGetRmaInformationFailure, -2,2680,,,,GameCardAsicStatusBit22Set, -2,2681,,,,GameCardSecureValuesNotInitialized, -2,2692,,,,InvalidSecureGameCardCommand, -2,2693,,,,InvalidWriteGameCardCommand, +2,2676,,,,GameCardChangeGcModeToSecureFailure, +2,2677,,,,GameCardChangeGcModeToDebugFailure, +2,2678,,,,GameCardReadRmaInfoFailure, +2,2680,2683,,,GameCardUpdateKeyFailure, +2,2681,,,,GameCardKeySourceNotFound, +2,2690,2695,,,GameCardStateFailure, +2,2691,,,,GameCardStateCardNormalModeRequired, +2,2692,,,,GameCardStateCardSecureModeRequired, +2,2693,,,,GameCardStateCardDebugModeRequired, +2,2694,,,,GameCardStateAsicInitialRequired, +2,2695,,,,GameCardStateAsicSecureRequired, + +2,2700,2708,,,GameCardGeneralIoFailure, +2,2701,,,,GameCardGeneralIoReleaseAsicResetFailure, +2,2702,,,,GameCardGeneralIoHoldAsicResetFailure, 2,2703,,,,GameCardSetVoltageFailure, +2,2710,2718,,,GameCardDataIoFailure, +2,2711,,,,GameCardDataIoActivateFailure, + +2,2730,2749,,,GameCardCardCommandFailure, 2,2731,,,,GameCardCommandReadId1Failure, 2,2732,,,,GameCardCommandReadId2Failure, 2,2733,,,,GameCardCommandReadId3Failure, 2,2735,,,,GameCardCommandReadPageFailure, +2,2734,,,,GameCardSendCardReadUidFailure, 2,2736,,,,GameCardCommandReadPageUnalignedFailure, 2,2737,,,,GameCardCommandWritePageFailure, 2,2738,,,,GameCardCommandRefreshFailure, 2,2739,,,,GameCardCommandUpdateKeyFailure, +2,2740,,,,GameCardSendCardSelfRefreshFailure, +2,2741,,,,GameCardSendCardReadRefreshStatusFailure, 2,2742,,,,GameCardCommandReadCrcFailure, 2,2743,,,,GameCardCommandEraseFailure, 2,2744,,,,GameCardCommandReadDevParamFailure, 2,2745,,,,GameCardCommandWriteDevParamFailure, +2,2746,,,,GameCardSendCardReadErrorCountFailure, 2,2900,2919,,,GameCardDevCardUnexpectedFailure, 2,2901,,,,GameCardDebugParameterMismatch, @@ -275,6 +305,7 @@ Module,DescriptionStart,DescriptionEnd,Flags,Namespace,Name,Summary 2,2950,2998,,,GameCardFsFailure, 2,2951,,,,GameCardFsGetHandleFailure, 2,2952,,,,GameCardFsCheckHandleInReadFailure, +2,2953,,,,GameCardFsCheckHandleInWriteFailure, 2,2954,,,,GameCardFsCheckHandleInGetStatusFailure, 2,2955,,,,GameCardFsCheckHandleInGetDeviceCertFailure, 2,2956,,,,GameCardFsCheckHandleInGetCardImageHashFailure, @@ -284,7 +315,7 @@ Module,DescriptionStart,DescriptionEnd,Flags,Namespace,Name,Summary 2,2960,,,,GameCardFsCheckHandleInCreateReadOnlyFailure, 2,2961,,,,GameCardFsCheckHandleInCreateSecureReadOnlyFailure, 2,2962,,,,GameCardFsInvalidCompatibilityType, -2,2963,,,,GameCardsNotSupportedOnDeviceModel, +2,2963,,,,GameCardNotSupportedOnDeviceModel, 2,3000,7999,,,Internal, 2,3001,,,,NotImplemented, diff --git a/src/LibHac/Common/FixedArrays/Array192.cs b/src/LibHac/Common/FixedArrays/Array192.cs new file mode 100644 index 00000000..6c4d0c77 --- /dev/null +++ b/src/LibHac/Common/FixedArrays/Array192.cs @@ -0,0 +1,31 @@ +#pragma warning disable CS0169, CS0649, IDE0051 // Field is never used, Field is never assigned to, Remove unused private members +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace LibHac.Common.FixedArrays; + +public struct Array192 +{ + public const int Length = 192; + + private Array128 _0; + private Array64 _128; + + public ref T this[int i] => ref Items[i]; + + public Span Items + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.Items), Length); + } + + public readonly ReadOnlySpan ItemsRo + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.ItemsRo), Length); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(in Array192 value) => value.ItemsRo; +} \ No newline at end of file diff --git a/src/LibHac/Common/FixedArrays/Array452.cs b/src/LibHac/Common/FixedArrays/Array452.cs new file mode 100644 index 00000000..723f14a3 --- /dev/null +++ b/src/LibHac/Common/FixedArrays/Array452.cs @@ -0,0 +1,33 @@ +#pragma warning disable CS0169, CS0649, IDE0051 // Field is never used, Field is never assigned to, Remove unused private members +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace LibHac.Common.FixedArrays; + +public struct Array452 +{ + public const int Length = 452; + + private Array256 _0; + private Array128 _256; + private Array64 _384; + private Array4 _448; + + public ref T this[int i] => ref Items[i]; + + public Span Items + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.Items), Length); + } + + public readonly ReadOnlySpan ItemsRo + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.ItemsRo), Length); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(in Array452 value) => value.ItemsRo; +} \ No newline at end of file diff --git a/src/LibHac/Common/FixedArrays/Array464.cs b/src/LibHac/Common/FixedArrays/Array464.cs new file mode 100644 index 00000000..beada3bf --- /dev/null +++ b/src/LibHac/Common/FixedArrays/Array464.cs @@ -0,0 +1,33 @@ +#pragma warning disable CS0169, CS0649, IDE0051 // Field is never used, Field is never assigned to, Remove unused private members +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace LibHac.Common.FixedArrays; + +public struct Array464 +{ + public const int Length = 464; + + private Array256 _0; + private Array128 _256; + private Array64 _384; + private Array16 _448; + + public ref T this[int i] => ref Items[i]; + + public Span Items + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.Items), Length); + } + + public readonly ReadOnlySpan ItemsRo + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.ItemsRo), Length); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(in Array464 value) => value.ItemsRo; +} \ No newline at end of file diff --git a/src/LibHac/Common/Keys/DefaultKeySet.cs b/src/LibHac/Common/Keys/DefaultKeySet.cs index eaa95a3f..3e5e8acc 100644 --- a/src/LibHac/Common/Keys/DefaultKeySet.cs +++ b/src/LibHac/Common/Keys/DefaultKeySet.cs @@ -167,6 +167,7 @@ internal static partial class DefaultKeySet keys.Add(new KeyInfo(264, Type.CommonSeed, "sd_card_custom_storage_key_source", (set, _) => set.SdCardKeySources[2])); keys.Add(new KeyInfo(270, Type.CommonSeedDiff, "xci_header_key", (set, _) => set.XciHeaderKey)); + keys.Add(new KeyInfo(271, Type.CommonRoot, "xci_t1_titlekey_kek", 0, 0x10, (set, i) => set.GcTitleKeyKeks[i])); keys.Add(new KeyInfo(280, Type.CommonRoot, "eticket_rsa_kek", (set, _) => set.ETicketRsaKek)); keys.Add(new KeyInfo(281, Type.CommonRoot, "ssl_rsa_kek", (set, _) => set.SslRsaKek)); diff --git a/src/LibHac/Common/Keys/KeySet.cs b/src/LibHac/Common/Keys/KeySet.cs index 95974f29..a70dee9d 100644 --- a/src/LibHac/Common/Keys/KeySet.cs +++ b/src/LibHac/Common/Keys/KeySet.cs @@ -54,6 +54,7 @@ public class KeySet public Span TsecAuthSignatures => RootKeys.TsecAuthSignatures.Items; public Span TsecRootKeys => RootKeys.TsecRootKeys.Items; public Span MasterKekSources => _keys.KeySeeds.MasterKekSources.Items; + public Span GcTitleKeyKeks => RootKeys.GcTitleKeyKeks.Items; public Span MarikoMasterKekSources => _mode == Mode.Dev ? _keys.KeySeeds.MarikoMasterKekSourcesDev.Items @@ -293,6 +294,9 @@ public struct RootKeys // Derived by TSEC. This is the first public root key for >= 6.2.0 Erista public Array32 TsecRootKeys; + + // Used to decrypt the title keys found in an XCI's initial data + public Array16 GcTitleKeyKeks; } public struct KeySeeds diff --git a/src/LibHac/Fs/AccessLog.cs b/src/LibHac/Fs/AccessLog.cs index 00b45b74..74672ee4 100644 --- a/src/LibHac/Fs/AccessLog.cs +++ b/src/LibHac/Fs/AccessLog.cs @@ -11,6 +11,7 @@ using LibHac.Fs.Fsa; using LibHac.Fs.Impl; using LibHac.Fs.Shim; using LibHac.FsSrv.Sf; +using LibHac.Gc.Impl; using LibHac.Os; using LibHac.Sf; using static LibHac.Fs.Impl.AccessLogStrings; @@ -158,7 +159,7 @@ namespace LibHac.Fs.Impl public static IdentifyAccessLogHandle MakeHandle(object handle) => new IdentifyAccessLogHandle(handle); } - internal struct IdString + public struct IdString { private Buffer32 _buffer; @@ -296,6 +297,74 @@ namespace LibHac.Fs.Impl default: return ToValueString((int)value.Flags); } } + + public ReadOnlySpan ToString(MemoryCapacity value) + { + switch (value) + { + case MemoryCapacity.Capacity1GB: return new[] { (byte)'1', (byte)'G', (byte)'B' }; + case MemoryCapacity.Capacity2GB: return new[] { (byte)'2', (byte)'G', (byte)'B' }; + case MemoryCapacity.Capacity4GB: return new[] { (byte)'4', (byte)'G', (byte)'B' }; + case MemoryCapacity.Capacity8GB: return new[] { (byte)'8', (byte)'G', (byte)'B' }; + case MemoryCapacity.Capacity16GB: return new[] { (byte)'1', (byte)'6', (byte)'G', (byte)'B' }; + case MemoryCapacity.Capacity32GB: return new[] { (byte)'3', (byte)'2', (byte)'G', (byte)'B' }; + default: return ToValueString((int)value); + } + } + + public ReadOnlySpan ToString(SelSec value) + { + switch (value) + { + case SelSec.T1: return new[] { (byte)'T', (byte)'1' }; + case SelSec.T2: return new[] { (byte)'T', (byte)'2' }; + default: return ToValueString((int)value); + } + } + + public ReadOnlySpan ToString(KekIndex value) + { + switch (value) + { + case KekIndex.Version0: return new[] { (byte)'V', (byte)'e', (byte)'r', (byte)'s', (byte)'i', (byte)'o', (byte)'n', (byte)'0' }; + case KekIndex.ForDev: return new[] { (byte)'V', (byte)'e', (byte)'r', (byte)'s', (byte)'i', (byte)'o', (byte)'n', (byte)'F', (byte)'o', (byte)'r', (byte)'D', (byte)'e', (byte)'v' }; + default: return ToValueString((int)value); + } + } + + public ReadOnlySpan ToString(AccessControl1ClockRate value) + { + switch (value) + { + case AccessControl1ClockRate.ClockRate25MHz: return new[] { (byte)'2', (byte)'5', (byte)' ', (byte)'M', (byte)'H', (byte)'z' }; + case AccessControl1ClockRate.ClockRate50MHz: return new[] { (byte)'5', (byte)'0', (byte)' ', (byte)'M', (byte)'H', (byte)'z' }; + default: return ToValueString((int)value); + } + } + + public ReadOnlySpan ToString(FwVersion value) + { + switch (value) + { + case FwVersion.ForDev: return new[] { (byte)'F', (byte)'o', (byte)'r', (byte)'D', (byte)'e', (byte)'v' }; + case FwVersion.Since1_0_0: return new[] { (byte)'1', (byte)'.', (byte)'0', (byte)'.', (byte)'0' }; + case FwVersion.Since4_0_0: return new[] { (byte)'4', (byte)'.', (byte)'0', (byte)'.', (byte)'0' }; + case FwVersion.Since9_0_0: return new[] { (byte)'9', (byte)'.', (byte)'0', (byte)'.', (byte)'0' }; + case FwVersion.Since11_0_0: return new[] { (byte)'1', (byte)'1', (byte)'.', (byte)'0', (byte)'.', (byte)'0' }; + case FwVersion.Since12_0_0: return new[] { (byte)'1', (byte)'2', (byte)'.', (byte)'0', (byte)'.', (byte)'0' }; + default: return ToValueString((int)value); + } + } + + public ReadOnlySpan ToString(GameCardCompatibilityType value) + { + switch (value) + { + case GameCardCompatibilityType.Normal: return new[] { (byte)'N', (byte)'o', (byte)'r', (byte)'m', (byte)'a', (byte)'l' }; + case GameCardCompatibilityType.Terra: return new[] { (byte)'T', (byte)'e', (byte)'r', (byte)'r', (byte)'a' }; + default: return ToValueString((int)value); + } + } } internal delegate int AccessLogPrinterCallback(Span textBuffer); diff --git a/src/LibHac/Fs/GameCard.cs b/src/LibHac/Fs/GameCard.cs index 73d4fb11..c4a22cf8 100644 --- a/src/LibHac/Fs/GameCard.cs +++ b/src/LibHac/Fs/GameCard.cs @@ -40,7 +40,15 @@ public enum GameCardAttribute : byte HistoryEraseFlag = 1 << 1, RepairToolFlag = 1 << 2, DifferentRegionCupToTerraDeviceFlag = 1 << 3, - DifferentRegionCupToGlobalDeviceFlag = 1 << 4 + DifferentRegionCupToGlobalDeviceFlag = 1 << 4, + + HasCa10CertificateFlag = 1 << 7 +} + +public enum GameCardCompatibilityType : byte +{ + Normal = 0, + Terra = 1 } public struct GameCardErrorInfo diff --git a/src/LibHac/Fs/ResultFs.cs b/src/LibHac/Fs/ResultFs.cs index 0c000df1..b81011f9 100644 --- a/src/LibHac/Fs/ResultFs.cs +++ b/src/LibHac/Fs/ResultFs.cs @@ -240,123 +240,156 @@ public static class ResultFs /// Error code: 2002-2500; Range: 2500-2999; Inner value: 0x138802 public static Result.Base GameCardAccessFailed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2500, 2999); } + /// Error code: 2002-2501; Inner value: 0x138a02 + public static Result.Base GameCardUnknown => new Result.Base(ModuleFs, 2501); + /// Error code: 2002-2502; Inner value: 0x138c02 + public static Result.Base GameCardUnexpectedDeadCode => new Result.Base(ModuleFs, 2502); /// Error code: 2002-2503; Inner value: 0x138e02 public static Result.Base GameCardPreconditionViolation => new Result.Base(ModuleFs, 2503); /// Error code: 2002-2504; Inner value: 0x139002 public static Result.Base GameCardNotImplemented => new Result.Base(ModuleFs, 2504); /// Error code: 2002-2510; Inner value: 0x139c02 - public static Result.Base GameCardNoAvailableLockers => new Result.Base(ModuleFs, 2510); + public static Result.Base GameCardQueueFullFailure => new Result.Base(ModuleFs, 2510); /// Error code: 2002-2511; Inner value: 0x139e02 - public static Result.Base GameCardLockerIndexOutOfRange => new Result.Base(ModuleFs, 2511); + public static Result.Base GameCardLockerOutOfRange => new Result.Base(ModuleFs, 2511); + /// Error code: 2002-2516; Inner value: 0x13a802 + public static Result.Base GameCardFailedIoMappingForGpio => new Result.Base(ModuleFs, 2516); /// Error code: 2002-2520; Inner value: 0x13b002 public static Result.Base GameCardCardNotInserted => new Result.Base(ModuleFs, 2520); /// Error code: 2002-2521; Inner value: 0x13b202 - public static Result.Base InvalidGameCardIdInSpecificData => new Result.Base(ModuleFs, 2521); + public static Result.Base GameCardCardIdMismatch => new Result.Base(ModuleFs, 2521); /// Error code: 2002-2522; Inner value: 0x13b402 public static Result.Base GameCardCardNotActivated => new Result.Base(ModuleFs, 2522); /// Error code: 2002-2523; Inner value: 0x13b602 - public static Result.Base InvalidCommandForDeactivatedGameCardAsic => new Result.Base(ModuleFs, 2523); - /// Error code: 2002-2531; Inner value: 0x13c602 - public static Result.Base GameCardCardAccessTimeout => new Result.Base(ModuleFs, 2531); - /// Error code: 2002-2532; Inner value: 0x13c802 - public static Result.Base GameCardStatusFatalError => new Result.Base(ModuleFs, 2532); - /// Error code: 2002-2533; Inner value: 0x13ca02 - public static Result.Base GameCardReadFailure => new Result.Base(ModuleFs, 2533); - /// Error code: 2002-2536; Inner value: 0x13d002 - public static Result.Base GameCardRetryLimitHit => new Result.Base(ModuleFs, 2536); - /// Error code: 2002-2537; Inner value: 0x13d202 - public static Result.Base GameCardStatusRefreshRequested => new Result.Base(ModuleFs, 2537); - /// Error code: 2002-2538; Inner value: 0x13d402 - public static Result.Base GameCardStatusCrcErrorAndRefreshRequested => new Result.Base(ModuleFs, 2538); - /// Error code: 2002-2540; Inner value: 0x13d802 - public static Result.Base GameCardInvalidSecureAccess => new Result.Base(ModuleFs, 2540); - /// Error code: 2002-2541; Inner value: 0x13da02 - public static Result.Base GameCardInvalidNormalAccess => new Result.Base(ModuleFs, 2541); - /// Error code: 2002-2542; Inner value: 0x13dc02 - public static Result.Base GameCardInvalidAccessAcrossMode => new Result.Base(ModuleFs, 2542); + public static Result.Base GameCardNotAwakened => new Result.Base(ModuleFs, 2523); - /// Error code: 2002-2543; Range: 2543-2546; Inner value: 0x13de02 - public static Result.Base GameCardWrongCard { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2543, 2546); } - /// Error code: 2002-2544; Inner value: 0x13e002 - public static Result.Base GameCardInitialDataMismatch => new Result.Base(ModuleFs, 2544); - /// Error code: 2002-2545; Inner value: 0x13e202 - public static Result.Base GameCardInitialNotFilledWithZero => new Result.Base(ModuleFs, 2545); - /// Error code: 2002-2546; Inner value: 0x13e402 - public static Result.Base GameCardKekIndexMismatch => new Result.Base(ModuleFs, 2546); + /// Error code: 2002-2530; Range: 2530-2559; Inner value: 0x13c402 + public static Result.Base GameCardCardAccessFailure { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2530, 2559); } + /// Error code: 2002-2531; Inner value: 0x13c602 + public static Result.Base GameCardCardAccessTimeout => new Result.Base(ModuleFs, 2531); + /// Error code: 2002-2532; Inner value: 0x13c802 + public static Result.Base GameCardCardFatal => new Result.Base(ModuleFs, 2532); + /// Error code: 2002-2533; Inner value: 0x13ca02 + public static Result.Base GameCardCardNeedRetry => new Result.Base(ModuleFs, 2533); + /// Error code: 2002-2534; Inner value: 0x13cc02 + public static Result.Base GameCardCardRetryFailure => new Result.Base(ModuleFs, 2534); + /// Error code: 2002-2536; Inner value: 0x13d002 + public static Result.Base GameCardRetryLimitOut => new Result.Base(ModuleFs, 2536); - /// Error code: 2002-2548; Inner value: 0x13e802 - public static Result.Base GameCardInvalidGetCardDeviceCertificate => new Result.Base(ModuleFs, 2548); - /// Error code: 2002-2549; Inner value: 0x13ea02 - public static Result.Base GameCardUnregisteredCardSecureMethod => new Result.Base(ModuleFs, 2549); - /// Error code: 2002-2550; Inner value: 0x13ec02 - public static Result.Base GameCardCardNeedRetryAfterAsicReinitialize => new Result.Base(ModuleFs, 2550); - /// Error code: 2002-2551; Inner value: 0x13ee02 - public static Result.Base GameCardCardHeaderReadFailure => new Result.Base(ModuleFs, 2551); - /// Error code: 2002-2552; Inner value: 0x13f002 - public static Result.Base GameCardCardReinitializeFailure => new Result.Base(ModuleFs, 2552); - /// Error code: 2002-2553; Inner value: 0x13f202 - public static Result.Base GameCardInvalidChallengeCardExistenceMode => new Result.Base(ModuleFs, 2553); - /// Error code: 2002-2554; Inner value: 0x13f402 - public static Result.Base GameCardInvalidCardHeader => new Result.Base(ModuleFs, 2554); - /// Error code: 2002-2555; Inner value: 0x13f602 - public static Result.Base GameCardInvalidCardCertificate => new Result.Base(ModuleFs, 2555); - /// Error code: 2002-2557; Inner value: 0x13fa02 - public static Result.Base Result2557 => new Result.Base(ModuleFs, 2557); - /// Error code: 2002-2558; Inner value: 0x13fc02 - public static Result.Base Result2558 => new Result.Base(ModuleFs, 2558); + /// Error code: 2002-2537; Range: 2537-2538; Inner value: 0x13d202 + public static Result.Base GameCardNeedRefresh { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2537, 2538); } + /// Error code: 2002-2538; Inner value: 0x13d402 + public static Result.Base GameCardNeedRefreshAndCardNeedRetry => new Result.Base(ModuleFs, 2538); + + /// Error code: 2002-2540; Inner value: 0x13d802 + public static Result.Base GameCardInvalidSecureAccess => new Result.Base(ModuleFs, 2540); + /// Error code: 2002-2541; Inner value: 0x13da02 + public static Result.Base GameCardInvalidNormalAccess => new Result.Base(ModuleFs, 2541); + /// Error code: 2002-2542; Inner value: 0x13dc02 + public static Result.Base GameCardInvalidAccessAcrossMode => new Result.Base(ModuleFs, 2542); + + /// Error code: 2002-2543; Range: 2543-2546; Inner value: 0x13de02 + public static Result.Base GameCardWrongCard { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2543, 2546); } + /// Error code: 2002-2544; Inner value: 0x13e002 + public static Result.Base GameCardInitialDataMismatch => new Result.Base(ModuleFs, 2544); + /// Error code: 2002-2545; Inner value: 0x13e202 + public static Result.Base GameCardInitialNotFilledWithZero => new Result.Base(ModuleFs, 2545); + /// Error code: 2002-2546; Inner value: 0x13e402 + public static Result.Base GameCardKekIndexMismatch => new Result.Base(ModuleFs, 2546); + + /// Error code: 2002-2548; Inner value: 0x13e802 + public static Result.Base GameCardInvalidGetCardDeviceCertificate => new Result.Base(ModuleFs, 2548); + /// Error code: 2002-2549; Inner value: 0x13ea02 + public static Result.Base GameCardUnregisteredCardSecureMethod => new Result.Base(ModuleFs, 2549); + /// Error code: 2002-2550; Inner value: 0x13ec02 + public static Result.Base GameCardCardNeedRetryAfterAsicReinitialize => new Result.Base(ModuleFs, 2550); + /// Error code: 2002-2551; Inner value: 0x13ee02 + public static Result.Base GameCardCardHeaderReadFailure => new Result.Base(ModuleFs, 2551); + /// Error code: 2002-2552; Inner value: 0x13f002 + public static Result.Base GameCardCardReinitializeFailure => new Result.Base(ModuleFs, 2552); + /// Error code: 2002-2553; Inner value: 0x13f202 + public static Result.Base GameCardInvalidChallengeCardExistenceMode => new Result.Base(ModuleFs, 2553); + /// Error code: 2002-2554; Inner value: 0x13f402 + public static Result.Base GameCardInvalidCardHeader => new Result.Base(ModuleFs, 2554); + /// Error code: 2002-2555; Inner value: 0x13f602 + public static Result.Base GameCardInvalidT1CardCertificate => new Result.Base(ModuleFs, 2555); + /// Error code: 2002-2557; Inner value: 0x13fa02 + public static Result.Base GameCardInvalidCa10Certificate => new Result.Base(ModuleFs, 2557); + /// Error code: 2002-2558; Inner value: 0x13fc02 + public static Result.Base GameCardInvalidCa10CardHeader => new Result.Base(ModuleFs, 2558); /// Error code: 2002-2565; Range: 2565-2595; Inner value: 0x140a02 public static Result.Base GameCardCommunicationFailure { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2565, 2595); } + /// Error code: 2002-2566; Inner value: 0x140c02 + public static Result.Base GameCardFinishOperationFailed => new Result.Base(ModuleFs, 2566); - /// Error code: 2002-2599; Inner value: 0x144e02 - public static Result.Base GameCardInvalidStateTransition => new Result.Base(ModuleFs, 2599); - /// Error code: 2002-2600; Inner value: 0x145002 - public static Result.Base GameCardAsicInvalidTransitionToNormalMode => new Result.Base(ModuleFs, 2600); - /// Error code: 2002-2601; Inner value: 0x145202 - public static Result.Base GameCardAsicInvalidTransitionToSecureMode => new Result.Base(ModuleFs, 2601); - /// Error code: 2002-2602; Inner value: 0x145402 - public static Result.Base GameCardAsicInvalidTransitionToWriteMode => new Result.Base(ModuleFs, 2602); - /// Error code: 2002-2629; Inner value: 0x148a02 - public static Result.Base GameCardAsicInitializationFailureForWriterFirmware => new Result.Base(ModuleFs, 2629); + /// Error code: 2002-2597; Range: 2597-2627; Inner value: 0x144a02 + public static Result.Base GameCardStateTransitionFailure { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2597, 2627); } + /// Error code: 2002-2598; Inner value: 0x144c02 + public static Result.Base GameCardAlreadyTransitionedState => new Result.Base(ModuleFs, 2598); + /// Error code: 2002-2599; Inner value: 0x144e02 + public static Result.Base GameCardShouldTransitFromAsicInitialToSecure => new Result.Base(ModuleFs, 2599); + /// Error code: 2002-2600; Inner value: 0x145002 + public static Result.Base GameCardShouldTransitFromInitialToNormal => new Result.Base(ModuleFs, 2600); + /// Error code: 2002-2601; Inner value: 0x145202 + public static Result.Base GameCardShouldTransitFromNormalModeToSecure => new Result.Base(ModuleFs, 2601); + /// Error code: 2002-2602; Inner value: 0x145402 + public static Result.Base GameCardShouldTransitFromNormalModeToDebug => new Result.Base(ModuleFs, 2602); + + /// Error code: 2002-2629; Range: 2629-2669; Inner value: 0x148a02 + public static Result.Base GameCardInitializeAsicFailure { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2629, 2669); } + /// Error code: 2002-2630; Inner value: 0x148c02 + public static Result.Base GameCardAlreadyInitializedAsic => new Result.Base(ModuleFs, 2630); + + /// Error code: 2002-2631; Range: 2631-2632; Inner value: 0x148e02 + public static Result.Base GameCardActivateAsicFailure { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2631, 2632); } + /// Error code: 2002-2632; Inner value: 0x149002 + public static Result.Base GameCardAsicBootFailure => new Result.Base(ModuleFs, 2632); - /// Error code: 2002-2630; Range: 2630-2669; Inner value: 0x148c02 - public static Result.Base GameCardAsicInitializationFailure { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2630, 2669); } - /// Error code: 2002-2631; Inner value: 0x148e02 - public static Result.Base GameCardAsicGetDeviceStatusFailure => new Result.Base(ModuleFs, 2631); - /// Error code: 2002-2632; Inner value: 0x149002 - public static Result.Base GameCardAsicActivationFailure => new Result.Base(ModuleFs, 2632); /// Error code: 2002-2634; Inner value: 0x149402 - public static Result.Base GameCardAsicSetUserAsicFirmwareFailure => new Result.Base(ModuleFs, 2634); - /// Error code: 2002-2637; Inner value: 0x149a02 - public static Result.Base GameCardAsicGetAsicCertFailure => new Result.Base(ModuleFs, 2637); - /// Error code: 2002-2638; Inner value: 0x149c02 - public static Result.Base GameCardParseCertificateFailure => new Result.Base(ModuleFs, 2638); - /// Error code: 2002-2639; Inner value: 0x149e02 - public static Result.Base InvalidGameCardAsicCertificate => new Result.Base(ModuleFs, 2639); - /// Error code: 2002-2640; Inner value: 0x14a002 - public static Result.Base GameCardAsicSetEmmcEmbeddedSocCertificateFailure => new Result.Base(ModuleFs, 2640); - /// Error code: 2002-2645; Inner value: 0x14aa02 - public static Result.Base GameCardAsicGetAsicEncryptedMessageFailure => new Result.Base(ModuleFs, 2645); - /// Error code: 2002-2646; Inner value: 0x14ac02 - public static Result.Base GameCardAsicSetLibraryEncryptedMessageFailure => new Result.Base(ModuleFs, 2646); - /// Error code: 2002-2651; Inner value: 0x14b602 - public static Result.Base GameCardAsicGetAsicAuthenticationDataFailure => new Result.Base(ModuleFs, 2651); - /// Error code: 2002-2652; Inner value: 0x14b802 - public static Result.Base GameCardAsicSetAsicAuthenticationDataHashFailure => new Result.Base(ModuleFs, 2652); - /// Error code: 2002-2653; Inner value: 0x14ba02 - public static Result.Base GameCardAsicSetLibraryAuthenticationDataFailure => new Result.Base(ModuleFs, 2653); - /// Error code: 2002-2654; Inner value: 0x14bc02 - public static Result.Base GameCardAsicGetLibraryAuthenticationDataHashFailure => new Result.Base(ModuleFs, 2654); - /// Error code: 2002-2655; Inner value: 0x14be02 - public static Result.Base GameCardInvalidLibraryAuthenticationDataHash => new Result.Base(ModuleFs, 2655); + public static Result.Base GameCardSendFirmwareFailure => new Result.Base(ModuleFs, 2634); + + /// Error code: 2002-2636; Range: 2636-2641; Inner value: 0x149802 + public static Result.Base GameCardVerifyCertificateFailure { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2636, 2641); } + /// Error code: 2002-2637; Inner value: 0x149a02 + public static Result.Base GameCardReceiveCertificateFailure => new Result.Base(ModuleFs, 2637); + /// Error code: 2002-2638; Inner value: 0x149c02 + public static Result.Base GameCardParseCertificateFailure => new Result.Base(ModuleFs, 2638); + /// Error code: 2002-2639; Inner value: 0x149e02 + public static Result.Base GameCardInvalidCertificate => new Result.Base(ModuleFs, 2639); + /// Error code: 2002-2640; Inner value: 0x14a002 + public static Result.Base GameCardSendSocCertificateFailure => new Result.Base(ModuleFs, 2640); + + /// Error code: 2002-2644; Range: 2644-2647; Inner value: 0x14a802 + public static Result.Base GameCardGenerateCommonKeyFailure { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2644, 2647); } + /// Error code: 2002-2645; Inner value: 0x14aa02 + public static Result.Base GameCardReceiveRandomValueFailure => new Result.Base(ModuleFs, 2645); + /// Error code: 2002-2646; Inner value: 0x14ac02 + public static Result.Base GameCardSendRandomValueFailure => new Result.Base(ModuleFs, 2646); + /// Error code: 2002-2647; Inner value: 0x14ae02 + public static Result.Base GameCardDecryptRandomValueFailure => new Result.Base(ModuleFs, 2647); + + /// Error code: 2002-2650; Range: 2650-2655; Inner value: 0x14b402 + public static Result.Base GameCardAuthenticateMutuallyFailure { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2650, 2655); } + /// Error code: 2002-2651; Inner value: 0x14b602 + public static Result.Base GameCardReceiveDeviceChallengeFailure => new Result.Base(ModuleFs, 2651); + /// Error code: 2002-2652; Inner value: 0x14b802 + public static Result.Base GameCardRespondDeviceChallengeFailure => new Result.Base(ModuleFs, 2652); + /// Error code: 2002-2653; Inner value: 0x14ba02 + public static Result.Base GameCardSendHostChallengeFailure => new Result.Base(ModuleFs, 2653); + /// Error code: 2002-2654; Inner value: 0x14bc02 + public static Result.Base GameCardReceiveChallengeResponseFailure => new Result.Base(ModuleFs, 2654); + /// Error code: 2002-2655; Inner value: 0x14be02 + public static Result.Base GameCardChallengeAndResponseFailure => new Result.Base(ModuleFs, 2655); + /// Error code: 2002-2658; Inner value: 0x14c402 - public static Result.Base GameCardAsicEnterSecureAsicModeFailure => new Result.Base(ModuleFs, 2658); + public static Result.Base GameCardChangeModeToSecureFailure => new Result.Base(ModuleFs, 2658); /// Error code: 2002-2659; Inner value: 0x14c602 - public static Result.Base GameCardAsicExchangeRandomValuesInSecureModeFailure => new Result.Base(ModuleFs, 2659); + public static Result.Base GameCardExchangeRandomValuesFailure => new Result.Base(ModuleFs, 2659); /// Error code: 2002-2660; Inner value: 0x14c802 public static Result.Base GameCardAsicChallengeCardExistenceFailure => new Result.Base(ModuleFs, 2660); /// Error code: 2002-2663; Inner value: 0x14ce02 - public static Result.Base GameCardAsicActivationTimeout => new Result.Base(ModuleFs, 2663); + public static Result.Base GameCardInitializeAsicTimeOut => new Result.Base(ModuleFs, 2663); /// Error code: 2002-2665; Range: 2665-2669; Inner value: 0x14d202 public static Result.Base GameCardSplFailure { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2665, 2669); } @@ -370,55 +403,88 @@ public static class ResultFs public static Result.Base GameCardSplDecryptGcMessageFailure => new Result.Base(ModuleFs, 2669); /// Error code: 2002-2671; Inner value: 0x14de02 - public static Result.Base GameCardAsicReadAsicRegisterFailure => new Result.Base(ModuleFs, 2671); + public static Result.Base GameCardReadRegisterFailure => new Result.Base(ModuleFs, 2671); /// Error code: 2002-2672; Inner value: 0x14e002 - public static Result.Base GameCardAsicWriteAsicRegisterFailure => new Result.Base(ModuleFs, 2672); + public static Result.Base GameCardWriteRegisterFailure => new Result.Base(ModuleFs, 2672); /// Error code: 2002-2673; Inner value: 0x14e202 - public static Result.Base GameCardAsicEnableCardBusFailure => new Result.Base(ModuleFs, 2673); + public static Result.Base GameCardEnableCardBusFailure => new Result.Base(ModuleFs, 2673); /// Error code: 2002-2674; Inner value: 0x14e402 - public static Result.Base GameCardAsicGetCardHeaderFailure => new Result.Base(ModuleFs, 2674); + public static Result.Base GameCardGetCardHeaderFailure => new Result.Base(ModuleFs, 2674); /// Error code: 2002-2675; Inner value: 0x14e602 public static Result.Base GameCardAsicStatusError => new Result.Base(ModuleFs, 2675); /// Error code: 2002-2676; Inner value: 0x14e802 - public static Result.Base GameCardAsicGetCardKeyAreaFailure => new Result.Base(ModuleFs, 2676); + public static Result.Base GameCardChangeGcModeToSecureFailure => new Result.Base(ModuleFs, 2676); /// Error code: 2002-2677; Inner value: 0x14ea02 - public static Result.Base GameCardAsicChangeDebugModeFailure => new Result.Base(ModuleFs, 2677); + public static Result.Base GameCardChangeGcModeToDebugFailure => new Result.Base(ModuleFs, 2677); /// Error code: 2002-2678; Inner value: 0x14ec02 - public static Result.Base GameCardAsicGetRmaInformationFailure => new Result.Base(ModuleFs, 2678); - /// Error code: 2002-2680; Inner value: 0x14f002 - public static Result.Base GameCardAsicStatusBit22Set => new Result.Base(ModuleFs, 2680); - /// Error code: 2002-2681; Inner value: 0x14f202 - public static Result.Base GameCardSecureValuesNotInitialized => new Result.Base(ModuleFs, 2681); - /// Error code: 2002-2692; Inner value: 0x150802 - public static Result.Base InvalidSecureGameCardCommand => new Result.Base(ModuleFs, 2692); - /// Error code: 2002-2693; Inner value: 0x150a02 - public static Result.Base InvalidWriteGameCardCommand => new Result.Base(ModuleFs, 2693); - /// Error code: 2002-2703; Inner value: 0x151e02 - public static Result.Base GameCardSetVoltageFailure => new Result.Base(ModuleFs, 2703); - /// Error code: 2002-2731; Inner value: 0x155602 - public static Result.Base GameCardCommandReadId1Failure => new Result.Base(ModuleFs, 2731); - /// Error code: 2002-2732; Inner value: 0x155802 - public static Result.Base GameCardCommandReadId2Failure => new Result.Base(ModuleFs, 2732); - /// Error code: 2002-2733; Inner value: 0x155a02 - public static Result.Base GameCardCommandReadId3Failure => new Result.Base(ModuleFs, 2733); - /// Error code: 2002-2735; Inner value: 0x155e02 - public static Result.Base GameCardCommandReadPageFailure => new Result.Base(ModuleFs, 2735); - /// Error code: 2002-2736; Inner value: 0x156002 - public static Result.Base GameCardCommandReadPageUnalignedFailure => new Result.Base(ModuleFs, 2736); - /// Error code: 2002-2737; Inner value: 0x156202 - public static Result.Base GameCardCommandWritePageFailure => new Result.Base(ModuleFs, 2737); - /// Error code: 2002-2738; Inner value: 0x156402 - public static Result.Base GameCardCommandRefreshFailure => new Result.Base(ModuleFs, 2738); - /// Error code: 2002-2739; Inner value: 0x156602 - public static Result.Base GameCardCommandUpdateKeyFailure => new Result.Base(ModuleFs, 2739); - /// Error code: 2002-2742; Inner value: 0x156c02 - public static Result.Base GameCardCommandReadCrcFailure => new Result.Base(ModuleFs, 2742); - /// Error code: 2002-2743; Inner value: 0x156e02 - public static Result.Base GameCardCommandEraseFailure => new Result.Base(ModuleFs, 2743); - /// Error code: 2002-2744; Inner value: 0x157002 - public static Result.Base GameCardCommandReadDevParamFailure => new Result.Base(ModuleFs, 2744); - /// Error code: 2002-2745; Inner value: 0x157202 - public static Result.Base GameCardCommandWriteDevParamFailure => new Result.Base(ModuleFs, 2745); + public static Result.Base GameCardReadRmaInfoFailure => new Result.Base(ModuleFs, 2678); + + /// Error code: 2002-2680; Range: 2680-2683; Inner value: 0x14f002 + public static Result.Base GameCardUpdateKeyFailure { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2680, 2683); } + /// Error code: 2002-2681; Inner value: 0x14f202 + public static Result.Base GameCardKeySourceNotFound => new Result.Base(ModuleFs, 2681); + + /// Error code: 2002-2690; Range: 2690-2695; Inner value: 0x150402 + public static Result.Base GameCardStateFailure { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2690, 2695); } + /// Error code: 2002-2691; Inner value: 0x150602 + public static Result.Base GameCardStateCardNormalModeRequired => new Result.Base(ModuleFs, 2691); + /// Error code: 2002-2692; Inner value: 0x150802 + public static Result.Base GameCardStateCardSecureModeRequired => new Result.Base(ModuleFs, 2692); + /// Error code: 2002-2693; Inner value: 0x150a02 + public static Result.Base GameCardStateCardDebugModeRequired => new Result.Base(ModuleFs, 2693); + /// Error code: 2002-2694; Inner value: 0x150c02 + public static Result.Base GameCardStateAsicInitialRequired => new Result.Base(ModuleFs, 2694); + /// Error code: 2002-2695; Inner value: 0x150e02 + public static Result.Base GameCardStateAsicSecureRequired => new Result.Base(ModuleFs, 2695); + + /// Error code: 2002-2700; Range: 2700-2708; Inner value: 0x151802 + public static Result.Base GameCardGeneralIoFailure { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2700, 2708); } + /// Error code: 2002-2701; Inner value: 0x151a02 + public static Result.Base GameCardGeneralIoReleaseAsicResetFailure => new Result.Base(ModuleFs, 2701); + /// Error code: 2002-2702; Inner value: 0x151c02 + public static Result.Base GameCardGeneralIoHoldAsicResetFailure => new Result.Base(ModuleFs, 2702); + /// Error code: 2002-2703; Inner value: 0x151e02 + public static Result.Base GameCardSetVoltageFailure => new Result.Base(ModuleFs, 2703); + + /// Error code: 2002-2710; Range: 2710-2718; Inner value: 0x152c02 + public static Result.Base GameCardDataIoFailure { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2710, 2718); } + /// Error code: 2002-2711; Inner value: 0x152e02 + public static Result.Base GameCardDataIoActivateFailure => new Result.Base(ModuleFs, 2711); + + /// Error code: 2002-2730; Range: 2730-2749; Inner value: 0x155402 + public static Result.Base GameCardCardCommandFailure { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2730, 2749); } + /// Error code: 2002-2731; Inner value: 0x155602 + public static Result.Base GameCardCommandReadId1Failure => new Result.Base(ModuleFs, 2731); + /// Error code: 2002-2732; Inner value: 0x155802 + public static Result.Base GameCardCommandReadId2Failure => new Result.Base(ModuleFs, 2732); + /// Error code: 2002-2733; Inner value: 0x155a02 + public static Result.Base GameCardCommandReadId3Failure => new Result.Base(ModuleFs, 2733); + /// Error code: 2002-2734; Inner value: 0x155c02 + public static Result.Base GameCardSendCardReadUidFailure => new Result.Base(ModuleFs, 2734); + /// Error code: 2002-2735; Inner value: 0x155e02 + public static Result.Base GameCardCommandReadPageFailure => new Result.Base(ModuleFs, 2735); + /// Error code: 2002-2736; Inner value: 0x156002 + public static Result.Base GameCardCommandReadPageUnalignedFailure => new Result.Base(ModuleFs, 2736); + /// Error code: 2002-2737; Inner value: 0x156202 + public static Result.Base GameCardCommandWritePageFailure => new Result.Base(ModuleFs, 2737); + /// Error code: 2002-2738; Inner value: 0x156402 + public static Result.Base GameCardCommandRefreshFailure => new Result.Base(ModuleFs, 2738); + /// Error code: 2002-2739; Inner value: 0x156602 + public static Result.Base GameCardCommandUpdateKeyFailure => new Result.Base(ModuleFs, 2739); + /// Error code: 2002-2740; Inner value: 0x156802 + public static Result.Base GameCardSendCardSelfRefreshFailure => new Result.Base(ModuleFs, 2740); + /// Error code: 2002-2741; Inner value: 0x156a02 + public static Result.Base GameCardSendCardReadRefreshStatusFailure => new Result.Base(ModuleFs, 2741); + /// Error code: 2002-2742; Inner value: 0x156c02 + public static Result.Base GameCardCommandReadCrcFailure => new Result.Base(ModuleFs, 2742); + /// Error code: 2002-2743; Inner value: 0x156e02 + public static Result.Base GameCardCommandEraseFailure => new Result.Base(ModuleFs, 2743); + /// Error code: 2002-2744; Inner value: 0x157002 + public static Result.Base GameCardCommandReadDevParamFailure => new Result.Base(ModuleFs, 2744); + /// Error code: 2002-2745; Inner value: 0x157202 + public static Result.Base GameCardCommandWriteDevParamFailure => new Result.Base(ModuleFs, 2745); + /// Error code: 2002-2746; Inner value: 0x157402 + public static Result.Base GameCardSendCardReadErrorCountFailure => new Result.Base(ModuleFs, 2746); /// Error code: 2002-2900; Range: 2900-2919; Inner value: 0x16a802 public static Result.Base GameCardDevCardUnexpectedFailure { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2900, 2919); } @@ -441,6 +507,8 @@ public static class ResultFs public static Result.Base GameCardFsGetHandleFailure => new Result.Base(ModuleFs, 2951); /// Error code: 2002-2952; Inner value: 0x171002 public static Result.Base GameCardFsCheckHandleInReadFailure => new Result.Base(ModuleFs, 2952); + /// Error code: 2002-2953; Inner value: 0x171202 + public static Result.Base GameCardFsCheckHandleInWriteFailure => new Result.Base(ModuleFs, 2953); /// Error code: 2002-2954; Inner value: 0x171402 public static Result.Base GameCardFsCheckHandleInGetStatusFailure => new Result.Base(ModuleFs, 2954); /// Error code: 2002-2955; Inner value: 0x171602 @@ -460,7 +528,7 @@ public static class ResultFs /// Error code: 2002-2962; Inner value: 0x172402 public static Result.Base GameCardFsInvalidCompatibilityType => new Result.Base(ModuleFs, 2962); /// Error code: 2002-2963; Inner value: 0x172602 - public static Result.Base GameCardsNotSupportedOnDeviceModel => new Result.Base(ModuleFs, 2963); + public static Result.Base GameCardNotSupportedOnDeviceModel => new Result.Base(ModuleFs, 2963); /// Error code: 2002-3000; Range: 3000-7999; Inner value: 0x177002 public static Result.Base Internal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 3000, 7999); } diff --git a/src/LibHac/FsSrv/EmulatedGameCard.cs b/src/LibHac/FsSrv/EmulatedGameCard.cs index cbb6d994..60bfbc83 100644 --- a/src/LibHac/FsSrv/EmulatedGameCard.cs +++ b/src/LibHac/FsSrv/EmulatedGameCard.cs @@ -39,10 +39,9 @@ public class EmulatedGameCard { RemoveGameCard(); - CardImageStorage = cardImageStorage; - CardImage = new Xci(KeySet, cardImageStorage); CardHeader = CardImage.Header; + CardImageStorage = CardImage.BaseStorage; } public void RemoveGameCard() diff --git a/src/LibHac/Gc/Impl/GameCardImplTypes.cs b/src/LibHac/Gc/Impl/GameCardImplTypes.cs index 21136c43..fd2d159d 100644 --- a/src/LibHac/Gc/Impl/GameCardImplTypes.cs +++ b/src/LibHac/Gc/Impl/GameCardImplTypes.cs @@ -22,6 +22,58 @@ public struct CardId3 public Array4 Reserved; } +public struct CardInitialDataPayload +{ + public Array8 PackageId; + public Array8 Reserved; + public Array16 AuthData; + public Array16 AuthMac; + public Array12 AuthNonce; +} + +public struct CardInitialData +{ + public CardInitialDataPayload Payload; + public Array452 Padding; +} + +public enum FwVersion : byte +{ + // ReSharper disable InconsistentNaming + ForDev = 0, + Since1_0_0 = 1, + Since4_0_0 = 2, + Since9_0_0 = 3, + Since11_0_0 = 4, + Since12_0_0 = 5 + // ReSharper restore InconsistentNaming +} + +public enum KekIndex : byte +{ + Version0 = 0, + ForDev = 1 +} + +public struct CardHeaderEncryptedData +{ + public Array2 FwVersion; + public uint AccCtrl1; + public uint Wait1TimeRead; + public uint Wait2TimeRead; + public uint Wait1TimeWrite; + public uint Wait2TimeWrite; + public uint FwMode; + public uint CupVersion; + public byte CompatibilityType; + public byte Reserved25; + public byte Reserved26; + public byte Reserved27; + public Array8 UppHash; + public ulong CupId; + public Array56 Reserved38; +} + public enum MemoryCapacity : byte { // ReSharper disable InconsistentNaming @@ -32,4 +84,72 @@ public enum MemoryCapacity : byte Capacity16GB = 0xE1, Capacity32GB = 0xE2 // ReSharper restore InconsistentNaming +} + +public enum AccessControl1ClockRate +{ + ClockRate25MHz = 0xA10011, + ClockRate50MHz = 0xA10010 +} + +public enum SelSec +{ + T1 = 1, + T2 = 2 +} + +public struct CardHeader +{ + public static uint HeaderMagic => 0x44414548; // HEAD + + public uint Magic; + public uint RomAreaStartPage; + public uint BackupAreaStartPage; + public byte KeyIndex; + public byte RomSize; + public byte Version; + public byte Flags; + public Array8 PackageId; + public uint ValidDataEndPage; + public Array4 Reserved11C; + public Array16 Iv; + public ulong PartitionFsHeaderAddress; + public ulong PartitionFsHeaderSize; + public Array32 PartitionFsHeaderHash; + public Array32 InitialDataHash; + public uint SelSec; + public uint SelT1Key; + public uint SelKey; + public uint LimAreaPage; + public CardHeaderEncryptedData EncryptedData; +} + +public struct CardHeaderWithSignature +{ + public Array256 Signature; + public CardHeader Data; +} + +public struct T1CardCertificate +{ + public static uint CertMagic => 0x54524543; // CERT + + public Array256 Signature; + public uint Magic; + public uint Version; + public byte KekIndex; + public Array7 Flags; + public Array16 T1CardDeviceId; + public Array16 Iv; + public Array16 HwKey; + public Array192 Reserved; + public Array512 Padding; +} + +public struct Ca10Certificate +{ + public Array256 Signature; + public Array48 Unk100; + public Array256 Modulus; + public Array464 Unk230; } \ No newline at end of file diff --git a/src/LibHac/Tools/Fs/Xci.cs b/src/LibHac/Tools/Fs/Xci.cs index 247870e4..1f41e4e2 100644 --- a/src/LibHac/Tools/Fs/Xci.cs +++ b/src/LibHac/Tools/Fs/Xci.cs @@ -11,7 +11,7 @@ public class Xci { public XciHeader Header { get; } - private IStorage BaseStorage { get; } + internal IStorage BaseStorage { get; } private object InitLocker { get; } = new object(); private XciPartition RootPartition { get; set; } @@ -19,6 +19,11 @@ public class Xci { BaseStorage = storage; Header = new XciHeader(keySet, storage.AsStream()); + + if (Header.HasInitialData) + { + BaseStorage = storage.Slice(0x1000); + } } public bool HasPartition(XciPartitionType type) diff --git a/src/LibHac/Tools/Fs/XciHeader.cs b/src/LibHac/Tools/Fs/XciHeader.cs index 6dd84bbc..83e027b2 100644 --- a/src/LibHac/Tools/Fs/XciHeader.cs +++ b/src/LibHac/Tools/Fs/XciHeader.cs @@ -1,11 +1,16 @@ using System; using System.IO; +using System.Runtime.CompilerServices; +using System.Security.Cryptography; using System.Text; using LibHac.Common; using LibHac.Common.Keys; using LibHac.Crypto; using LibHac.Fs; +using LibHac.Gc.Impl; using LibHac.Tools.Crypto; +using LibHac.Tools.FsSystem; +using Aes = LibHac.Crypto.Aes; namespace LibHac.Tools.Fs; @@ -13,7 +18,9 @@ public class XciHeader { private const int SignatureSize = 0x100; private const string HeaderMagic = "HEAD"; + private const uint HeaderMagicValue = 0x44414548; // HEAD private const int EncryptedHeaderSize = 0x70; + private const int GcTitleKeyKekIndexMax = 0x10; private static readonly byte[] XciHeaderPubk = { @@ -56,6 +63,7 @@ public class XciHeader public int SelKey { get; set; } public int LimAreaPage { get; set; } + public bool IsHeaderDecrypted { get; set; } public ulong FwVersion { get; set; } public CardClockRate AccCtrl1 { get; set; } public int Wait1TimeRead { get; set; } @@ -64,6 +72,7 @@ public class XciHeader public int Wait2TimeWrite { get; set; } public int FwMode { get; set; } public int UppVersion { get; set; } + public byte CompatibilityType { get; set; } public byte[] UppHash { get; set; } public ulong UppId { get; set; } @@ -71,10 +80,38 @@ public class XciHeader public Validity SignatureValidity { get; set; } public Validity PartitionFsHeaderValidity { get; set; } + public Validity InitialDataValidity { get; set; } + + public bool HasInitialData { get; set; } + public byte[] InitialDataPackageId { get; set; } + public byte[] InitialDataAuthData { get; set; } + public byte[] InitialDataAuthMac { get; set; } + public byte[] InitialDataAuthNonce { get; set; } + public byte[] InitialData { get; set; } + public byte[] DecryptedTitleKey { get; set; } public XciHeader(KeySet keySet, Stream stream) { - using (var reader = new BinaryReader(stream, Encoding.Default, true)) + DetermineXciSubStorages(out IStorage keyAreaStorage, out IStorage bodyStorage, stream.AsStorage()) + .ThrowIfFailure(); + + if (keyAreaStorage is not null) + { + using (var r = new BinaryReader(keyAreaStorage.AsStream(), Encoding.Default, true)) + { + HasInitialData = true; + InitialDataPackageId = r.ReadBytes(8); + r.BaseStream.Position += 8; + InitialDataAuthData = r.ReadBytes(0x10); + InitialDataAuthMac = r.ReadBytes(0x10); + InitialDataAuthNonce = r.ReadBytes(0xC); + + r.BaseStream.Position = 0; + InitialData = r.ReadBytes(Unsafe.SizeOf()); + } + } + + using (var reader = new BinaryReader(bodyStorage.AsStream(), Encoding.Default, true)) { Signature = reader.ReadBytes(SignatureSize); Magic = reader.ReadAscii(4); @@ -112,6 +149,8 @@ public class XciHeader if (keySet != null && !keySet.XciHeaderKey.IsZeros()) { + IsHeaderDecrypted = true; + byte[] encHeader = reader.ReadBytes(EncryptedHeaderSize); byte[] decHeader = new byte[EncryptedHeaderSize]; Aes.DecryptCbc128(encHeader, decHeader, keySet.XciHeaderKey, AesCbcIv); @@ -126,7 +165,8 @@ public class XciHeader Wait2TimeWrite = decReader.ReadInt32(); FwMode = decReader.ReadInt32(); UppVersion = decReader.ReadInt32(); - decReader.BaseStream.Position += 4; + CompatibilityType = decReader.ReadByte(); + decReader.BaseStream.Position += 3; UppHash = decReader.ReadBytes(8); UppId = decReader.ReadUInt64(); } @@ -142,14 +182,103 @@ public class XciHeader Sha256.GenerateSha256Hash(headerBytes, actualHeaderHash); PartitionFsHeaderValidity = Utilities.SpansEqual(RootPartitionHeaderHash, actualHeaderHash) ? Validity.Valid : Validity.Invalid; + + if (HasInitialData) + { + Span actualInitialDataHash = stackalloc byte[Sha256.DigestSize]; + Sha256.GenerateSha256Hash(InitialData, actualInitialDataHash); + + InitialDataValidity = Utilities.SpansEqual(InitialDataHash, actualInitialDataHash) + ? Validity.Valid + : Validity.Invalid; + } + + Span key = stackalloc byte[0x10]; + Result rc = DecryptCardInitialData(key, InitialData, KekIndex, keySet); + if (rc.IsSuccess()) + { + DecryptedTitleKey = key.ToArray(); + } } } + + private Result DecryptCardInitialData(Span dest, ReadOnlySpan initialData, int kekIndex, KeySet keySet) + { + if (initialData.Length != Unsafe.SizeOf()) + return ResultFs.GameCardPreconditionViolation.Log(); + + if (kekIndex >= GcTitleKeyKekIndexMax) + return ResultFs.GameCardPreconditionViolation.Log(); + + // Verify the kek is preset. + if (keySet.GcTitleKeyKeks[kekIndex].IsZeros()) + return ResultFs.GameCardPreconditionViolation.Log(); + + // Generate the key. + Span key = stackalloc byte[0x10]; + Aes.DecryptEcb128(initialData.Slice(0, 0x10), key, keySet.GcTitleKeyKeks[kekIndex]); + + ref readonly CardInitialData data = ref SpanHelpers.AsReadOnlyStruct(initialData); + + if (dest.Length != data.Payload.AuthData.ItemsRo.Length) + return ResultFs.GameCardPreconditionViolation.Log(); + + // Verify padding is all-zero. + bool anyNonZero = false; + for (int i = 0; i < data.Padding.ItemsRo.Length; i++) + { + anyNonZero |= data.Padding.ItemsRo[i] != 0; + } + + if (anyNonZero) + return ResultFs.GameCardInitialNotFilledWithZero.Log(); + + using (var decryptor = new AesCcm(key)) + { + try + { + decryptor.Decrypt(data.Payload.AuthNonce, data.Payload.AuthData, data.Payload.AuthMac, dest); + } + catch (CryptographicException) + { + return ResultFs.GameCardKekIndexMismatch.Log(); + } + } + + return Result.Success; + } + + private Result DetermineXciSubStorages(out IStorage keyAreaStorage, out IStorage bodyStorage, IStorage baseStorage) + { + UnsafeHelpers.SkipParamInit(out keyAreaStorage, out bodyStorage); + + Result rc = baseStorage.GetSize(out long storageSize); + if (rc.IsFailure()) return rc.Miss(); + + if (storageSize >= 0x1104) + { + uint magic = 0; + rc = baseStorage.Read(0x1100, SpanHelpers.AsByteSpan(ref magic)); + if (rc.IsFailure()) return rc.Miss(); + + if (magic == HeaderMagicValue) + { + keyAreaStorage = new SubStorage(baseStorage, 0, 0x1000); + bodyStorage = new SubStorage(baseStorage, 0x1000, storageSize - 0x1000); + return Result.Success; + } + } + + keyAreaStorage = null; + bodyStorage = baseStorage; + return Result.Success; + } } public enum CardClockRate { - ClockRate25 = 10551312, - ClockRate50 + ClockRate25 = 0xA10011, + ClockRate50 = 0xA10010 } public enum XciPartitionType diff --git a/src/hactoolnet/IndentingStringBuilder.cs b/src/hactoolnet/IndentingStringBuilder.cs new file mode 100644 index 00000000..a3eb8711 --- /dev/null +++ b/src/hactoolnet/IndentingStringBuilder.cs @@ -0,0 +1,173 @@ +using System; +using System.Text; + +namespace hactoolnet; + +public struct ScopedIndentation : IDisposable +{ + private IndentingStringBuilder Builder; + + public ScopedIndentation(IndentingStringBuilder builder) + { + builder.IncreaseLevel(); + Builder = builder; + } + + public void Dispose() + { + Builder.DecreaseLevel(); + } +} + +public class IndentingStringBuilder +{ + public int LevelSize { get; set; } = 4; + public int Level { get; private set; } + + private StringBuilder _sb = new StringBuilder(); + private string _indentation = string.Empty; + private bool _hasIndentedCurrentLine; + private bool _lastLineWasEmpty; + private int _columnLength; + private int _paddingSize; + + public IndentingStringBuilder(int columnLength) + { + _columnLength = columnLength; + _paddingSize = columnLength; + } + + public IndentingStringBuilder(int levelSize, int columnLength) + { + LevelSize = levelSize; + _columnLength = columnLength; + _paddingSize = columnLength; + } + + public void SetLevel(int level) + { + Level = Math.Max(level, 0); + _indentation = new string(' ', Level * LevelSize); + _paddingSize = _columnLength - Level * LevelSize; + } + + public void IncreaseLevel() => SetLevel(Level + 1); + public void DecreaseLevel() => SetLevel(Level - 1); + + public IndentingStringBuilder AppendLine() + { + _sb.AppendLine(); + _hasIndentedCurrentLine = false; + _lastLineWasEmpty = true; + return this; + } + + public IndentingStringBuilder AppendSpacerLine() + { + if (!_lastLineWasEmpty) + { + _sb.AppendLine(); + _hasIndentedCurrentLine = false; + _lastLineWasEmpty = true; + } + + return this; + } + + public IndentingStringBuilder AppendLine(string value) + { + IndentIfNeeded(); + _sb.AppendLine(value); + _hasIndentedCurrentLine = false; + _lastLineWasEmpty = string.IsNullOrWhiteSpace(value); + return this; + } + + public IndentingStringBuilder Append(string value) + { + IndentIfNeeded(); + _sb.Append(value); + return this; + } + + public IndentingStringBuilder Append(char value, int repeatCount) + { + IndentIfNeeded(); + _sb.Append(value, repeatCount); + return this; + } + + public ScopedIndentation AppendHeader(string value) + { + AppendLine(value); + return new ScopedIndentation(this); + } + + public void PrintItem(string prefix, object data) + { + if (data is byte[] byteData) + { + AppendBytes(prefix.PadRight(_paddingSize), byteData); + } + else + { + AppendLine(prefix.PadRight(_paddingSize) + data); + } + } + + public IndentingStringBuilder AppendLineAndIncrease(string value) + { + AppendLine(value); + IncreaseLevel(); + return this; + } + + public IndentingStringBuilder DecreaseAndAppendLine(string value) + { + DecreaseLevel(); + AppendLine(value); + return this; + } + + private void IndentIfNeeded() + { + if (!_hasIndentedCurrentLine) + { + _sb.Append(_indentation); + _hasIndentedCurrentLine = true; + } + } + + public void AppendBytes(string prefix, byte[] data) + { + int max = 32; + int remaining = data.Length; + bool first = true; + int offset = 0; + + while (remaining > 0) + { + max = Math.Min(max, remaining); + + if (first) + { + Append(prefix); + first = false; + } + else + { + Append(' ', prefix.Length); + } + + for (int i = 0; i < max; i++) + { + Append($"{data[offset++]:X2}"); + } + + AppendLine(); + remaining -= max; + } + } + + public override string ToString() => _sb.ToString(); +} \ No newline at end of file diff --git a/src/hactoolnet/ProcessXci.cs b/src/hactoolnet/ProcessXci.cs index fd273dd0..70688f1e 100644 --- a/src/hactoolnet/ProcessXci.cs +++ b/src/hactoolnet/ProcessXci.cs @@ -1,13 +1,14 @@ -using System.IO; +using System; +using System.IO; using System.Linq; -using System.Text; using LibHac.Common; using LibHac.Fs; +using LibHac.Fs.Impl; using LibHac.FsSystem; +using LibHac.Gc.Impl; using LibHac.Tools.Fs; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; -using static hactoolnet.Print; namespace hactoolnet; @@ -140,19 +141,86 @@ internal static class ProcessXci private static string Print(this Xci xci) { - const int colLen = 36; + const int colLen = 52; - var sb = new StringBuilder(); - sb.AppendLine(); + var sb = new IndentingStringBuilder(colLen); - sb.AppendLine("XCI:"); + if (!xci.Header.HasInitialData) + { + sb.AppendLine("Warning: Game card is missing key area/initial data header. Re-dump?"); + } - PrintItem(sb, colLen, "Magic:", xci.Header.Magic); - PrintItem(sb, colLen, $"Header Signature{xci.Header.SignatureValidity.GetValidityString()}:", xci.Header.Signature); - PrintItem(sb, colLen, $"Header Hash{xci.Header.PartitionFsHeaderValidity.GetValidityString()}:", xci.Header.RootPartitionHeaderHash); - PrintItem(sb, colLen, "Cartridge Type:", GetCartridgeType(xci.Header.GameCardSize)); - PrintItem(sb, colLen, "Cartridge Size:", $"0x{Utilities.MediaToReal(xci.Header.ValidDataEndPage + 1):x12}"); - PrintItem(sb, colLen, "Header IV:", xci.Header.AesCbcIv); + using ScopedIndentation xciScope = sb.AppendHeader("XCI:"); + + if (xci.Header.HasInitialData) + { + using ScopedIndentation initialDataScope = sb.AppendHeader("Initial Data:"); + + sb.PrintItem("Package Id:", xci.Header.InitialDataPackageId); + sb.PrintItem("Encrypted Title Key:", xci.Header.InitialDataAuthData); + + if (xci.Header.DecryptedTitleKey is not null) + { + sb.PrintItem("Decrypted Title Key:", xci.Header.DecryptedTitleKey); + } + } + else + { + sb.PrintItem("Initial Data:", "Missing/Not Dumped"); + } + + using (sb.AppendHeader("Main Header:")) + { + sb.PrintItem("Magic:", xci.Header.Magic); + sb.PrintItem($"Signature{xci.Header.SignatureValidity.GetValidityString()}:", + xci.Header.Signature); + sb.PrintItem("Package Id:", BitConverter.GetBytes(xci.Header.PackageId)); + + sb.PrintItem("Memory Capacity:", new U8Span(new IdString().ToString((MemoryCapacity)xci.Header.GameCardSize)).ToString()); + sb.PrintItem("Rom Area Start:", $"0x{Utilities.MediaToReal(xci.Header.RomAreaStartPage):X12}"); + sb.PrintItem("Backup Area Start:", $"0x{Utilities.MediaToReal((uint)xci.Header.BackupAreaStartPage):X12}"); + sb.PrintItem("Valid Data End:", $"0x{Utilities.MediaToReal(xci.Header.ValidDataEndPage):X12}"); + sb.PrintItem("Limit Area:", $"0x{Utilities.MediaToReal(xci.Header.LimAreaPage):X12}"); + sb.PrintItem("Kek Index:", new U8Span(new IdString().ToString((KekIndex)xci.Header.KekIndex)).ToString()); + sb.PrintItem("Title Key Dec Index:", xci.Header.TitleKeyDecIndex); + + using (sb.AppendHeader("Flags:")) + { + sb.PrintItem("Auto Boot:", xci.Header.Flags.HasFlag(GameCardAttribute.AutoBootFlag) ? 1 : 0); + sb.PrintItem("History Erase:", xci.Header.Flags.HasFlag(GameCardAttribute.HistoryEraseFlag) ? 1 : 0); + sb.PrintItem("Repair Tool:", xci.Header.Flags.HasFlag(GameCardAttribute.RepairToolFlag) ? 1 : 0); + sb.PrintItem("Different Region Cup to Terra Device:", xci.Header.Flags.HasFlag(GameCardAttribute.DifferentRegionCupToTerraDeviceFlag) ? 1 : 0); + sb.PrintItem("Different Region Cup to Global Device:", xci.Header.Flags.HasFlag(GameCardAttribute.DifferentRegionCupToGlobalDeviceFlag) ? 1 : 0); + sb.PrintItem("Has Ca10 Certificate:", xci.Header.Flags.HasFlag(GameCardAttribute.HasCa10CertificateFlag) ? 1 : 0); + } + + sb.PrintItem("Sel Sec:", new U8Span(new IdString().ToString((SelSec)xci.Header.SelSec)).ToString()); + sb.PrintItem("Sel T1 Key:", xci.Header.SelT1Key); + sb.PrintItem("Sel Key:", xci.Header.SelKey); + + sb.PrintItem($"Initial Data Hash{xci.Header.InitialDataValidity.GetValidityString()}:", xci.Header.InitialDataHash); + sb.PrintItem($"Partition Header Hash{xci.Header.PartitionFsHeaderValidity.GetValidityString()}:", xci.Header.RootPartitionHeaderHash); + sb.PrintItem("Encrypted Data Iv:", xci.Header.AesCbcIv.Reverse().ToArray()); + + if (xci.Header.IsHeaderDecrypted) + { + using ScopedIndentation infoScope = sb.AppendHeader("Card Info:"); + + sb.PrintItem("Card Fw Version:", new U8Span(new IdString().ToString((FwVersion)xci.Header.FwVersion)).ToString()); + sb.PrintItem("Clock Rate:", new U8Span(new IdString().ToString((AccessControl1ClockRate)xci.Header.AccCtrl1)).ToString()); + sb.PrintItem("Wait1 Time Read:", xci.Header.Wait1TimeRead); + sb.PrintItem("Wait2 Time Read:", xci.Header.Wait2TimeRead); + sb.PrintItem("Wait1 Time Write:", xci.Header.Wait1TimeWrite); + sb.PrintItem("Wait2 Time Write:", xci.Header.Wait2TimeWrite); + sb.PrintItem("Fw Mode:", $"0x{xci.Header.FwMode:X8}"); + sb.PrintItem("Compatibility Type:", new U8Span(new IdString().ToString((GameCardCompatibilityType)xci.Header.CompatibilityType)).ToString()); + + int cv = xci.Header.UppVersion; + sb.PrintItem("Cup Version:", $"{(cv >> 26) & 0x3F}.{(cv >> 20) & 0x3F}.{(cv >> 16) & 0xF}.{(cv >> 0) & 0xFFFF} ({cv})"); + sb.PrintItem("Cup Id:", $"{xci.Header.UppId:X16}"); + sb.PrintItem("Upp Hash:", xci.Header.UppHash); + } + } PrintPartition(sb, colLen, xci.OpenPartition(XciPartitionType.Root), XciPartitionType.Root); @@ -168,14 +236,13 @@ internal static class ProcessXci return sb.ToString(); } - private static void PrintPartition(StringBuilder sb, int colLen, XciPartition partition, XciPartitionType type) + private static void PrintPartition(IndentingStringBuilder sb, int colLen, XciPartition partition, XciPartitionType type) { - const int fileNameLen = 57; + using ScopedIndentation mainHeader = + sb.AppendHeader($"{type.Print()} Partition:{partition.HashValidity.GetValidityString()}"); - sb.AppendLine($"{type.Print()} Partition:{partition.HashValidity.GetValidityString()}"); - PrintItem(sb, colLen, " Magic:", partition.Header.Magic); - PrintItem(sb, colLen, " Offset:", $"{partition.Offset:x12}"); - PrintItem(sb, colLen, " Number of files:", partition.Files.Length); + sb.PrintItem("Magic:", partition.Header.Magic); + sb.PrintItem("Number of files:", partition.Files.Length); string name = type.GetFileName(); @@ -185,26 +252,11 @@ internal static class ProcessXci { PartitionFileEntry file = partition.Files[i]; - string label = i == 0 ? " Files:" : ""; - string offsets = $"{file.Offset:x12}-{file.Offset + file.Size:x12}{file.HashValidity.GetValidityString()}"; - string data = $"{name}:/{file.Name}".PadRight(fileNameLen) + offsets; + string label = i == 0 ? "Files:" : ""; + string data = $"{name}:/{file.Name}"; - PrintItem(sb, colLen, label, data); + sb.PrintItem(label, data); } } } - - private static string GetCartridgeType(GameCardSizeInternal size) - { - switch (size) - { - case GameCardSizeInternal.Size1Gb: return "1GB"; - case GameCardSizeInternal.Size2Gb: return "2GB"; - case GameCardSizeInternal.Size4Gb: return "4GB"; - case GameCardSizeInternal.Size8Gb: return "8GB"; - case GameCardSizeInternal.Size16Gb: return "16GB"; - case GameCardSizeInternal.Size32Gb: return "32GB"; - default: return string.Empty; - } - } } \ No newline at end of file diff --git a/tests/LibHac.Tests/Gc/TypeLayoutTests.cs b/tests/LibHac.Tests/Gc/TypeLayoutTests.cs index 3914d2f3..bfe30c60 100644 --- a/tests/LibHac.Tests/Gc/TypeLayoutTests.cs +++ b/tests/LibHac.Tests/Gc/TypeLayoutTests.cs @@ -86,4 +86,125 @@ public class TypeLayoutTests Assert.Equal(0, GetOffset(in s, in s.Reserved)); } + + [Fact] + public static void CardInitialDataPayload_Layout() + { + var s = new CardInitialDataPayload(); + + Assert.Equal(0x3C, Unsafe.SizeOf()); + + Assert.Equal(0x00, GetOffset(in s, in s.PackageId)); + Assert.Equal(0x08, GetOffset(in s, in s.Reserved)); + Assert.Equal(0x10, GetOffset(in s, in s.AuthData)); + Assert.Equal(0x20, GetOffset(in s, in s.AuthMac)); + Assert.Equal(0x30, GetOffset(in s, in s.AuthNonce)); + } + + [Fact] + public static void CardInitialData_Layout() + { + var s = new CardInitialData(); + + Assert.Equal(0x200, Unsafe.SizeOf()); + + Assert.Equal(0x00, GetOffset(in s, in s.Payload)); + Assert.Equal(0x3C, GetOffset(in s, in s.Padding)); + } + + [Fact] + public static void CardHeaderEncryptedData_Layout() + { + var s = new CardHeaderEncryptedData(); + + Assert.Equal(0x70, Unsafe.SizeOf()); + + Assert.Equal(0x00, GetOffset(in s, in s.FwVersion)); + Assert.Equal(0x08, GetOffset(in s, in s.AccCtrl1)); + Assert.Equal(0x0C, GetOffset(in s, in s.Wait1TimeRead)); + Assert.Equal(0x10, GetOffset(in s, in s.Wait2TimeRead)); + Assert.Equal(0x14, GetOffset(in s, in s.Wait1TimeWrite)); + Assert.Equal(0x18, GetOffset(in s, in s.Wait2TimeWrite)); + Assert.Equal(0x1C, GetOffset(in s, in s.FwMode)); + Assert.Equal(0x20, GetOffset(in s, in s.CupVersion)); + Assert.Equal(0x24, GetOffset(in s, in s.CompatibilityType)); + Assert.Equal(0x25, GetOffset(in s, in s.Reserved25)); + Assert.Equal(0x26, GetOffset(in s, in s.Reserved26)); + Assert.Equal(0x27, GetOffset(in s, in s.Reserved27)); + Assert.Equal(0x28, GetOffset(in s, in s.UppHash)); + Assert.Equal(0x30, GetOffset(in s, in s.CupId)); + Assert.Equal(0x38, GetOffset(in s, in s.Reserved38)); + } + + [Fact] + public static void CardHeader_Layout() + { + var s = new CardHeader(); + + Assert.Equal(0x100, Unsafe.SizeOf()); + + Assert.Equal(0x00, GetOffset(in s, in s.Magic)); + Assert.Equal(0x04, GetOffset(in s, in s.RomAreaStartPage)); + Assert.Equal(0x08, GetOffset(in s, in s.BackupAreaStartPage)); + Assert.Equal(0x0C, GetOffset(in s, in s.KeyIndex)); + Assert.Equal(0x0D, GetOffset(in s, in s.RomSize)); + Assert.Equal(0x0E, GetOffset(in s, in s.Version)); + Assert.Equal(0x0F, GetOffset(in s, in s.Flags)); + Assert.Equal(0x10, GetOffset(in s, in s.PackageId)); + Assert.Equal(0x18, GetOffset(in s, in s.ValidDataEndPage)); + Assert.Equal(0x1C, GetOffset(in s, in s.Reserved11C)); + Assert.Equal(0x20, GetOffset(in s, in s.Iv)); + Assert.Equal(0x30, GetOffset(in s, in s.PartitionFsHeaderAddress)); + Assert.Equal(0x38, GetOffset(in s, in s.PartitionFsHeaderSize)); + Assert.Equal(0x40, GetOffset(in s, in s.PartitionFsHeaderHash)); + Assert.Equal(0x60, GetOffset(in s, in s.InitialDataHash)); + Assert.Equal(0x80, GetOffset(in s, in s.SelSec)); + Assert.Equal(0x84, GetOffset(in s, in s.SelT1Key)); + Assert.Equal(0x88, GetOffset(in s, in s.SelKey)); + Assert.Equal(0x8C, GetOffset(in s, in s.LimAreaPage)); + Assert.Equal(0x90, GetOffset(in s, in s.EncryptedData)); + } + + [Fact] + public static void CardHeaderWithSignature_Layout() + { + var s = new CardHeaderWithSignature(); + + Assert.Equal(0x200, Unsafe.SizeOf()); + + Assert.Equal(0x000, GetOffset(in s, in s.Signature)); + Assert.Equal(0x100, GetOffset(in s, in s.Data)); + } + + [Fact] + public static void T1CardCertificate_Layout() + { + var s = new T1CardCertificate(); + + Assert.Equal(0x400, Unsafe.SizeOf()); + + Assert.Equal(0x000, GetOffset(in s, in s.Signature)); + Assert.Equal(0x100, GetOffset(in s, in s.Magic)); + Assert.Equal(0x104, GetOffset(in s, in s.Version)); + Assert.Equal(0x108, GetOffset(in s, in s.KekIndex)); + Assert.Equal(0x109, GetOffset(in s, in s.Flags)); + Assert.Equal(0x110, GetOffset(in s, in s.T1CardDeviceId)); + Assert.Equal(0x120, GetOffset(in s, in s.Iv)); + Assert.Equal(0x130, GetOffset(in s, in s.HwKey)); + Assert.Equal(0x140, GetOffset(in s, in s.Reserved)); + Assert.Equal(0x200, GetOffset(in s, in s.Padding)); + } + + [Fact] + public static void Ca10Certificate_Layout() + { + var s = new Ca10Certificate(); + + Assert.Equal(0x400, Unsafe.SizeOf()); + + Assert.Equal(0x000, GetOffset(in s, in s.Signature)); + Assert.Equal(0x100, GetOffset(in s, in s.Unk100)); + Assert.Equal(0x130, GetOffset(in s, in s.Modulus)); + Assert.Equal(0x230, GetOffset(in s, in s.Unk230)); + } } \ No newline at end of file