diff --git a/src/LibHac/Es/ETicket.cs b/src/LibHac/Es/ETicket.cs new file mode 100644 index 00000000..2e395c35 --- /dev/null +++ b/src/LibHac/Es/ETicket.cs @@ -0,0 +1,76 @@ +using System; +using System.Runtime.InteropServices; +using LibHac.Common; + +namespace LibHac.Es +{ + [StructLayout(LayoutKind.Explicit, Size = 0x2C0)] + public struct ETicket + { + private const int SignatureSize = 0x200; + private const int IssuerSize = 0x40; + private const int TitleKeySize = 0x100; + private const int RightsIdSize = 0x10; + + [FieldOffset(0)] private SignatureType SignatureType; + [FieldOffset(4)] private byte _signature; + + [FieldOffset(0x140)] private byte _issuer; + [FieldOffset(0x180)] private byte _titleKey; + + [FieldOffset(0x280)] public byte FormatVersion; + [FieldOffset(0x281)] public TitleKeyType TitleKeyType; + [FieldOffset(0x282)] public ushort TicketVersion; + [FieldOffset(0x284)] public LicenseType LicenseType; + [FieldOffset(0x285)] public byte CommonKeyId; + [FieldOffset(0x286)] public TicketProperties PropertyMask; + + [FieldOffset(0x290)] public ulong TicketId; + [FieldOffset(0x298)] public ulong DeviceId; + [FieldOffset(0x2A0)] private byte _rightsId; + [FieldOffset(0x2B0)] public uint AccountId; + [FieldOffset(0x2B4)] public int SectTotalSize; + [FieldOffset(0x2B8)] public int SectHeaderOffset; + [FieldOffset(0x2BC)] public short SectNum; + [FieldOffset(0x2BE)] public short SectEntrySize; + + public Span Signature => SpanHelpers.CreateSpan(ref _signature, SignatureSize); + public Span Issuer => SpanHelpers.CreateSpan(ref _issuer, IssuerSize); + public Span TitleKey => SpanHelpers.CreateSpan(ref _titleKey, TitleKeySize); + public Span RightsId => SpanHelpers.CreateSpan(ref _rightsId, RightsIdSize); + } + + public enum SignatureType + { + Rsa4096Sha1 = 0x10000, + Rsa2048Sha1, + EcdsaSha1, + Rsa4096Sha256, + Rsa2048Sha256, + EcdsaSha256 + } + + public enum TitleKeyType : byte + { + Common, + Personalized + } + + public enum LicenseType : byte + { + Permanent, + Demo, + Trial, + Rental, + Subscription, + Service + } + + [Flags] + public enum TicketProperties : byte + { + PreInstall = 1 << 0, + SharedTitle = 1 << 1, + AllowAllContent = 1 << 2 + } +} diff --git a/src/LibHac/Es/ETicketReader.cs b/src/LibHac/Es/ETicketReader.cs new file mode 100644 index 00000000..f22478dd --- /dev/null +++ b/src/LibHac/Es/ETicketReader.cs @@ -0,0 +1,39 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using LibHac.Spl; + +namespace LibHac.Es +{ + public class ETicketReader + { + public ETicket Ticket; + + public ETicketReader() { } + + public ETicketReader(ETicket ticket) + { + Ticket = ticket; + } + + public ETicketReader(ReadOnlySpan ticketData) + { + if (ticketData.Length < Unsafe.SizeOf()) + { + throw new ArgumentException($"{nameof(ticketData)} must be at least {Unsafe.SizeOf()} bytes long."); + } + + Ticket = Unsafe.As(ref MemoryMarshal.GetReference(ticketData)); + } + + public AccessKey GetTitleKey(Keyset keyset) + { + if (Ticket.TitleKeyType == TitleKeyType.Common) + { + return Unsafe.As(ref MemoryMarshal.GetReference(Ticket.TitleKey)); + } + + return new AccessKey(CryptoOld.DecryptTitleKey(Ticket.TitleKey.ToArray(), keyset.EticketExtKeyRsa)); + } + } +} diff --git a/src/LibHac/FsSystem/StorageExtensions.cs b/src/LibHac/FsSystem/StorageExtensions.cs index 3deebdf5..ab7f3f74 100644 --- a/src/LibHac/FsSystem/StorageExtensions.cs +++ b/src/LibHac/FsSystem/StorageExtensions.cs @@ -179,7 +179,8 @@ namespace LibHac.FsSystem storage.GetSize(out long storageSize).ThrowIfFailure(); var arr = new byte[storageSize]; - storage.CopyTo(new MemoryStorage(arr)); + + storage.Read(0, arr); return arr; }