public static byte[] MessageTransmissionHandler(Message message) { byte[] textBytes = new byte[0]; if (!String.IsNullOrEmpty(message.Text)) { textBytes = Encoding.Unicode.GetBytes(message.Text); } byte[] dataBytes = new byte[0]; if (message.Data != null) { dataBytes = message.Data; } byte[] messageBytes = ByteHelper.ConcatinateArray(BitConverter.GetBytes(message.From), new byte[] { (byte)message.Type }); messageBytes = ByteHelper.ConcatinateArray(messageBytes, dataBytes, textBytes); return(messageBytes); }
public static void MessageTransmissionHandler(Message message) { byte[] messageBytes = ChatTwo_Protocol.MessageTransmissionHandler(message); string sharedSecret; if (message.Type == ChatTwo_Protocol.MessageType.CreateUser) { sharedSecret = ChatTwo_Protocol.DefaultSharedSecret; } else if (message.Type == ChatTwo_Protocol.MessageType.Login) { ServerSharedSecret = ByteHelper.GetHashString(messageBytes); sharedSecret = ServerSharedSecret; } else if (message.To == ChatTwo_Protocol.ServerReserrvedUserID) { sharedSecret = ServerSharedSecret; } else { int userId = message.To; sharedSecret = _contacts.Find(x => x.ID == userId).Secret; // Testing!!!! REMOVE THIS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! sharedSecret = ChatTwo_Protocol.DefaultSharedSecret; } messageBytes = ChatTwo_Protocol.AddSignatureAndMac(messageBytes, sharedSecret); // Fire an OnMessageTransmission event. PacketTransmissionEventArgs args = new PacketTransmissionEventArgs(); args.Destination = message.Ip; args.PacketContent = messageBytes; OnMessageTransmission(args); }
private static void Keepalive() // Threaded looping method. { try { while (_loggedIn) { Thread.Sleep(500); List <ContactObj> onlineContacts = _contacts.FindAll(x => x.Online == true); byte[] contactIds = new byte[0]; foreach (ContactObj contact in onlineContacts) { byte[] contactId = BitConverter.GetBytes(contact.ID); contactIds = ByteHelper.ConcatinateArray(contactIds, contactId); } ChatTwo_Client_Protocol.MessageToServer(ChatTwo_Protocol.MessageType.Status, contactIds, null); } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine("### " + _threadKeepalive.Name + " has crashed:"); System.Diagnostics.Debug.WriteLine("### " + ex.Message); System.Diagnostics.Debug.WriteLine("### " + ex.ToString()); } }
private static string CreateMac(byte[] messageBytes, string sharedSecret) { return(ByteHelper.GetHashString(ByteHelper.ConcatinateArray(ByteHelper.GetHashBytes(messageBytes), Convert.FromBase64String(sharedSecret)))); }
public static byte[] RemoveSignatureAndMac(byte[] bytes) { bytes = ByteHelper.SubArray(bytes, SignatureByteLength + ByteHelper.HashByteLength); // Remove the signature, the version number and the MAC. return(bytes); }
public static void MessageReceivedHandler(object sender, PacketReceivedEventArgs args) { if (args.Data[0] == 0x92) { string sharedSecret; // Position of the Type byte is 30 (SignatureByteLength + MacByteLength + TimezByteLength + UserIdByteLength). ChatTwo_Protocol.MessageType type = (ChatTwo_Protocol.MessageType)args.Data[ChatTwo_Protocol.SignatureByteLength + ByteHelper.HashByteLength + 4 + 4]; // Position of the UserID bytes is 26 (SignatureByteLength + MacByteLength + TimezByteLength) with a length of 4. int senderId = ByteHelper.ToInt32(args.Data, ChatTwo_Protocol.SignatureByteLength + ByteHelper.HashByteLength + 4); if (type == ChatTwo_Protocol.MessageType.CreateUserReply) { sharedSecret = ChatTwo_Protocol.DefaultSharedSecret; } else if (senderId == 0) { sharedSecret = ServerSharedSecret; } else { sharedSecret = _contacts.Find(x => x.ID == senderId).Secret; // Testing!!!! REMOVE THIS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! sharedSecret = ChatTwo_Protocol.DefaultSharedSecret; } if (ChatTwo_Protocol.ValidateMac(args.Data, sharedSecret)) { Message message = ChatTwo_Protocol.MessageReceivedHandler(args); switch (message.Type) { case ChatTwo_Protocol.MessageType.CreateUserReply: { // Fire an OnCreateUserReply event. CreateUserReplyEventArgs argsCreateUser = new CreateUserReplyEventArgs(); argsCreateUser.Success = message.Data[0] == 0x00; switch (message.Data[0]) { case 0: // Success. break; case 1: // Username already exist. argsCreateUser.Message = "A user already exist with that name."; break; case 2: argsCreateUser.Message = "Username is too short or too long."; break; } OnCreateUserReply(argsCreateUser); break; } case ChatTwo_Protocol.MessageType.LoginReply: { // Fire an OnLoginReply event. LoginReplyEventArgs argsLogin = new LoginReplyEventArgs(); argsLogin.Success = message.Data[0] == 0x00; switch (message.Data[0]) { case 0: // Success. int userId = ByteHelper.ToInt32(message.Data, 1); string username = Encoding.Unicode.GetString(ByteHelper.SubArray(message.Data, 5)); LogIn(userId); _user.Name = username; argsLogin.Name = username; break; case 1: // Wrong password. argsLogin.Message = "Wrong username or password."; break; case 2: // Already online. argsLogin.Message = "That user is already online."; break; } OnLoginReply(argsLogin); break; } case ChatTwo_Protocol.MessageType.ContactRequestReply: { // Fire an OnAddContactReply event. AddContactReplyEventArgs argsAddContact = new AddContactReplyEventArgs(); argsAddContact.Success = message.Data[0] == 0x00; switch (message.Data[0]) { case 0: // Success. break; case 1: // No user with that name. argsAddContact.Message = "No user with that name."; break; case 2: // You can't add your self. argsAddContact.Message = "You can't add your self."; break; case 3: // User is already a contact. argsAddContact.Message = "User is already a contact."; break; } OnAddContactReply(argsAddContact); break; } case ChatTwo_Protocol.MessageType.ContactStatus: { int contactId = ByteHelper.ToInt32(message.Data, 0); int nameLength = ((31 & message.Data[4]) * 2); ContactObj contact; if (_contacts.Any(x => x.ID == contactId)) { contact = _contacts.Find(x => x.ID == contactId); } else { contact = new ContactObj(); contact.ID = contactId; contact.Name = Encoding.Unicode.GetString(message.Data, 5, nameLength); _contacts.Add(contact); } contact.Online = ByteHelper.CheckBitCodeIndex(message.Data[4], 7); contact.RelationshipTo = ByteHelper.CheckBitCodeIndex(message.Data[4], 6); contact.RelationshipFrom = ByteHelper.CheckBitCodeIndex(message.Data[4], 5); if (contact.Online) { int port = ByteHelper.ToInt32(message.Data, 5 + nameLength); contact.Socket = new IPEndPoint(new IPAddress(ByteHelper.SubArray(message.Data, 5 + nameLength + 4)), port); } // Fire an OnContactUpdate event. OnContactUpdate(); break; } case ChatTwo_Protocol.MessageType.Message: { ContactObj contact; if (_contacts.Any(x => x.ID == message.From && x.RelationshipTo && x.RelationshipFrom)) { contact = _contacts.Find(x => x.ID == message.From); OpenChat(contact.ID); message.Text = Encoding.Unicode.GetString(message.Data); contact.ChatWindow.ReceiveMessage(message.Text); } else #if DEBUG { throw new NotImplementedException("You received a message from someone that isn't your contact?"); } #else { return; } #endif break; } } } #if DEBUG else { throw new NotImplementedException("Could not validate the MAC of received message."); } // Need to add a simple debug message here, but this works as a great breakpoint until then. #endif } #if DEBUG else { throw new NotImplementedException("Could not validate the signature of the received message. The signature was \"0x" + args.Data[0] + "\" but only \"0x92\" is allowed."); } // Need to add a simple debug message here, but this works as a great breakpoint until then. #endif }
/// <summary> /// This is a threaded method that keeps looping while _online is true. /// It will receive UDP messages on the UdpClient's port number and forward them to the OnPacketReceived event. /// </summary> public void ReceivePacket() // Threaded looping method. { while (_online) { try { IPEndPoint remoteSender = new IPEndPoint(IPAddress.Any, 0); byte[] receivedBytes = _client.Receive(ref remoteSender); if (receivedBytes != null && receivedBytes.Length != 0) { if (receivedBytes.Length == ByteHelper.HashByteLength + 2 && receivedBytes[0] == 0xCE && receivedBytes[receivedBytes.Length - 1] == 0xCE) { if (_messageSendingControlList.Count != 0) { // The received message is a ACK message. string hash = OpenAck(receivedBytes); ControlledPacket packet = _messageSendingControlList.Find(x => x.Hash == hash); if (packet != null) { _messageSendingControlList.Remove(packet); } } } else if (receivedBytes.Length == 1 && receivedBytes[0] == 0xEC) { // Fire an OnEtherConnectionReply event. OnEtherConnectionReply(null); } else { // Send back an ACK packet. string hash = ByteHelper.GetHashString(receivedBytes); byte[] ackBytes = CreateAck(hash); _client.Send(ackBytes, ackBytes.Length, remoteSender); // Check if the message is a duplicate. if (!_messageReceivingControlList.Any(x => x == hash)) { // Add the message's hash to a list so we don't react on the same message twice. _messageReceivingControlList.Add(hash); if (_messageReceivingControlList.Count > 5) // Only keep the latest 5 messages. { _messageReceivingControlList.RemoveAt(0); } // Fire an OnPacketReceived event. PacketReceivedEventArgs args = new PacketReceivedEventArgs(); args.Sender = remoteSender; args.Data = receivedBytes; OnPacketReceived(args); } } } } catch (SocketException ex) { if (ex.SocketErrorCode != SocketError.TimedOut) { System.Diagnostics.Debug.WriteLine("### " + _threadPacketListener.Name + " has crashed:"); System.Diagnostics.Debug.WriteLine("### " + ex.Message); System.Diagnostics.Debug.WriteLine("### " + ex.ToString()); break; } else { continue; } } } }
/// <summary> /// Create an ACK packet from a base64 hash string. /// </summary> /// <param name="hash">Base64 hash string to be used.</param> protected byte[] CreateAck(string hash) { byte[] ackTag = new byte[] { 0xCE }; // 0xCE = 206 byte[] ackBytes = ByteHelper.ConcatinateArray(ackTag, Convert.FromBase64String(hash), ackTag); return(ackBytes); }
private void btnRegister_Click(object sender, EventArgs e) { ResetWindow(); // If there is no username entered. if (tbxUsername.Text == "") { lblUsername.ForeColor = Color.Red; tbxUsername.ForeColor = Color.Red; lblResult.ForeColor = Color.Red; lblResult.Text = "You did not enter a username."; return; } // If the username is too long. if (tbxUsername.Text.Length > 30) { lblUsername.ForeColor = Color.Red; tbxUsername.ForeColor = Color.Red; lblResult.ForeColor = Color.Red; lblResult.Text = "The username is too long. Please use 30 or less characters."; return; } // If there is no password entered. if (tbxPassword1.Text == "") { lblPassword1.ForeColor = Color.Red; tbxPassword1.ForeColor = Color.Red; lblResult.ForeColor = Color.Red; lblResult.Text = "You did not enter a password."; return; } // If the password and the confirm password textboxes aren't the same. if (tbxPassword1.Text != tbxPassword2.Text) { lblPassword2.ForeColor = Color.Red; tbxPassword2.ForeColor = Color.Red; lblResult.ForeColor = Color.Red; lblResult.Text = "The two passwords are not the same."; return; } // If the password is too short. // (I hate strict password rules! If it is not a bank or social security thing, don't force the uesr to make insane passwords.) if (tbxPassword1.Text.Length < 4) { lblPassword1.ForeColor = Color.Red; tbxPassword1.ForeColor = Color.Red; lblResult.ForeColor = Color.Red; lblResult.Text = "The password is too short. Please use 4 or more characters."; return; } btnRegister.Enabled = false; btnCancel.Enabled = false; tbxUsername.ReadOnly = true; tbxPassword1.ReadOnly = true; tbxPassword2.ReadOnly = true; lblResult.Text = "Contacting server..."; _waitingForCreateUserReply = true; byte[] passwordHash = ByteHelper.GetHashBytes(Encoding.Unicode.GetBytes(tbxPassword1.Text)); ChatTwo_Client_Protocol.MessageToServer(ChatTwo_Protocol.MessageType.CreateUser, passwordHash, tbxUsername.Text); timer1.Start(); }