From 5013e7d2ec9f03ba807fd15c811857d65f6e313e Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Wed, 29 Dec 2021 10:06:02 -0700 Subject: [PATCH] Use fixed array structs instead of Data* structs --- build/CodeGen/Stage2/KeysCodeGen.cs | 56 +++++++++---------- src/LibHac/Common/Keys/KeySet.cs | 20 +++---- src/LibHac/Crypto/KeyTypes.cs | 51 ++++------------- src/LibHac/Fat/FatError.cs | 20 +++---- src/LibHac/Fs/Fsa/MountUtility.cs | 2 +- src/LibHac/Fs/MountName.cs | 8 +-- .../SaveDataTransferCryptoConfiguration.cs | 20 +++---- tests/LibHac.Tests/Common/Layout.cs | 19 +++++++ tests/LibHac.Tests/Fat/TypeLayoutTests.cs | 23 ++++++++ 9 files changed, 114 insertions(+), 105 deletions(-) create mode 100644 tests/LibHac.Tests/Common/Layout.cs create mode 100644 tests/LibHac.Tests/Fat/TypeLayoutTests.cs diff --git a/build/CodeGen/Stage2/KeysCodeGen.cs b/build/CodeGen/Stage2/KeysCodeGen.cs index 21c60f98..9e5152f8 100644 --- a/build/CodeGen/Stage2/KeysCodeGen.cs +++ b/build/CodeGen/Stage2/KeysCodeGen.cs @@ -99,46 +99,46 @@ public static class KeysCodeGen RSAParameters betaNca0Params = Rsa.RecoverParameters(BetaNca0Modulus, StandardPublicExponent, BetaNca0Exponent); - betaNca0Params.D.AsSpan().CopyTo(keySet.BetaNca0KeyAreaKey.PrivateExponent.Data); - betaNca0Params.DP.AsSpan().CopyTo(keySet.BetaNca0KeyAreaKey.Dp.Data); - betaNca0Params.DQ.AsSpan().CopyTo(keySet.BetaNca0KeyAreaKey.Dq.Data); - betaNca0Params.Exponent.AsSpan().CopyTo(keySet.BetaNca0KeyAreaKey.PublicExponent.Data); - betaNca0Params.InverseQ.AsSpan().CopyTo(keySet.BetaNca0KeyAreaKey.InverseQ.Data); - betaNca0Params.Modulus.AsSpan().CopyTo(keySet.BetaNca0KeyAreaKey.Modulus.Data); - betaNca0Params.P.AsSpan().CopyTo(keySet.BetaNca0KeyAreaKey.P.Data); - betaNca0Params.Q.AsSpan().CopyTo(keySet.BetaNca0KeyAreaKey.Q.Data); + betaNca0Params.D.AsSpan().CopyTo(keySet.BetaNca0KeyAreaKey.PrivateExponent.Items); + betaNca0Params.DP.AsSpan().CopyTo(keySet.BetaNca0KeyAreaKey.Dp.Items); + betaNca0Params.DQ.AsSpan().CopyTo(keySet.BetaNca0KeyAreaKey.Dq.Items); + betaNca0Params.Exponent.AsSpan().CopyTo(keySet.BetaNca0KeyAreaKey.PublicExponent.Items); + betaNca0Params.InverseQ.AsSpan().CopyTo(keySet.BetaNca0KeyAreaKey.InverseQ.Items); + betaNca0Params.Modulus.AsSpan().CopyTo(keySet.BetaNca0KeyAreaKey.Modulus.Items); + betaNca0Params.P.AsSpan().CopyTo(keySet.BetaNca0KeyAreaKey.P.Items); + betaNca0Params.Q.AsSpan().CopyTo(keySet.BetaNca0KeyAreaKey.Q.Items); // First populate the prod RSA keys keySet.SetMode(KeySet.Mode.Prod); - StandardPublicExponent.CopyTo(keySet.NcaHeaderSigningKeys[0].PublicExponent.Data); - StandardPublicExponent.CopyTo(keySet.NcaHeaderSigningKeys[1].PublicExponent.Data); - NcaHdrFixedKeyModulus0Prod.CopyTo(keySet.NcaHeaderSigningKeys[0].Modulus.Data); - NcaHdrFixedKeyModulus1Prod.CopyTo(keySet.NcaHeaderSigningKeys[1].Modulus.Data); + StandardPublicExponent.CopyTo(keySet.NcaHeaderSigningKeys[0].PublicExponent.Items); + StandardPublicExponent.CopyTo(keySet.NcaHeaderSigningKeys[1].PublicExponent.Items); + NcaHdrFixedKeyModulus0Prod.CopyTo(keySet.NcaHeaderSigningKeys[0].Modulus.Items); + NcaHdrFixedKeyModulus1Prod.CopyTo(keySet.NcaHeaderSigningKeys[1].Modulus.Items); - StandardPublicExponent.CopyTo(keySet.AcidSigningKeys[0].PublicExponent.Data); - StandardPublicExponent.CopyTo(keySet.AcidSigningKeys[1].PublicExponent.Data); - AcidFixedKeyModulus0Prod.CopyTo(keySet.AcidSigningKeys[0].Modulus.Data); - AcidFixedKeyModulus1Prod.CopyTo(keySet.AcidSigningKeys[1].Modulus.Data); + StandardPublicExponent.CopyTo(keySet.AcidSigningKeys[0].PublicExponent.Items); + StandardPublicExponent.CopyTo(keySet.AcidSigningKeys[1].PublicExponent.Items); + AcidFixedKeyModulus0Prod.CopyTo(keySet.AcidSigningKeys[0].Modulus.Items); + AcidFixedKeyModulus1Prod.CopyTo(keySet.AcidSigningKeys[1].Modulus.Items); - StandardPublicExponent.CopyTo(keySet.Package2SigningKey.PublicExponent.Data); - Package2FixedKeyModulusProd.CopyTo(keySet.Package2SigningKey.Modulus.Data); + StandardPublicExponent.CopyTo(keySet.Package2SigningKey.PublicExponent.Items); + Package2FixedKeyModulusProd.CopyTo(keySet.Package2SigningKey.Modulus.Items); // Populate the dev RSA keys keySet.SetMode(KeySet.Mode.Dev); - StandardPublicExponent.CopyTo(keySet.NcaHeaderSigningKeys[0].PublicExponent.Data); - StandardPublicExponent.CopyTo(keySet.NcaHeaderSigningKeys[1].PublicExponent.Data); - NcaHdrFixedKeyModulus0Dev.CopyTo(keySet.NcaHeaderSigningKeys[0].Modulus.Data); - NcaHdrFixedKeyModulus1Dev.CopyTo(keySet.NcaHeaderSigningKeys[1].Modulus.Data); + StandardPublicExponent.CopyTo(keySet.NcaHeaderSigningKeys[0].PublicExponent.Items); + StandardPublicExponent.CopyTo(keySet.NcaHeaderSigningKeys[1].PublicExponent.Items); + NcaHdrFixedKeyModulus0Dev.CopyTo(keySet.NcaHeaderSigningKeys[0].Modulus.Items); + NcaHdrFixedKeyModulus1Dev.CopyTo(keySet.NcaHeaderSigningKeys[1].Modulus.Items); - StandardPublicExponent.CopyTo(keySet.AcidSigningKeys[0].PublicExponent.Data); - StandardPublicExponent.CopyTo(keySet.AcidSigningKeys[1].PublicExponent.Data); - AcidFixedKeyModulus0Dev.CopyTo(keySet.AcidSigningKeys[0].Modulus.Data); - AcidFixedKeyModulus1Dev.CopyTo(keySet.AcidSigningKeys[1].Modulus.Data); + StandardPublicExponent.CopyTo(keySet.AcidSigningKeys[0].PublicExponent.Items); + StandardPublicExponent.CopyTo(keySet.AcidSigningKeys[1].PublicExponent.Items); + AcidFixedKeyModulus0Dev.CopyTo(keySet.AcidSigningKeys[0].Modulus.Items); + AcidFixedKeyModulus1Dev.CopyTo(keySet.AcidSigningKeys[1].Modulus.Items); - StandardPublicExponent.CopyTo(keySet.Package2SigningKey.PublicExponent.Data); - Package2FixedKeyModulusDev.CopyTo(keySet.Package2SigningKey.Modulus.Data); + StandardPublicExponent.CopyTo(keySet.Package2SigningKey.PublicExponent.Items); + Package2FixedKeyModulusDev.CopyTo(keySet.Package2SigningKey.Modulus.Items); return keySet; } diff --git a/src/LibHac/Common/Keys/KeySet.cs b/src/LibHac/Common/Keys/KeySet.cs index 32ec535a..95974f29 100644 --- a/src/LibHac/Common/Keys/KeySet.cs +++ b/src/LibHac/Common/Keys/KeySet.cs @@ -225,8 +225,8 @@ public class KeySet { return new RSAParameters { - Exponent = key.PublicExponent.DataRo.ToArray(), - Modulus = key.Modulus.DataRo.ToArray() + Exponent = key.PublicExponent.ItemsRo.ToArray(), + Modulus = key.Modulus.ItemsRo.ToArray() }; } @@ -234,14 +234,14 @@ public class KeySet { return new RSAParameters { - D = key.PrivateExponent.DataRo.ToArray(), - DP = key.Dp.DataRo.ToArray(), - DQ = key.Dq.DataRo.ToArray(), - Exponent = key.PublicExponent.DataRo.ToArray(), - InverseQ = key.InverseQ.DataRo.ToArray(), - Modulus = key.Modulus.DataRo.ToArray(), - P = key.P.DataRo.ToArray(), - Q = key.Q.DataRo.ToArray() + D = key.PrivateExponent.ItemsRo.ToArray(), + DP = key.Dp.ItemsRo.ToArray(), + DQ = key.Dq.ItemsRo.ToArray(), + Exponent = key.PublicExponent.ItemsRo.ToArray(), + InverseQ = key.InverseQ.ItemsRo.ToArray(), + Modulus = key.Modulus.ItemsRo.ToArray(), + P = key.P.ItemsRo.ToArray(), + Q = key.Q.ItemsRo.ToArray() }; } diff --git a/src/LibHac/Crypto/KeyTypes.cs b/src/LibHac/Crypto/KeyTypes.cs index 083d53e8..01f38993 100644 --- a/src/LibHac/Crypto/KeyTypes.cs +++ b/src/LibHac/Crypto/KeyTypes.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using LibHac.Common; +using LibHac.Common.FixedArrays; using LibHac.Util; namespace LibHac.Crypto; @@ -117,49 +118,21 @@ public struct AesCmac #endif } -[StructLayout(LayoutKind.Sequential)] public struct RsaFullKey { - public Data100 PrivateExponent; - public Data80 Dp; - public Data80 Dq; - public Data3 PublicExponent; - public Data80 InverseQ; - public Data100 Modulus; - public Data80 P; - public Data80 Q; + // ReSharper disable once UnassignedField.Global + public Array256 PrivateExponent; + public Array128 Dp; + public Array128 Dq; + public Array3 PublicExponent; + public Array128 InverseQ; + public Array256 Modulus; + public Array128 P; + public Array128 Q; } -[StructLayout(LayoutKind.Sequential)] public struct RsaKey { - public Data100 Modulus; - public Data3 PublicExponent; -} - -[StructLayout(LayoutKind.Explicit, Size = 0x100)] -public struct Data100 -{ - [FieldOffset(0)] private byte _byte; - - public Span Data => SpanHelpers.CreateSpan(ref _byte, 0x100); - public readonly ReadOnlySpan DataRo => SpanHelpers.CreateReadOnlySpan(in _byte, 0x100); -} - -[StructLayout(LayoutKind.Explicit, Size = 0x80)] -public struct Data80 -{ - [FieldOffset(0)] private byte _byte; - - public Span Data => SpanHelpers.CreateSpan(ref _byte, 0x80); - public readonly ReadOnlySpan DataRo => SpanHelpers.CreateReadOnlySpan(in _byte, 0x80); -} - -[StructLayout(LayoutKind.Explicit, Size = 3)] -public struct Data3 -{ - [FieldOffset(0)] private byte _byte; - - public Span Data => SpanHelpers.CreateSpan(ref _byte, 3); - public readonly ReadOnlySpan DataRo => SpanHelpers.CreateReadOnlySpan(in _byte, 3); + public Array256 Modulus; + public Array3 PublicExponent; } \ No newline at end of file diff --git a/src/LibHac/Fat/FatError.cs b/src/LibHac/Fat/FatError.cs index bef2cf1a..f558cd22 100644 --- a/src/LibHac/Fat/FatError.cs +++ b/src/LibHac/Fat/FatError.cs @@ -1,18 +1,12 @@ -using System.Runtime.InteropServices; -using LibHac.Common; +using LibHac.Common.FixedArrays; namespace LibHac.Fat; -[StructLayout(LayoutKind.Explicit, Size = 0x20)] public struct FatError { - private const int FunctionNameLength = 0x10; - - [FieldOffset(0x00)] public int Error; - [FieldOffset(0x04)] public int ExtraError; - [FieldOffset(0x08)] public int DriveId; - [FieldOffset(0x0C)] private byte _functionName; - - public U8SpanMutable ErrorName => - new U8SpanMutable(SpanHelpers.CreateSpan(ref _functionName, FunctionNameLength)); -} + public int Error; + public int ExtraError; + public int DriveId; + public Array16 ErrorName; + public int Reserved; +} \ No newline at end of file diff --git a/src/LibHac/Fs/Fsa/MountUtility.cs b/src/LibHac/Fs/Fsa/MountUtility.cs index 09182350..38096e77 100644 --- a/src/LibHac/Fs/Fsa/MountUtility.cs +++ b/src/LibHac/Fs/Fsa/MountUtility.cs @@ -11,7 +11,7 @@ namespace LibHac.Fs.Fsa; public static class MountUtility { - internal static Result GetMountNameAndSubPath(out MountName mountName, out U8Span subPath, U8Span path) + private static Result GetMountNameAndSubPath(out MountName mountName, out U8Span subPath, U8Span path) { UnsafeHelpers.SkipParamInit(out mountName); subPath = default; diff --git a/src/LibHac/Fs/MountName.cs b/src/LibHac/Fs/MountName.cs index 8f6c8d35..52ca771c 100644 --- a/src/LibHac/Fs/MountName.cs +++ b/src/LibHac/Fs/MountName.cs @@ -1,15 +1,15 @@ using System; using System.Diagnostics; -using System.Runtime.InteropServices; using LibHac.Common; +using LibHac.Common.FixedArrays; namespace LibHac.Fs; -[StructLayout(LayoutKind.Sequential, Size = 16)] [DebuggerDisplay("{ToString()}")] internal struct MountName { - public Span Name => SpanHelpers.AsByteSpan(ref this); + private Array16 _nameArray; + public Span Name => _nameArray.Items; public override string ToString() => new U8Span(Name).ToString(); -} +} \ No newline at end of file diff --git a/src/LibHac/FsSrv/SaveDataTransferCryptoConfiguration.cs b/src/LibHac/FsSrv/SaveDataTransferCryptoConfiguration.cs index e3c9b86a..d6b6b15d 100644 --- a/src/LibHac/FsSrv/SaveDataTransferCryptoConfiguration.cs +++ b/src/LibHac/FsSrv/SaveDataTransferCryptoConfiguration.cs @@ -1,19 +1,19 @@ using System; -using LibHac.Crypto; +using LibHac.Common.FixedArrays; namespace LibHac.FsSrv; public class SaveDataTransferCryptoConfiguration { - private Data100 _tokenSigningKeyModulus; - private Data100 _keySeedPackageSigningKeyModulus; - private Data100 _kekEncryptionKeyModulus; - private Data100 _keyPackageSigningModulus; + private Array256 _tokenSigningKeyModulus; + private Array256 _keySeedPackageSigningKeyModulus; + private Array256 _kekEncryptionKeyModulus; + private Array256 _keyPackageSigningModulus; - public Span TokenSigningKeyModulus => _tokenSigningKeyModulus.Data; - public Span KeySeedPackageSigningKeyModulus => _keySeedPackageSigningKeyModulus.Data; - public Span KekEncryptionKeyModulus => _kekEncryptionKeyModulus.Data; - public Span KeyPackageSigningModulus => _keyPackageSigningModulus.Data; + public Span TokenSigningKeyModulus => _tokenSigningKeyModulus.Items; + public Span KeySeedPackageSigningKeyModulus => _keySeedPackageSigningKeyModulus.Items; + public Span KekEncryptionKeyModulus => _kekEncryptionKeyModulus.Items; + public Span KeyPackageSigningModulus => _keyPackageSigningModulus.Items; public SaveTransferAesKeyGenerator GenerateAesKey { get; set; } public RandomDataGenerator GenerateRandomData { get; set; } @@ -31,4 +31,4 @@ public class SaveDataTransferCryptoConfiguration SaveDataRepairInitialDataMacBeforeRepair, SaveDataRepairInitialDataMacAfterRepair } -} +} \ No newline at end of file diff --git a/tests/LibHac.Tests/Common/Layout.cs b/tests/LibHac.Tests/Common/Layout.cs new file mode 100644 index 00000000..1a0cb743 --- /dev/null +++ b/tests/LibHac.Tests/Common/Layout.cs @@ -0,0 +1,19 @@ +using System; +using System.Runtime.CompilerServices; + +namespace LibHac.Tests.Common; + +public class Layout +{ + public static int GetOffset(in TStruct structRef, in TField fieldRef) + { + ref TField structOffset = ref Unsafe.As(ref Unsafe.AsRef(in structRef)); + ref TField fieldOffset = ref Unsafe.AsRef(in fieldRef); + int offset = Unsafe.ByteOffset(ref structOffset, ref fieldOffset).ToInt32(); + + if (offset >= Unsafe.SizeOf()) + throw new ArgumentException($"Error getting field offset. {nameof(structRef)} and {nameof(fieldRef)} must be from the same struct instance."); + + return offset; + } +} \ No newline at end of file diff --git a/tests/LibHac.Tests/Fat/TypeLayoutTests.cs b/tests/LibHac.Tests/Fat/TypeLayoutTests.cs new file mode 100644 index 00000000..30c82b21 --- /dev/null +++ b/tests/LibHac.Tests/Fat/TypeLayoutTests.cs @@ -0,0 +1,23 @@ +using System.Runtime.CompilerServices; +using LibHac.Fat; +using Xunit; +using static LibHac.Tests.Common.Layout; + +namespace LibHac.Tests.Fat; + +public class TypeLayoutTests +{ + [Fact] + public static void FatError_Layout() + { + var s = new FatError(); + + Assert.Equal(0x20, Unsafe.SizeOf()); + + Assert.Equal(0x00, GetOffset(in s, in s.Error)); + Assert.Equal(0x04, GetOffset(in s, in s.ExtraError)); + Assert.Equal(0x08, GetOffset(in s, in s.DriveId)); + Assert.Equal(0x0C, GetOffset(in s, in s.ErrorName)); + Assert.Equal(0x1C, GetOffset(in s, in s.Reserved)); + } +} \ No newline at end of file