using System; using System.Collections.Generic; using System.Security.Cryptography; using System.Text; using System.Text.Json.Serialization; 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; } [JsonIgnore] 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]); Signature = []; } 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(), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); } public bool IsSignatureValid(RSA key) { return key.VerifyData(Bytes(), Signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); } public byte[] Bytes() { // initialize a list List msg = []; // 0..4 - message id msg.AddRange(BitConverter.GetBytes(Id)); // 4..12 - sender's phone number msg.AddRange(Utils.NumberToBytes(Sender)); // 12 - is this message an acknowledgement or a normal message msg.Add((byte)(IsAck ? 1 : 0)); // 13.. the message itself (should be empty for an acknowledgement) msg.AddRange(Encoding.UTF8.GetBytes(Content)); // Turn into array, prepending the version byte return [0, .. msg]; } }