using System; using System.Collections.Generic; using System.Security.Cryptography; using System.Text; using lib; namespace client; public class Message { public uint Id { set; get; } public string Sender { set; get; } public bool IsAck { set; get; } public string Content { set; get; } public byte[] Signature { set; get; } public Message(byte[] bytes) { if (bytes[0] != 0) { Console.WriteLine("Failed parsing message, unsupported version"); } // skip the first byte for simplicity bytes = bytes[1..]; Id = BitConverter.ToUInt32(bytes, 0); Sender = Utils.BytesToNumber(bytes[4..12]); IsAck = bytes[12] != 0; Content = Encoding.UTF8.GetString(bytes[13..(bytes.Length - 32)]); Signature = bytes[(bytes.Length - 32)..]; } public Message(uint Id, string Sender, bool IsAck, string Content) { this.Id = Id; this.Sender = Sender; this.IsAck = IsAck; this.Content = Content; Signature = []; } public void CalculateSignature(RSA key) { Signature = key.SignData(Bytes(false), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); } public bool IsSignatureValid(RSA key) { return key.VerifyData(Bytes(false), Signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); } public byte[] Bytes(bool IncludeSignature = true) { List msg = []; // 0..4 msg.AddRange(BitConverter.GetBytes(Id)); // 4..12 msg.AddRange(Utils.NumberToBytes(Sender)); // 12 msg.Add((byte)(IsAck ? 1 : 0)); // 13..(len - 32) msg.AddRange(Encoding.UTF8.GetBytes(Content)); // (len - 32).. if (IncludeSignature) // we dont want to include the signature when we sign/verify the data { msg.AddRange(Signature); } return [0, .. msg]; } }