/// <summary> /// Determines whether or not to accept the connection based on whether a user's username is recognised, and constructs a ProtoLogIn containing session salt /// </summary> /// <param name="client">Client who is connecting</param> /// <param name="text">Challenge text from which to create a signature</param> /// <param name="response">Response message</param> /// <returns>Boolean indicating whether connection was accepted</returns> public static bool AcceptConnection(Client client, string text, out ProtoLogIn response) { Contract.Requires(client != null); byte[] sessionSalt = GetRandomSalt(32); byte[] userSalt = GetUserSalt(client.username); if (userSalt == null) { response = null; return(false); } response = new ProtoLogIn { sessionSalt = sessionSalt }; if (!sessionSalts.ContainsKey(client.username)) { sessionSalts.Add(client.username, sessionSalt); } else { sessionSalts[client.username] = sessionSalt; } response.userSalt = userSalt; response.ActionType = Actions.LogIn; if (ServerCert != null) { response.certificate = ServerCert.GetRawCertData(); } response.Signature = Sign(text); return(true); }
public void SendDummyLogIn(string user, string pass, byte[] key = null) { ProtoLogIn logIn = new ProtoLogIn(); logIn.ActionType = Actions.LogIn; logIn.Key = key; net.Send(logIn); }
/// <summary> /// Take a client's log in details, verify them and then choose to either allow the user to log in, or disconnect /// </summary> /// <param name="login">Log in details</param> /// <param name="c">Client who is logging in</param> /// <returns>Boolean indicating whether log in was successful</returns> public static bool ProcessLogIn(ProtoLogIn login, Client c) { Contract.Requires(c != null && login != null); if (!VerifyUser(c.username, login.userSalt)) { return(false); } try { if (login.Key != null) { byte[] key = rsa.Decrypt(login.Key, false); // Key must be non-null and long enough if (key == null || key.Length < 5) { return(false); } c.alg = new NetAESEncryption(Globals_Server.server, key, 0, key.Length); } else { #if ALLOW_UNENCRYPT c.alg = null; #else return(false); #endif } ProtoClient clientDetails = new ProtoClient(c); clientDetails.ActionType = Actions.LogIn; clientDetails.ResponseType = DisplayMessages.LogInSuccess; Server.SendViaProto(clientDetails, c.conn, c.alg); Globals_Game.RegisterObserver(c); return(true); } catch (Exception e) { #if DEBUG Console.WriteLine("Failure during decryption: " + e.GetType() + " " + e.Message + ";" + e.StackTrace); #endif return(false); } }
public void ComputeAndSendHashAndKey(ProtoLogIn salts, byte[] key) { string hashstring = ""; foreach (byte b in salts.userSalt) { hashstring += b.ToString(); } string sessSalt = ""; foreach (byte b in salts.sessionSalt) { sessSalt += b.ToString(); } byte[] passBytes = Encoding.UTF8.GetBytes(pass); byte[] hashPassword = ComputeHash(passBytes, salts.userSalt); string passHash = ""; foreach (byte b in hashPassword) { passHash += b.ToString(); } byte[] hashFull = ComputeHash(hashPassword, salts.sessionSalt); string fullHash = ""; foreach (byte b in hashFull) { fullHash += b.ToString(); } var response = new ProtoLogIn { userSalt = hashFull, ActionType = Actions.LogIn, Key = key }; Send(response, false); }
public bool ValidateCertificateAndCreateKey(ProtoLogIn login, out byte[] key) { if (login == null || login.certificate == null) { key = null; return(false); } else { try { // Get certificate X509Certificate2 cert = new X509Certificate2(login.certificate); RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PublicKey.Key; #if DEBUG if (this.key != null) { if (this.key.Length == 0) { alg = new NetAESEncryption(client); } else { alg = new NetAESEncryption(client, this.key, 0, this.key.Length); } key = rsa.Encrypt(this.key, false); } else { // If no key, do not use an encryption algorithm alg = null; key = null; } #else // Create a new symmetric key TripleDES des = TripleDESCryptoServiceProvider.Create(); des.GenerateKey(); // Encrypt key with server's public key this.key = des.Key; key = rsa.Encrypt(des.Key, false); // Initialise the algoitm alg = new NetAESEncryption(client, des.Key, 0, des.Key.Length); Console.WriteLine("CLIENT: my unencrypted key:"); foreach (var bite in des.Key) { Console.Write(bite.ToString()); } #endif // Validate certificate if (!cert.Verify()) { X509Chain CertificateChain = new X509Chain(); //If you do not provide revokation information, use the following line. CertificateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; bool IsCertificateChainValid = CertificateChain.Build(cert); if (!IsCertificateChainValid) { for (int i = 0; i < CertificateChain.ChainStatus.Length; i++) { } // TODO change to false after testing return(true); } } // temporary certificate validation fix return(true); //return cert.Verify(); } catch (Exception e) { Console.Error.WriteLine("A problem occurred when parsing certificate from bytes: \n" + "type: " + e.GetType().FullName + "\n " + ", source: " + e.Source + "\n message: " + e.Message); key = null; return(false); } } }
public void Listen() { while (server.Status == NetPeerStatus.Running && !ctSource.Token.IsCancellationRequested) { NetIncomingMessage im; WaitHandle.WaitAny(new WaitHandle[] { server.MessageReceivedEvent, ctSource.Token.WaitHandle }); while ((im = server.ReadMessage()) != null && !ctSource.Token.IsCancellationRequested) { switch (im.MessageType) { case NetIncomingMessageType.DebugMessage: case NetIncomingMessageType.ErrorMessage: case NetIncomingMessageType.WarningMessage: Globals_Server.logError("Recieved warning message: " + im.ReadString()); break; case NetIncomingMessageType.VerboseDebugMessage: case NetIncomingMessageType.Data: { #if DEBUG Console.WriteLine("SERVER: recieved data message"); #endif if (!clientConnections.ContainsKey(im.SenderConnection)) { //error im.SenderConnection.Disconnect("Not recognised"); return; } Client c = clientConnections[im.SenderConnection]; if (c.alg != null) { im.Decrypt(c.alg); } ProtoMessage m = null; //global::ProtoMessage.ProtoMessage y = null; using (MemoryStream ms = new MemoryStream(im.Data)) { try { //y = Serializer.DeserializeWithLengthPrefix<global::ProtoMessage.ProtoMessage>(ms, //PrefixStyle.Fixed32); m = Serializer.DeserializeWithLengthPrefix <ProtoMessage>(ms, PrefixStyle.Fixed32); } catch (Exception e) { NetOutgoingMessage errorMessage = server.CreateMessage( "Failed to deserialise message. The message may be incorrect, or the decryption may have failed."); if (c.alg != null) { errorMessage.Encrypt(c.alg); } server.SendMessage(errorMessage, im.SenderConnection, NetDeliveryMethod.ReliableOrdered); Globals_Server.logError("Failed to deserialize message for client: " + c.username); } } if (m == null /*&& y == null*/) { string error = "Recieved null message from " + im.SenderEndPoint.ToString(); if (clientConnections.ContainsKey(im.SenderConnection)) { error += ", recognised client " + clientConnections[im.SenderConnection]; } else { error += ", unrecognised client (possible ping)"; } error += ". Data: " + im.ReadString(); Globals_Server.logError(error); break; } if (m.ActionType == Actions.LogIn) { ProtoLogIn login = m as ProtoLogIn; if (login == null) { im.SenderConnection.Disconnect("Not login"); return; } lock (ServerLock) { if (LogInManager.VerifyUser(c.username, login.userSalt)) { if (LogInManager.ProcessLogIn(login, c)) { string log = c.username + " logs in from " + im.SenderEndPoint.ToString(); Globals_Server.logEvent(log); } } else { ProtoMessage reply = new ProtoMessage { ActionType = Actions.LogIn, ResponseType = DisplayMessages.LogInFail }; im.SenderConnection.Disconnect("Authentication Fail"); } } } // temp for testing, should validate connection first else if (clientConnections.ContainsKey(im.SenderConnection)) { if (Globals_Game.IsObserver(c)) { ProcessMessage(m, im.SenderConnection); ProtoClient clientDetails = new ProtoClient(c); clientDetails.ActionType = Actions.Update; SendViaProto(clientDetails, im.SenderConnection, c.alg); } else { im.SenderConnection.Disconnect("Not logged in- Disconnecting"); } } /*//IF Y ACTION * if (y.ActionType == global::ProtoMessage.Actions.LogIn) * { * global::ProtoMessage.Client forCheck = new global::ProtoMessage.Client(c.username, c.myPlayerCharacter.playerID); * global::ProtoMessage.ProtoLogIn login = y as global::ProtoMessage.ProtoLogIn; * if (login == null) * { * im.SenderConnection.Disconnect("Not login"); * return; * } * lock (ServerLock) * { * if (LogInManager.VerifyUser(c.username, login.userSalt)) * { * if (LogInManager.ProcessLogIn(login, forCheck, true)) * { * string log = c.username + " logs in from " + im.SenderEndPoint.ToString(); * Globals_Server.logEvent(log); * } * } * else * { * ProtoMessage reply = new ProtoMessage * { * ActionType = Actions.LogIn, * ResponseType = DisplayMessages.LogInFail * }; * im.SenderConnection.Disconnect("Authentication Fail"); * } * } * } * // temp for testing, should validate connection first * else if (clientConnections.ContainsKey(im.SenderConnection)) * { * if (Globals_Game.IsObserver(c)) * { * ProcessMessage(y, im.SenderConnection); * ProtoClient clientDetails = new ProtoClient(c); * clientDetails.ActionType = Actions.Update; * SendViaProto(clientDetails, im.SenderConnection, c.alg); * } * else * { * im.SenderConnection.Disconnect("Not logged in- Disconnecting"); * } * }*/ } break; case NetIncomingMessageType.StatusChanged: byte stat = im.ReadByte(); NetConnectionStatus status = NetConnectionStatus.None; if (Enum.IsDefined(typeof(NetConnectionStatus), Convert.ToInt32(stat))) { status = (NetConnectionStatus)stat; } else { Globals_Server.logError("Failure to parse byte " + stat + " to NetConnectionStatus for endpoint " + im.ReadIPEndPoint()); } if (status == NetConnectionStatus.Disconnected) { if (clientConnections.ContainsKey(im.SenderConnection)) { Disconnect(im.SenderConnection); } } break; case NetIncomingMessageType.ConnectionApproval: { string senderID = im.ReadString(); string text = im.ReadString(); Client client; Globals_Server.Clients.TryGetValue(senderID, out client); if (client != null) { ProtoLogIn logIn; if (!LogInManager.AcceptConnection(client, text, out logIn)) { im.SenderConnection.Deny(); } else { NetOutgoingMessage msg = server.CreateMessage(); MemoryStream ms = new MemoryStream(); // Include X509 certificate as bytes for client to validate Serializer.SerializeWithLengthPrefix <ProtoLogIn>(ms, logIn, PrefixStyle.Fixed32); msg.Write(ms.GetBuffer()); clientConnections.Add(im.SenderConnection, client); client.conn = im.SenderConnection; im.SenderConnection.Approve(msg); server.FlushSendQueue(); Globals_Server.logEvent("Accepted connection from " + client.username); } } else { im.SenderConnection.Deny("unrecognised"); } } break; case NetIncomingMessageType.ConnectionLatencyUpdated: break; default: Globals_Server.logError("Received unrecognised incoming message type: " + im.MessageType); break; } server.Recycle(im); } } #if DEBUG Globals_Server.logEvent("Server listening thread exits"); #endif }
public void Listen() { while (server.Status == NetPeerStatus.Running && !ctSource.Token.IsCancellationRequested) { NetIncomingMessage im; WaitHandle.WaitAny(new WaitHandle[] { server.MessageReceivedEvent, ctSource.Token.WaitHandle }); while ((im = server.ReadMessage()) != null && !ctSource.Token.IsCancellationRequested) { if (im.SenderConnection != null) { Globals_Server.logEvent("Recieved: " + im.MessageType.ToString() + " | " + im.SenderConnection.RemoteEndPoint.ToString()); } else { Globals_Server.logEvent("Recieved: " + im.MessageType.ToString() + " | NULL"); } switch (im.MessageType) { case NetIncomingMessageType.DebugMessage: case NetIncomingMessageType.ErrorMessage: case NetIncomingMessageType.WarningMessage: Globals_Server.logError("Recieved warning message: " + im.ReadString()); break; case NetIncomingMessageType.VerboseDebugMessage: case NetIncomingMessageType.Data: { #if DEBUG //Console.WriteLine("SERVER: recieved data message"); #endif if (!clientConnections.ContainsKey(im.SenderConnection)) { //error im.SenderConnection.Disconnect("Not recognised"); return; } Client c = clientConnections[im.SenderConnection]; if (c.alg != null) { im.Decrypt(c.alg); } ProtoMessage m = null; using (MemoryStream ms = new MemoryStream(im.Data)) { try { m = Serializer.DeserializeWithLengthPrefix <ProtoMessage>(ms, PrefixStyle.Fixed32); } catch (Exception e) { NetOutgoingMessage errorMessage = server.CreateMessage( "Failed to deserialise message. The message may be incorrect, or the decryption may have failed."); if (c.alg != null) { errorMessage.Encrypt(c.alg); } server.SendMessage(errorMessage, im.SenderConnection, NetDeliveryMethod.ReliableOrdered); Globals_Server.logError("Failed to deserialize message for client: " + c.username); } } if (m == null) { string error = "Recieved null message from " + im.SenderEndPoint.ToString(); if (clientConnections.ContainsKey(im.SenderConnection)) { error += ", recognised client " + clientConnections[im.SenderConnection]; } else { error += ", unrecognised client (possible ping)"; } error += ". Data: " + im.ReadString(); Globals_Server.logError(error); break; } if (m.ActionType == Actions.LogIn) { ProtoLogIn login = m as ProtoLogIn; if (login == null) { im.SenderConnection.Disconnect("Received blank login message."); return; } lock (ServerLock) { if (LogInManager.VerifyUser(c.username, login.userSalt)) { if (LogInManager.ProcessLogIn(login, c)) { string log = c.username + " logs in from " + im.SenderEndPoint.ToString(); Globals_Server.logEvent(log); } } else { ProtoMessage reply = new ProtoMessage { ActionType = Actions.LogIn, ResponseType = DisplayMessages.LogInFail }; Server.SendViaProto(reply, c.conn, c.alg); //reply = new ProtoMessage { // ActionType = Actions.Update, // ResponseType = DisplayMessages.Error //}; //Server.SendViaProto(reply, c.conn, c.alg); im.SenderConnection.Disconnect("Authentication Fail"); Globals_Server.logEvent("Wrong Password, disconnecting user."); } } } // temp for testing, should validate connection first else if (clientConnections.ContainsKey(im.SenderConnection)) { if (Globals_Game.IsObserver(c)) { ProcessMessage(m, im.SenderConnection); ProtoClient clientDetails = new ProtoClient(c); clientDetails.ActionType = Actions.Update; clientDetails.ResponseType = DisplayMessages.Success; SendViaProto(clientDetails, im.SenderConnection, c.alg); } else { im.SenderConnection.Disconnect("Not logged in- Disconnecting"); } } } break; case NetIncomingMessageType.StatusChanged: byte stat = im.ReadByte(); NetConnectionStatus status = NetConnectionStatus.None; if (Enum.IsDefined(typeof(NetConnectionStatus), Convert.ToInt32(stat))) { status = (NetConnectionStatus)stat; } else { Globals_Server.logError("Failure to parse byte " + stat + " to NetConnectionStatus for endpoint " + im.ReadIPEndPoint()); } Globals_Server.logEvent("\tStatus is now: " + status); if (status == NetConnectionStatus.Disconnected) { string reason = im.ReadString(); if (reason == null) { reason = "Unknown"; } Globals_Server.logEvent(im.SenderConnection.RemoteEndPoint.ToString() + " has disconnected. Reason: " + reason); if (clientConnections.ContainsKey(im.SenderConnection)) { Disconnect(im.SenderConnection); } } break; case NetIncomingMessageType.ConnectionApproval: { string senderID = im.ReadString(); string text = im.ReadString(); Client client; Globals_Server.Clients.TryGetValue(senderID, out client); if (client != null) { ProtoLogIn logIn; //ProtoMessage logIn; if (!LogInManager.AcceptConnection(client, text, out logIn)) { im.SenderConnection.Deny("User not recognised."); } else { ProtoMessage temp = logIn; NetOutgoingMessage msg = server.CreateMessage(); MemoryStream ms = new MemoryStream(); // Include X509 certificate as bytes for client to validate //Serializer.SerializeWithLengthPrefix<ProtoLogIn>(ms, logIn, PrefixStyle.Fixed32); Serializer.SerializeWithLengthPrefix <ProtoMessage>(ms, temp, PrefixStyle.Fixed32); msg.Write(ms.GetBuffer()); clientConnections.Add(im.SenderConnection, client); client.conn = im.SenderConnection; im.SenderConnection.Approve(msg); //server.FlushSendQueue(); Globals_Server.logEvent("Accepted connection from " + client.username + " | " + senderID + " | " + text); } } else { im.SenderConnection.Deny("Username unrecognised."); } server.FlushSendQueue(); } break; case NetIncomingMessageType.ConnectionLatencyUpdated: Globals_Server.logEvent("LATENCY: Still getting these."); break; default: Globals_Server.logError("Received unrecognised incoming message type: " + im.MessageType); break; } server.Recycle(im); } } Globals_Server.logEvent("Server listening thread exits."); }