/ GUNRPG.Infrastructure / Security / ServerIdentity.cs
ServerIdentity.cs
 1  using System.Security.Cryptography;
 2  
 3  namespace GUNRPG.Security;
 4  
 5  public sealed class ServerIdentity
 6  {
 7      private readonly byte[] _serverPrivateKey;
 8  
 9      public ServerIdentity(ServerCertificate certificate, byte[] serverPrivateKey)
10      {
11          ArgumentNullException.ThrowIfNull(certificate);
12  
13          var normalizedPrivateKey = AuthorityCrypto.CloneAndValidatePrivateKey(serverPrivateKey);
14          var derivedPublicKey = AuthorityCrypto.GetPublicKey(normalizedPrivateKey);
15          var certificatePublicKey = certificate.PublicKey;
16          if (!CryptographicOperations.FixedTimeEquals(derivedPublicKey, certificatePublicKey))
17          {
18              throw new ArgumentException("The supplied private key does not match the certificate public key.", nameof(serverPrivateKey));
19          }
20  
21          Certificate = certificate;
22          _serverPrivateKey = normalizedPrivateKey;
23      }
24  
25      public ServerCertificate Certificate { get; }
26  
27      public RunValidationSignature SignRunValidation(
28          Guid runId,
29          Guid playerId,
30          byte[] finalStateHash)
31      {
32          var payloadHash = AuthorityCrypto.ComputeRunValidationPayloadHash(runId, playerId, finalStateHash);
33          var signature = AuthorityCrypto.SignHashedPayload(_serverPrivateKey, payloadHash);
34          return new RunValidationSignature(runId, playerId, finalStateHash, Certificate.ServerId, signature);
35      }
36  
37      public SignedRunValidation SignSignedRunValidation(Guid runId, Guid playerId, byte[] finalStateHash) =>
38          new(SignRunValidation(runId, playerId, finalStateHash), Certificate);
39  
40      public static byte[] GeneratePrivateKey() => AuthorityCrypto.GeneratePrivateKey();
41  
42      public static byte[] GetPublicKey(byte[] privateKey) => AuthorityCrypto.GetPublicKey(privateKey);
43  }