Tweak how the eticket rsa key pair is handled

This commit is contained in:
Alex Barney 2023-01-31 23:12:48 -07:00
parent 572849b67d
commit 754df0dcd9
8 changed files with 129 additions and 66 deletions

View file

@ -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[]

View file

@ -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[] { };
}

View file

@ -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]));

View file

@ -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
@ -402,4 +420,9 @@ public struct RsaSigningKeys
public struct RsaKeys
{
public RsaFullKey BetaNca0KeyAreaKey;
}
public struct DeviceRsaKeys
{
public RsaKeyPair ETicketRsaKey;
}

View file

@ -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;
}

View file

@ -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);
}
}

View 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>());
}
}

View file

@ -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>());
}
}