From d23a82c5a01d0f5ddb9545aca064a94fef4e12ed Mon Sep 17 00:00:00 2001 From: jvyden Date: Sun, 23 Jul 2023 23:22:36 -0400 Subject: [PATCH] Ticket verification works! --- NPTicket.Test/LbpSigningKey.cs | 9 ++++ NPTicket.Test/Program.cs | 4 +- NPTicket/Reader/TicketReader.cs | 4 +- NPTicket/Verification/ITicketSigningKey.cs | 1 + NPTicket/Verification/Keys/PsnSigningKey.cs | 1 + NPTicket/Verification/Keys/RpcnSigningKey.cs | 1 + .../TicketSignatureMessageType.cs | 7 +++ NPTicket/Verification/TicketVerifier.cs | 46 ++++++++++++++++++- 8 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 NPTicket.Test/LbpSigningKey.cs create mode 100644 NPTicket/Verification/TicketSignatureMessageType.cs diff --git a/NPTicket.Test/LbpSigningKey.cs b/NPTicket.Test/LbpSigningKey.cs new file mode 100644 index 0000000..66f0dbd --- /dev/null +++ b/NPTicket.Test/LbpSigningKey.cs @@ -0,0 +1,9 @@ +using NPTicket.Verification.Keys; + +namespace NPTicket.Test; + +public class LbpSigningKey : PsnSigningKey +{ + public override string CurveX => "39c62d061d4ee35c5f3f7531de0af3cf918346526edac727"; + public override string CurveY => "a5d578b55113e612bf1878d4cc939d61a41318403b5bdf86"; +} \ No newline at end of file diff --git a/NPTicket.Test/Program.cs b/NPTicket.Test/Program.cs index 28f8468..69d2eda 100644 --- a/NPTicket.Test/Program.cs +++ b/NPTicket.Test/Program.cs @@ -1,13 +1,13 @@ using System.Text.Json; using NPTicket; +using NPTicket.Test; using NPTicket.Verification; -using NPTicket.Verification.Keys; byte[] ticketData = await File.ReadAllBytesAsync(string.Join(' ', args)); Ticket ticket = Ticket.ReadFromBytes(ticketData); Console.WriteLine(JsonSerializer.Serialize(ticket)); -TicketVerifier verifier = new(ticketData, ticket, RpcnSigningKey.Instance); +TicketVerifier verifier = new(ticketData, ticket, new LbpSigningKey()); Console.WriteLine(JsonSerializer.Serialize(verifier)); Console.WriteLine(verifier.IsTicketValid()); \ No newline at end of file diff --git a/NPTicket/Reader/TicketReader.cs b/NPTicket/Reader/TicketReader.cs index 6e7dd74..b7acb97 100644 --- a/NPTicket/Reader/TicketReader.cs +++ b/NPTicket/Reader/TicketReader.cs @@ -34,11 +34,11 @@ internal ushort ReadTicketHeader() internal TicketDataSection ReadTicketSectionHeader() { + long position = this.BaseStream.Position; + this.ReadByte(); // Skip first byte of type (which is a short) - TicketDataSectionType type = (TicketDataSectionType)this.ReadByte(); ushort length = this.ReadUInt16(); - long position = this.BaseStream.Position; return new TicketDataSection(type, length, position); } diff --git a/NPTicket/Verification/ITicketSigningKey.cs b/NPTicket/Verification/ITicketSigningKey.cs index 5551e14..0a0528c 100644 --- a/NPTicket/Verification/ITicketSigningKey.cs +++ b/NPTicket/Verification/ITicketSigningKey.cs @@ -7,6 +7,7 @@ public interface ITicketSigningKey { string HashAlgorithm { get; } string CurveTable { get; } + TicketSignatureMessageType MessageType { get; } string CurveX { get; } string CurveY { get; } } \ No newline at end of file diff --git a/NPTicket/Verification/Keys/PsnSigningKey.cs b/NPTicket/Verification/Keys/PsnSigningKey.cs index 9b5c71c..7f375a3 100644 --- a/NPTicket/Verification/Keys/PsnSigningKey.cs +++ b/NPTicket/Verification/Keys/PsnSigningKey.cs @@ -4,6 +4,7 @@ public abstract class PsnSigningKey : ITicketSigningKey { public string HashAlgorithm => "SHA-1"; public string CurveTable => "secp192r1"; + public TicketSignatureMessageType MessageType => TicketSignatureMessageType.Ticket; public abstract string CurveX { get; } public abstract string CurveY { get; } } \ No newline at end of file diff --git a/NPTicket/Verification/Keys/RpcnSigningKey.cs b/NPTicket/Verification/Keys/RpcnSigningKey.cs index 2c39e23..e968441 100644 --- a/NPTicket/Verification/Keys/RpcnSigningKey.cs +++ b/NPTicket/Verification/Keys/RpcnSigningKey.cs @@ -10,6 +10,7 @@ private RpcnSigningKey() {} public string HashAlgorithm => "SHA-224"; public string CurveTable => "secp224k1"; + public TicketSignatureMessageType MessageType => TicketSignatureMessageType.Body; public string CurveX => "b07bc0f0addb97657e9f389039e8d2b9c97dc2a31d3042e7d0479b93"; public string CurveY => "d81c42b0abdf6c42191a31e31f93342f8f033bd529c2c57fdb5a0a7d"; } \ No newline at end of file diff --git a/NPTicket/Verification/TicketSignatureMessageType.cs b/NPTicket/Verification/TicketSignatureMessageType.cs new file mode 100644 index 0000000..0442db6 --- /dev/null +++ b/NPTicket/Verification/TicketSignatureMessageType.cs @@ -0,0 +1,7 @@ +namespace NPTicket.Verification; + +public enum TicketSignatureMessageType : byte +{ + Ticket = 0, + Body = 1, +} \ No newline at end of file diff --git a/NPTicket/Verification/TicketVerifier.cs b/NPTicket/Verification/TicketVerifier.cs index 6e201de..97605cb 100644 --- a/NPTicket/Verification/TicketVerifier.cs +++ b/NPTicket/Verification/TicketVerifier.cs @@ -1,3 +1,4 @@ +using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; @@ -9,12 +10,14 @@ namespace NPTicket.Verification; public class TicketVerifier { + private readonly TicketSignatureMessageType _messageType; private readonly Ticket _ticket; private readonly byte[] _ticketData; private readonly ISigner _signer; public TicketVerifier(byte[] ticketData, Ticket ticket, ITicketSigningKey key) { + this._messageType = key.MessageType; this._ticketData = ticketData; this._ticket = ticket; @@ -26,10 +29,49 @@ public TicketVerifier(byte[] ticketData, Ticket ticket, ITicketSigningKey key) this._signer = SignerUtilities.GetSigner(key.HashAlgorithm + "withECDSA"); this._signer.Init(false, publicKey); } + + // https://github.com/LBPUnion/ProjectLighthouse/blob/80cfb24d6f72ecdf45c8389b29a89fd1c13d0a96/ProjectLighthouse/Tickets/Signature/TicketSignatureVerifier.cs#L30 + // Sometimes psn signatures have one or two extra empty bytes + // This is slow but it's better than carelessly chopping 0's + private static byte[] TrimSignature(byte[] signature) + { + for (int i = 0; i <= 2; i++) + { + try + { + Asn1Object.FromByteArray(signature); + break; + } + catch + { + signature = signature.SkipLast(1).ToArray(); + } + } + + return signature; + } public bool IsTicketValid() { - this._signer.BlockUpdate(this._ticketData, this._ticket.BodySection.Position, this._ticket.BodySection.Length); - return this._signer.VerifySignature(this._ticketData); + int inOff; + int inLen; + + switch (this._messageType) + { + case TicketSignatureMessageType.Body: + inOff = this._ticket.BodySection.Position; + inLen = this._ticket.BodySection.Length + 4; + break; + case TicketSignatureMessageType.Ticket: + inOff = 0; + inLen = this._ticketData.Length - this._ticket.SignatureData.Length; + break; + default: + throw new NotImplementedException(this._messageType.ToString()); + } + + this._signer.BlockUpdate(this._ticketData, inOff, inLen); + + return this._signer.VerifySignature(TrimSignature(this._ticket.SignatureData)); } } \ No newline at end of file