mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Tweak how the eticket rsa key pair is handled
This commit is contained in:
parent
572849b67d
commit
754df0dcd9
8 changed files with 129 additions and 66 deletions
|
@ -37,6 +37,7 @@ public static class KeysCodeGen
|
|||
sb.AppendLine("internal static partial class DefaultKeySet");
|
||||
sb.AppendLineAndIncrease("{");
|
||||
|
||||
BuildArray(sb, "TsecSecrets", SpanHelpers.AsReadOnlyByteSpan(in keySet.KeyStruct.TsecSecrets));
|
||||
BuildArray(sb, "RootKeysDev", SpanHelpers.AsReadOnlyByteSpan(in keySet.KeyStruct.RootKeysDev));
|
||||
BuildArray(sb, "RootKeysProd", SpanHelpers.AsReadOnlyByteSpan(in keySet.KeyStruct.RootKeysProd));
|
||||
BuildArray(sb, "KeySeeds", SpanHelpers.AsReadOnlyByteSpan(in keySet.KeyStruct.KeySeeds));
|
||||
|
@ -50,6 +51,7 @@ public static class KeysCodeGen
|
|||
BuildArray(sb, "RsaSigningKeysDev", SpanHelpers.AsReadOnlyByteSpan(in keySet.KeyStruct.RsaSigningKeysDev));
|
||||
BuildArray(sb, "RsaSigningKeysProd", SpanHelpers.AsReadOnlyByteSpan(in keySet.KeyStruct.RsaSigningKeysProd));
|
||||
BuildArray(sb, "RsaKeys", SpanHelpers.AsReadOnlyByteSpan(in keySet.KeyStruct.RsaKeys));
|
||||
BuildArray(sb, "DeviceRsaKeys", SpanHelpers.AsReadOnlyByteSpan(in keySet.KeyStruct.DeviceRsaKeys));
|
||||
|
||||
sb.DecreaseAndAppend("}");
|
||||
|
||||
|
@ -147,7 +149,7 @@ public static class KeysCodeGen
|
|||
|
||||
private static ReadOnlySpan<byte> StandardPublicExponent => new byte[]
|
||||
{
|
||||
0x01, 0x00, 0x01
|
||||
0x00, 0x01, 0x00, 0x01
|
||||
};
|
||||
|
||||
private static ReadOnlySpan<byte> BetaNca0Modulus => new byte[]
|
||||
|
|
|
@ -4,6 +4,7 @@ namespace LibHac.Common.Keys;
|
|||
|
||||
internal static partial class DefaultKeySet
|
||||
{
|
||||
private static ReadOnlySpan<byte> TsecSecrets => new byte[] { };
|
||||
private static ReadOnlySpan<byte> RootKeysDev => new byte[] { };
|
||||
private static ReadOnlySpan<byte> RootKeysProd => new byte[] { };
|
||||
private static ReadOnlySpan<byte> KeySeeds => new byte[] { };
|
||||
|
@ -17,4 +18,5 @@ internal static partial class DefaultKeySet
|
|||
private static ReadOnlySpan<byte> RsaSigningKeysDev => new byte[] { };
|
||||
private static ReadOnlySpan<byte> RsaSigningKeysProd => new byte[] { };
|
||||
private static ReadOnlySpan<byte> RsaKeys => new byte[] { };
|
||||
private static ReadOnlySpan<byte> DeviceRsaKeys => new byte[] { };
|
||||
}
|
|
@ -17,6 +17,11 @@ internal static partial class DefaultKeySet
|
|||
|
||||
// Fill the key set with any key structs included in the library.
|
||||
// This is split into multiple parts so the binary size isn't increased when providing only some keys.
|
||||
if (TsecSecrets.Length == Unsafe.SizeOf<TsecSecrets>())
|
||||
{
|
||||
keySet.KeyStruct.TsecSecrets = SpanHelpers.AsReadOnlyStruct<TsecSecrets>(TsecSecrets);
|
||||
}
|
||||
|
||||
if (RootKeysDev.Length == Unsafe.SizeOf<RootKeys>())
|
||||
{
|
||||
keySet.KeyStruct.RootKeysDev = SpanHelpers.AsReadOnlyStruct<RootKeys>(RootKeysDev);
|
||||
|
@ -82,6 +87,11 @@ internal static partial class DefaultKeySet
|
|||
keySet.KeyStruct.RsaKeys = SpanHelpers.AsReadOnlyStruct<RsaKeys>(RsaKeys);
|
||||
}
|
||||
|
||||
if (DeviceRsaKeys.Length == Unsafe.SizeOf<DeviceRsaKeys>())
|
||||
{
|
||||
keySet.KeyStruct.DeviceRsaKeys = SpanHelpers.AsReadOnlyStruct<DeviceRsaKeys>(DeviceRsaKeys);
|
||||
}
|
||||
|
||||
return keySet;
|
||||
}
|
||||
|
||||
|
@ -183,7 +193,7 @@ internal static partial class DefaultKeySet
|
|||
|
||||
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));
|
||||
keys.Add(new KeyInfo(282, Type.DeviceDrvd, "eticket_rsa_keypair", (set, _) => set.ETicketRsaKeyPair));
|
||||
keys.Add(new KeyInfo(282, Type.DeviceDrvd, "eticket_rsa_keypair", (set, _) => SpanHelpers.AsByteSpan(ref set.ETicketRsaKey)));
|
||||
|
||||
keys.Add(new KeyInfo(290, Type.CommonDrvd, "key_area_key_application", 0, KeyRevisionCount, (set, i) => set.KeyAreaKeys[i][0]));
|
||||
keys.Add(new KeyInfo(300, Type.CommonDrvd, "key_area_key_ocean", 0, KeyRevisionCount, (set, i) => set.KeyAreaKeys[i][1]));
|
||||
|
|
|
@ -46,6 +46,7 @@ public class KeySet
|
|||
private ref DerivedDeviceKeys DerivedDeviceKeys => ref _mode == Mode.Dev ? ref _keys.DerivedDeviceKeysDev : ref _keys.DerivedDeviceKeysProd;
|
||||
private ref RsaSigningKeys RsaSigningKeys => ref _mode == Mode.Dev ? ref _keys.RsaSigningKeysDev : ref _keys.RsaSigningKeysProd;
|
||||
private ref RsaKeys RsaKeys => ref _keys.RsaKeys;
|
||||
private ref DeviceRsaKeys DeviceRsaKeys => ref _keys.DeviceRsaKeys;
|
||||
|
||||
private ref RsaSigningKeyParameters RsaSigningKeyParams => ref _mode == Mode.Dev
|
||||
? ref _rsaSigningKeyParamsDev
|
||||
|
@ -124,12 +125,12 @@ public class KeySet
|
|||
public Span<RsaKey> AcidSigningKeys => RsaSigningKeys.AcidSigningKeys.Items;
|
||||
public ref RsaKey Package2SigningKey => ref RsaSigningKeys.Package2SigningKey;
|
||||
public ref RsaFullKey BetaNca0KeyAreaKey => ref RsaKeys.BetaNca0KeyAreaKey;
|
||||
public ref RsaKeyPair ETicketRsaKey => ref DeviceRsaKeys.ETicketRsaKey;
|
||||
|
||||
private RsaSigningKeyParameters _rsaSigningKeyParamsDev;
|
||||
private RsaSigningKeyParameters _rsaSigningKeyParamsProd;
|
||||
private RsaKeyParameters _rsaKeyParams;
|
||||
|
||||
public ref RsaKeyPair ETicketRsaKeyPair => ref DerivedDeviceKeys.ETicketRsaKeyPair;
|
||||
|
||||
public Span<RSAParameters> NcaHeaderSigningKeyParams
|
||||
{
|
||||
|
@ -196,6 +197,22 @@ public class KeySet
|
|||
}
|
||||
}
|
||||
|
||||
public ref RSAParameters ETicketRsaKeyParams
|
||||
{
|
||||
get
|
||||
{
|
||||
ref Optional<RSAParameters> keys = ref _rsaKeyParams.ETicketRsaKey;
|
||||
|
||||
if (!keys.HasValue && !ETicketRsaKey.PublicExponent.ItemsRo.IsZeros())
|
||||
{
|
||||
RSAParameters rsaParams = Rsa.RecoverParameters(ETicketRsaKey.Modulus, ETicketRsaKey.PublicExponent, ETicketRsaKey.PrivateExponent);
|
||||
keys.Set(rsaParams);
|
||||
}
|
||||
|
||||
return ref keys.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSdSeed(ReadOnlySpan<byte> sdSeed)
|
||||
{
|
||||
if (sdSeed.Length != 0x10)
|
||||
|
@ -270,6 +287,7 @@ public class KeySet
|
|||
private struct RsaKeyParameters
|
||||
{
|
||||
public Optional<RSAParameters> BetaNca0KeyAreaKey;
|
||||
public Optional<RSAParameters> ETicketRsaKey;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -289,6 +307,7 @@ public struct AllKeys
|
|||
public RsaSigningKeys RsaSigningKeysDev;
|
||||
public RsaSigningKeys RsaSigningKeysProd;
|
||||
public RsaKeys RsaKeys;
|
||||
public DeviceRsaKeys DeviceRsaKeys;
|
||||
}
|
||||
|
||||
public struct TsecSecrets
|
||||
|
@ -389,7 +408,6 @@ public struct DerivedDeviceKeys
|
|||
public Array2<AesKey> DeviceUniqueSaveMacKeys;
|
||||
public AesKey SeedUniqueSaveMacKey;
|
||||
public Array3<AesXtsKey> SdCardEncryptionKeys;
|
||||
public RsaKeyPair ETicketRsaKeyPair;
|
||||
}
|
||||
|
||||
public struct RsaSigningKeys
|
||||
|
@ -403,3 +421,8 @@ public struct RsaKeys
|
|||
{
|
||||
public RsaFullKey BetaNca0KeyAreaKey;
|
||||
}
|
||||
|
||||
public struct DeviceRsaKeys
|
||||
{
|
||||
public RsaKeyPair ETicketRsaKey;
|
||||
}
|
|
@ -115,43 +115,31 @@ public struct AesCmac
|
|||
#endif
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RsaFullKey
|
||||
{
|
||||
// ReSharper disable once UnassignedField.Global
|
||||
public Array256<byte> PrivateExponent;
|
||||
public Array256<byte> Modulus;
|
||||
public Array4<byte> PublicExponent;
|
||||
public Array128<byte> Dp;
|
||||
public Array128<byte> Dq;
|
||||
public Array3<byte> PublicExponent;
|
||||
public Array128<byte> InverseQ;
|
||||
public Array256<byte> Modulus;
|
||||
public Array128<byte> P;
|
||||
public Array128<byte> Q;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RsaKey
|
||||
{
|
||||
public Array256<byte> Modulus;
|
||||
public Array3<byte> PublicExponent;
|
||||
public Array4<byte> PublicExponent;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = Size)]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RsaKeyPair
|
||||
{
|
||||
private const int Size = 0x210;
|
||||
|
||||
[FieldOffset(0)] private byte _byte;
|
||||
[FieldOffset(0)] private ulong _ulong;
|
||||
|
||||
[FieldOffset(0)] public Array256<byte> PrivateExponent;
|
||||
[FieldOffset(0x100)] public Array256<byte> Modulus;
|
||||
[FieldOffset(0x200)] public Array4<byte> PublicExponent;
|
||||
[FieldOffset(0x204)] public Array12<byte> Reserved;
|
||||
|
||||
public Span<byte> Data => SpanHelpers.CreateSpan(ref _byte, Size);
|
||||
public readonly ReadOnlySpan<byte> DataRo => SpanHelpers.CreateReadOnlySpan(in _byte, Size);
|
||||
|
||||
public static implicit operator Span<byte>(in RsaKeyPair value) => Unsafe.AsRef(in value).Data;
|
||||
public static implicit operator ReadOnlySpan<byte>(in RsaKeyPair value) => value.DataRo;
|
||||
|
||||
public readonly override string ToString() => DataRo.ToHexString();
|
||||
public Array256<byte> PrivateExponent;
|
||||
public Array256<byte> Modulus;
|
||||
public Array4<byte> PublicExponent;
|
||||
public Array12<byte> Reserved;
|
||||
}
|
|
@ -1,9 +1,7 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using LibHac.Common;
|
||||
using LibHac.Common.Keys;
|
||||
using LibHac.Crypto;
|
||||
using LibHac.Tools.Crypto;
|
||||
using LibHac.Util;
|
||||
|
||||
|
@ -159,11 +157,10 @@ public class Ticket
|
|||
return commonKey;
|
||||
}
|
||||
|
||||
RSAParameters rsaParameters = Rsa.RecoverParameters(
|
||||
keySet.ETicketRsaKeyPair.Modulus,
|
||||
keySet.ETicketRsaKeyPair.PublicExponent,
|
||||
keySet.ETicketRsaKeyPair.PrivateExponent);
|
||||
return CryptoOld.DecryptRsaOaep(TitleKeyBlock, rsaParameters);
|
||||
if (keySet.ETicketRsaKey.PublicExponent.ItemsRo.IsZeros())
|
||||
return null;
|
||||
|
||||
return CryptoOld.DecryptRsaOaep(TitleKeyBlock, keySet.ETicketRsaKeyParams);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
74
tests/LibHac.Tests/CryptoTests/TypeLayoutTests.cs
Normal file
74
tests/LibHac.Tests/CryptoTests/TypeLayoutTests.cs
Normal file
|
@ -0,0 +1,74 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Crypto;
|
||||
using Xunit;
|
||||
using static LibHac.Tests.Common.Layout;
|
||||
|
||||
namespace LibHac.Tests.CryptoTests;
|
||||
|
||||
public class TypeLayoutTests
|
||||
{
|
||||
[Fact]
|
||||
public static void RsaFullKey_Layout()
|
||||
{
|
||||
var s = new RsaFullKey();
|
||||
|
||||
Assert.Equal(0x484, Unsafe.SizeOf<RsaFullKey>());
|
||||
|
||||
Assert.Equal(0x000, GetOffset(in s, in s.PrivateExponent));
|
||||
Assert.Equal(0x100, GetOffset(in s, in s.Modulus));
|
||||
Assert.Equal(0x200, GetOffset(in s, in s.PublicExponent));
|
||||
Assert.Equal(0x204, GetOffset(in s, in s.Dp));
|
||||
Assert.Equal(0x284, GetOffset(in s, in s.Dq));
|
||||
Assert.Equal(0x304, GetOffset(in s, in s.InverseQ));
|
||||
Assert.Equal(0x384, GetOffset(in s, in s.P));
|
||||
Assert.Equal(0x404, GetOffset(in s, in s.Q));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void RsaKeyPair_Layout()
|
||||
{
|
||||
var s = new RsaKeyPair();
|
||||
|
||||
Assert.Equal(0x210, Unsafe.SizeOf<RsaKeyPair>());
|
||||
|
||||
Assert.Equal(0x000, GetOffset(in s, in s.PrivateExponent));
|
||||
Assert.Equal(0x100, GetOffset(in s, in s.Modulus));
|
||||
Assert.Equal(0x200, GetOffset(in s, in s.PublicExponent));
|
||||
Assert.Equal(0x204, GetOffset(in s, in s.Reserved));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void RsaKey_Layout()
|
||||
{
|
||||
var s = new RsaKey();
|
||||
|
||||
Assert.Equal(0x104, Unsafe.SizeOf<RsaKey>());
|
||||
|
||||
Assert.Equal(0x000, GetOffset(in s, in s.Modulus));
|
||||
Assert.Equal(0x100, GetOffset(in s, in s.PublicExponent));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void AesKey_Layout()
|
||||
{
|
||||
Assert.Equal(0x10, Unsafe.SizeOf<AesKey>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void AesXtsKey_Layout()
|
||||
{
|
||||
Assert.Equal(0x20, Unsafe.SizeOf<AesXtsKey>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void AesIv_Layout()
|
||||
{
|
||||
Assert.Equal(0x10, Unsafe.SizeOf<AesIv>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void AesCmac_Layout()
|
||||
{
|
||||
Assert.Equal(0x10, Unsafe.SizeOf<Crypto.AesCmac>());
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
// ReSharper disable InconsistentNaming
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Crypto;
|
||||
using Xunit;
|
||||
|
||||
namespace LibHac.Tests.CryptoTests;
|
||||
|
||||
public class TypeSizeTests
|
||||
{
|
||||
[Fact]
|
||||
public static void AesKeySizeIs0x10()
|
||||
{
|
||||
Assert.Equal(0x10, Unsafe.SizeOf<AesKey>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void AesXtsKeySizeIs0x20()
|
||||
{
|
||||
Assert.Equal(0x20, Unsafe.SizeOf<AesXtsKey>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void AesIvSizeIs0x10()
|
||||
{
|
||||
Assert.Equal(0x10, Unsafe.SizeOf<AesIv>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void AesCmacSizeIs0x10()
|
||||
{
|
||||
Assert.Equal(0x10, Unsafe.SizeOf<Crypto.AesCmac>());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue