/// <summary> /// Occurs when the client has been sucessfully authenticated by the loginserver. /// Called by UILoginDialog.cs. /// </summary> /// <param name="Client">The client that received the packet.</param> /// <param name="Packet">The packet that was received.</param> public static void OnLoginNotify(NetworkClient Client, ProcessedPacket Packet) { //Should this be stored for permanent access? byte[] ServerPublicKey = Packet.ReadBytes(Packet.ReadByte()); byte[] EncryptedData = Packet.ReadBytes(Packet.ReadByte()); AESEncryptor Enc = (AESEncryptor)Client.ClientEncryptor; Enc.PublicKey = ServerPublicKey; Client.ClientEncryptor = Enc; lock (NetworkFacade.Client) NetworkFacade.Client.ClientEncryptor = Enc; ECDiffieHellmanCng PrivateKey = Client.ClientEncryptor.GetDecryptionArgsContainer().AESDecryptArgs.PrivateKey; byte[] NOnce = Client.ClientEncryptor.GetDecryptionArgsContainer().AESDecryptArgs.NOnce; byte[] ChallengeResponse = StaticStaticDiffieHellman.Decrypt(PrivateKey, ECDiffieHellmanCngPublicKey.FromByteArray(ServerPublicKey, CngKeyBlobFormat.EccPublicBlob), NOnce, EncryptedData); MemoryStream StreamToEncrypt = new MemoryStream(); BinaryWriter Writer = new BinaryWriter(StreamToEncrypt); Writer.Write((byte)ChallengeResponse.Length); Writer.Write(ChallengeResponse, 0, ChallengeResponse.Length); Writer.Write(Client.ClientEncryptor.Username); Writer.Write((byte)PlayerAccount.Hash.Length); Writer.Write(PlayerAccount.Hash); Writer.Flush(); //Encrypt data using key and IV from server, hoping that it'll be decrypted correctly at the other end... Client.SendEncrypted((byte)PacketType.CHALLENGE_RESPONSE, StreamToEncrypt.ToArray()); }
/// <summary> /// A client requested login. /// </summary> /// <param name="Client">NetworkClient instance.</param> /// <param name="Packet">ProcessedPacket instance.</param> public static void InitialClientConnect(NetworkClient Client, ProcessedPacket Packet) { Console.WriteLine("Server receives data - test 1"); PacketStream EncryptedPacket = new PacketStream(0x02, 0); EncryptedPacket.WriteHeader(); ClientPublicKey = Packet.ReadBytes((Packet.ReadByte())); AESEncryptor Enc = (AESEncryptor)Client.ClientEncryptor; Enc.NOnce = Packet.ReadBytes((Packet.ReadByte())); Enc.PublicKey = ClientPublicKey; Enc.PrivateKey = ServerPrivateKey; Client.ClientEncryptor = Enc; //THIS IS IMPORTANT - public key must be derived from private! ServerPublicKey = ServerPrivateKey.PublicKey.ToByteArray(); ChallengeResponse = new byte[16]; m_Random.GetNonZeroBytes(ChallengeResponse); MemoryStream StreamToEncrypt = new MemoryStream(); BinaryWriter Writer = new BinaryWriter(StreamToEncrypt); Writer.Write(ChallengeResponse, 0, ChallengeResponse.Length); Writer.Flush(); byte[] EncryptedData = StaticStaticDiffieHellman.Encrypt(ServerPrivateKey, ECDiffieHellmanCngPublicKey.FromByteArray(ClientPublicKey, CngKeyBlobFormat.EccPublicBlob), Enc.NOnce, StreamToEncrypt.ToArray()); EncryptedPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + (1 + ServerPublicKey.Length) + (1 + EncryptedData.Length))); EncryptedPacket.WriteByte((byte)ServerPublicKey.Length); EncryptedPacket.WriteBytes(ServerPublicKey); EncryptedPacket.WriteByte((byte)EncryptedData.Length); EncryptedPacket.WriteBytes(EncryptedData); Client.Send(EncryptedPacket.ToArray()); NetworkFacade.Listener.UpdateClient(Client); Console.WriteLine("Test 1: passed!"); }
public static void HandleChallengeResponse(NetworkClient Client, ProcessedPacket Packet) { Console.WriteLine("Server receives challenge response - test 3"); byte[] CResponse = Packet.ReadBytes(Packet.ReadByte()); if (CResponse.SequenceEqual(ChallengeResponse)) { Console.WriteLine("Received correct challenge response, client was authenticated!"); } string Username = Packet.ReadString(); Console.WriteLine("Username: "******"Test 3: passed!"); }
public static void InitialClientConnect(NetworkClient Client, ProcessedPacket P) { Logger.LogInfo("Received InitialClientConnect!"); PacketStream EncryptedPacket = new PacketStream((byte)PacketType.LOGIN_NOTIFY_CITY, 0); EncryptedPacket.WriteHeader(); AESEncryptor Enc = (AESEncryptor)Client.ClientEncryptor; Enc.PublicKey = P.ReadBytes((P.ReadByte())); Enc.NOnce = P.ReadBytes((P.ReadByte())); Enc.PrivateKey = NetworkFacade.ServerPrivateKey; Client.ClientEncryptor = Enc; MemoryStream StreamToEncrypt = new MemoryStream(); BinaryWriter Writer = new BinaryWriter(StreamToEncrypt); Writer.Write(Enc.Challenge, 0, Enc.Challenge.Length); Writer.Flush(); byte[] EncryptedData = StaticStaticDiffieHellman.Encrypt(NetworkFacade.ServerPrivateKey, System.Security.Cryptography.ECDiffieHellmanCngPublicKey.FromByteArray(Enc.PublicKey, System.Security.Cryptography.CngKeyBlobFormat.EccPublicBlob), Enc.NOnce, StreamToEncrypt.ToArray()); EncryptedPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + (1 + NetworkFacade.ServerPublicKey.Length) + (1 + EncryptedData.Length))); EncryptedPacket.WriteByte((byte)NetworkFacade.ServerPublicKey.Length); EncryptedPacket.WriteBytes(NetworkFacade.ServerPublicKey); EncryptedPacket.WriteByte((byte)EncryptedData.Length); EncryptedPacket.WriteBytes(EncryptedData); Client.Send(EncryptedPacket.ToArray()); }
/// <summary> /// Initial response from server to client. /// </summary> /// <param name="Client">A NetworkClient instance.</param> /// <param name="Packet">A ProcessedPacket instance.</param> public static void HandleServerChallenge(NetworkClient Client, ProcessedPacket Packet) { Console.WriteLine("Client receives encrypted data - test 2"); ServerPublicKey = Packet.ReadBytes(Packet.ReadByte()); byte[] EncryptedData = Packet.ReadBytes(Packet.ReadByte()); AESEncryptor Enc = (AESEncryptor)Client.ClientEncryptor; Enc.PublicKey = ServerPublicKey; Client.ClientEncryptor = Enc; NetworkFacade.Client.ClientEncryptor = Enc; ECDiffieHellmanCng PrivateKey = Client.ClientEncryptor.GetDecryptionArgsContainer().AESDecryptArgs.PrivateKey; byte[] NOnce = Client.ClientEncryptor.GetDecryptionArgsContainer().AESDecryptArgs.NOnce; byte[] ChallengeResponse = StaticStaticDiffieHellman.Decrypt(PrivateKey, ECDiffieHellmanCngPublicKey.FromByteArray(ServerPublicKey, CngKeyBlobFormat.EccPublicBlob), NOnce, EncryptedData); MemoryStream StreamToEncrypt = new MemoryStream(); BinaryWriter Writer = new BinaryWriter(StreamToEncrypt); Writer.Write((byte)ChallengeResponse.Length); Writer.Write(ChallengeResponse, 0, ChallengeResponse.Length); Writer.Write(Client.ClientEncryptor.Username); Writer.Write((byte)PasswordHash.Length); Writer.Write(PasswordHash); Writer.Flush(); Client.SendEncrypted(0x03, StreamToEncrypt.ToArray()); Console.WriteLine("Test 2: passed!"); }
/// <summary> /// Client wanted to log in! /// </summary> public static void HandleLoginRequest(NetworkClient Client, ProcessedPacket P) { try { Logger.LogInfo("Received LoginRequest!\r\n"); byte Version1 = (byte)P.ReadByte(); byte Version2 = (byte)P.ReadByte(); byte Version3 = (byte)P.ReadByte(); byte Version4 = (byte)P.ReadByte(); string ClientVersion = Version1.ToString() + "." + Version2.ToString() + "." + Version3.ToString() + "." + Version4.ToString(); if (ClientVersion != GlobalSettings.Default.ClientVersion) { PacketStream OutPacket = new PacketStream((byte)PacketType.INVALID_VERSION, 2); OutPacket.WriteHeader(); OutPacket.WriteByte(0x01); Client.Send(OutPacket.ToArray()); Logger.LogInfo("Bad version - sent SInvalidVersion!\r\n"); Client.Disconnect(); return; } PacketStream EncryptedPacket = new PacketStream((byte)PacketType.LOGIN_NOTIFY, 0); EncryptedPacket.WriteHeader(); AESEncryptor Enc = (AESEncryptor)Client.ClientEncryptor; if (Enc == null) Enc = new AESEncryptor(""); Enc.PublicKey = P.ReadBytes((P.ReadByte())); Enc.NOnce = P.ReadBytes((P.ReadByte())); Enc.PrivateKey = NetworkFacade.ServerKey; Client.ClientEncryptor = Enc; MemoryStream StreamToEncrypt = new MemoryStream(); BinaryWriter Writer = new BinaryWriter(StreamToEncrypt); Writer.Write(Enc.Challenge, 0, Enc.Challenge.Length); Writer.Flush(); byte[] EncryptedData = StaticStaticDiffieHellman.Encrypt(NetworkFacade.ServerKey, System.Security.Cryptography.ECDiffieHellmanCngPublicKey.FromByteArray(Enc.PublicKey, System.Security.Cryptography.CngKeyBlobFormat.EccPublicBlob), Enc.NOnce, StreamToEncrypt.ToArray()); EncryptedPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + (1 + NetworkFacade.ServerPublicKey.Length) + (1 + EncryptedData.Length))); EncryptedPacket.WriteByte((byte)NetworkFacade.ServerPublicKey.Length); EncryptedPacket.WriteBytes(NetworkFacade.ServerPublicKey); EncryptedPacket.WriteByte((byte)EncryptedData.Length); EncryptedPacket.WriteBytes(EncryptedData); Client.Send(EncryptedPacket.ToArray()); } //This should HOPEFULLY wade off clients sending unreadable (I.E old protocol) packets... catch (Exception E) { Logger.LogDebug("Error while handling login request, disconnecting client: " + E.ToString()); Client.Disconnect(); return; } }
/// <summary> /// Client sent a response to our challenge, as well as account name and password. /// </summary> public static void HandleChallengeResponse(NetworkClient Client, ProcessedPacket P) { PacketStream OutPacket; if (P.BufferLength <= 1) { OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 0); OutPacket.WriteByte(0x03); //Bad challenge response. Client.Send(OutPacket.ToArray()); Logger.LogInfo("Bad challenge response - sent SLoginFailResponse!\r\n"); return; //How does this even happen?! } int Length = P.ReadByte(); byte[] CResponse; if (P.BufferLength >= Length) CResponse = P.ReadBytes(Length); else return; AESDecryptionArgs DecryptionArgs = Client.ClientEncryptor.GetDecryptionArgsContainer().AESDecryptArgs; if (DecryptionArgs.Challenge.SequenceEqual(CResponse)) { string AccountName = SanitizeAccount(P.ReadString()); Length = P.ReadByte(); byte[] PasswordHash; if (P.BufferLength >= Length) PasswordHash = P.ReadBytes(Length); else return; // Check whether the accountname is empty or is/contains "username" if (AccountName == string.Empty || AccountName.ToLower().Equals("username") || AccountName.ToLower().Contains("username")) { OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 0); OutPacket.WriteHeader(); OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1)); OutPacket.WriteByte(0x01); Client.Send(OutPacket.ToArray()); Logger.LogInfo(@"Bad accountname (""" + AccountName + @""") - sent SLoginFailResponse!\r\n"); Client.Disconnect(); return; } using (var db = DataAccess.Get()) { var account = db.Accounts.GetByUsername(AccountName); if (!GlobalSettings.Default.CreateAccountsOnLogin) { Logger.LogInfo("Done reading LoginRequest, checking account...\r\n"); if (account == null) { OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 0); OutPacket.WriteHeader(); OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1)); OutPacket.WriteByte(0x01); Client.Send(OutPacket.ToArray()); Logger.LogInfo(@"Bad accountname (""" + AccountName + @""") - sent SLoginFailResponse!\r\n"); Client.Disconnect(); return; } } else { if (account == null) { try { if (!AccountName.ToLower().Equals("username") || !AccountName.ToLower().Contains("username")) db.Accounts.Create(new Account { AccountName = AccountName.ToLower(), Password = Convert.ToBase64String(PasswordHash) }); } catch (Exception) { OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 0); OutPacket.WriteHeader(); OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1)); OutPacket.WriteByte(0x01); Client.Send(OutPacket.ToArray()); Logger.LogInfo(@"Bad accountname (""" + AccountName + @""") - sent SLoginFailResponse!\r\n"); Client.Disconnect(); return; } account = db.Accounts.GetByUsername(AccountName); } } if (account.IsCorrectPassword(AccountName, PasswordHash)) { OutPacket = new PacketStream((byte)PacketType.LOGIN_SUCCESS, 0); OutPacket.WriteByte(0x01); Client.ClientEncryptor.Username = AccountName; Client.SendEncrypted((byte)PacketType.LOGIN_SUCCESS, OutPacket.ToArray()); Logger.LogInfo("Sent SLoginSuccessResponse!\r\n"); return; } else { OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 0); OutPacket.WriteHeader(); OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1)); OutPacket.WriteByte(0x02); Client.Send(OutPacket.ToArray()); Logger.LogInfo("Bad password - sent SLoginFailResponse!\r\n"); Client.Disconnect(); return; } } } OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 0); OutPacket.WriteHeader(); OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1)); OutPacket.WriteByte(0x03); //Bad challenge response. Client.Send(OutPacket.ToArray()); Logger.LogInfo("Bad challenge response - sent SLoginFailResponse!\r\n"); return; }
public static void HandleChallengeResponse(NetworkClient Client, ProcessedPacket P) { PacketStream OutPacket; if (P.DecryptedSuccessfully) { int Length = P.ReadByte(); byte[] CResponse; if (P.BufferLength >= Length) { CResponse = P.ReadBytes(Length); } else { //Authentication failed, so send this packet unencrypted. OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE_CITY, 0); OutPacket.WriteHeader(); OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1)); OutPacket.WriteByte(0x03); //Bad challenge response. Client.Send(OutPacket.ToArray()); Logger.LogInfo("Sent LOGIN_FAILURE_CITY!"); return; } AESDecryptionArgs DecryptionArgs = Client.ClientEncryptor.GetDecryptionArgsContainer().AESDecryptArgs; if (DecryptionArgs.Challenge.SequenceEqual(CResponse)) { OutPacket = new PacketStream((byte)PacketType.LOGIN_SUCCESS_CITY, 0); OutPacket.WriteByte(0x01); Client.SendEncrypted((byte)PacketType.LOGIN_SUCCESS_CITY, OutPacket.ToArray()); Logger.LogInfo("Sent LOGIN_SUCCESS_CITY!"); } else { //Authentication failed, so send this packet unencrypted. OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE_CITY, 0); OutPacket.WriteHeader(); OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1)); OutPacket.WriteByte(0x03); //Bad challenge response. Client.Send(OutPacket.ToArray()); Logger.LogInfo("Sent LOGIN_FAILURE_CITY!"); } } else { //Authentication failed, so send this packet unencrypted. OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE_CITY, 0); OutPacket.WriteHeader(); OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1)); OutPacket.WriteByte(0x03); //Bad challenge response. Client.Send(OutPacket.ToArray()); Debug.WriteLine("HandleChallengeResponse - decryption failed!"); Logger.LogInfo("Sent LOGIN_FAILURE_CITY!"); } }
/// <summary> /// Received initial packet from CityServer. /// </summary> public static void OnLoginNotifyCity(NetworkClient Client, ProcessedPacket Packet) { LogThis.Log.LogThis("Received OnLoginNotifyCity!", LogThis.eloglevel.info); //Should this be stored for permanent access? byte[] ServerPublicKey = Packet.ReadBytes(Packet.ReadByte()); byte[] EncryptedData = Packet.ReadBytes(Packet.ReadByte()); lock (Client.ClientEncryptor) { AESEncryptor Enc = (AESEncryptor)Client.ClientEncryptor; Enc.PublicKey = ServerPublicKey; Client.ClientEncryptor = Enc; lock (NetworkFacade.Client) NetworkFacade.Client.ClientEncryptor = Enc; } ECDiffieHellmanCng PrivateKey = Client.ClientEncryptor.GetDecryptionArgsContainer().AESDecryptArgs.PrivateKey; byte[] NOnce = Client.ClientEncryptor.GetDecryptionArgsContainer().AESDecryptArgs.NOnce; byte[] ChallengeResponse = StaticStaticDiffieHellman.Decrypt(PrivateKey, ECDiffieHellmanCngPublicKey.FromByteArray(ServerPublicKey, CngKeyBlobFormat.EccPublicBlob), NOnce, EncryptedData); MemoryStream StreamToEncrypt = new MemoryStream(); BinaryWriter Writer = new BinaryWriter(StreamToEncrypt); Writer.Write((byte)ChallengeResponse.Length); Writer.Write(ChallengeResponse, 0, ChallengeResponse.Length); Writer.Flush(); //Encrypt data using key and IV from server, hoping that it'll be decrypted correctly at the other end... Client.SendEncrypted((byte)PacketType.CHALLENGE_RESPONSE, StreamToEncrypt.ToArray()); }