예제 #1
0
        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);
        }
예제 #2
0
        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);
        }
예제 #3
0
 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());
     }
 }
예제 #4
0
 private static string CreateMac(byte[] messageBytes, string sharedSecret)
 {
     return(ByteHelper.GetHashString(ByteHelper.ConcatinateArray(ByteHelper.GetHashBytes(messageBytes), Convert.FromBase64String(sharedSecret))));
 }
예제 #5
0
 public static byte[] RemoveSignatureAndMac(byte[] bytes)
 {
     bytes = ByteHelper.SubArray(bytes, SignatureByteLength + ByteHelper.HashByteLength); // Remove the signature, the version number and the MAC.
     return(bytes);
 }
예제 #6
0
        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
        }
예제 #7
0
        /// <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;
                    }
                }
            }
        }
예제 #8
0
 /// <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);
 }
예제 #9
0
        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();
        }