Skip to content

Commit

Permalink
Ticket verification works!
Browse files Browse the repository at this point in the history
  • Loading branch information
jvyden committed Jul 24, 2023
1 parent 3278fa8 commit d23a82c
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 6 deletions.
9 changes: 9 additions & 0 deletions NPTicket.Test/LbpSigningKey.cs
Original file line number Diff line number Diff line change
@@ -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";
}
4 changes: 2 additions & 2 deletions NPTicket.Test/Program.cs
Original file line number Diff line number Diff line change
@@ -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());
4 changes: 2 additions & 2 deletions NPTicket/Reader/TicketReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
1 change: 1 addition & 0 deletions NPTicket/Verification/ITicketSigningKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public interface ITicketSigningKey
{
string HashAlgorithm { get; }
string CurveTable { get; }
TicketSignatureMessageType MessageType { get; }
string CurveX { get; }
string CurveY { get; }
}
1 change: 1 addition & 0 deletions NPTicket/Verification/Keys/PsnSigningKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
}
1 change: 1 addition & 0 deletions NPTicket/Verification/Keys/RpcnSigningKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
7 changes: 7 additions & 0 deletions NPTicket/Verification/TicketSignatureMessageType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace NPTicket.Verification;

public enum TicketSignatureMessageType : byte
{
Ticket = 0,
Body = 1,
}
46 changes: 44 additions & 2 deletions NPTicket/Verification/TicketVerifier.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
Expand All @@ -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;

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

0 comments on commit d23a82c

Please sign in to comment.