/// <summary> /// This is automatically called when you first access Keys. /// </summary> public static void IndexKeys() { keys.Clear(); if(!Directory.Exists(folderName)) Directory.CreateDirectory(folderName); var files = Directory.GetFiles(folderName, "*.mek"); if(files.Length == 0) { //Generate a new key AES newKey = new AES(Encoding.UTF8); newKey.KeyToFile(folderName+"/EncryptionKey.mek"); File.WriteAllText(folderName+"/EncryptionKey.txt", "There were no keys, so this default key was generated for you. Note this key will be erased the next time nodes are synced and this is NOT the proper way to add client keys."); files = Directory.GetFiles(folderName, "*.mek"); } foreach(var file in files) { using (var md5 = MD5.Create()) { using (var stream = File.OpenRead(file)) { var hash = md5.ComputeHash(stream); keys[hash] = new AES(Encoding.UTF8, file); } } } }
/// <summary> /// Create a new key database in a location. /// </summary> public EncryptionKeyDB(string folderName) { Instance = this; this.folderName = folderName; //Load mek files (matrix encryption keys) if (!Directory.Exists(folderName)) Directory.CreateDirectory(folderName); var files = Directory.GetFiles(this.folderName, "*.mek"); if(files.Length == 0) { //Generate a new key AES newKey = new AES(Encoding.UTF8); newKey.KeyToFile(this.folderName+"/DefaultKey.mek"); File.WriteAllText(this.folderName+"/DefaultKey.txt", "There were no keys, so this default key was generated for you."); files = Directory.GetFiles(this.folderName, "*.mek"); } foreach(var file in files) { using (var md5 = MD5.Create()) { using (var stream = File.OpenRead(file)) { var hash = md5.ComputeHash(stream); keys[hash] = new AES(Encoding.UTF8, file); } } } }
public static void Main(string[] args) { running = true; log4net.Config.XmlConfigurator.Configure(); log.Info("=== Matrix Host Server Launching ==="); log.Debug("Searching for encryption key "+Settings.Default.KeyFile+"..."); if(!File.Exists(Settings.Default.KeyFile)) { log.Error("No encryption key! Exiting..."); Console.ReadLine(); return; } byte[] hash; AES encrypt; //Hash the file to a all lowercase string using (var md5 = MD5.Create()) { using (var stream = File.OpenRead(Settings.Default.KeyFile)) { hash = md5.ComputeHash(stream); encrypt = new AES(Encoding.UTF8, Settings.Default.KeyFile); } } client = new HostClient(Settings.Default.MasterIP, Settings.Default.MasterPort, encrypt, hash); nodeLibraryManager = new NodeLibraryManager("CompiledNodes", client); pool = new NodePool(); client.Startup(); while(running) { Thread.Sleep(50); } client.Shutdown(); if(restart) { restart = false; Main(args); } }
public void Start() { if (started) return; using (var md5 = MD5.Create()) { using (var stream = File.OpenRead("EncryptionKey.mek")) { keyHash = md5.ComputeHash(stream); encryption = new AES(Encoding.UTF8, "EncryptionKey.mek"); } } Task.Factory.StartNew(ClientThread); //ClientThread(); }
public void ProcessMessage(byte[] message) { if (status == ClientStatus.Disconnected) return; //Reset heartbeat heartbeat.Stop(); heartbeat.Start(); if(status > ClientStatus.NoEncryption && message.Length > 1) { //Decrypt message var decrypt = encryption.Decrypt(message.Skip(1).ToArray()); byte[] finalMessage = new byte[1+decrypt.Length]; decrypt.CopyTo(finalMessage,1); finalMessage[0] = message[0]; message = finalMessage; } var data = message.Skip(1).ToArray(); if(message[0] != (byte)MessageIdentifier.Heartbeat) log.Debug("Received message: "+System.Enum.GetName(typeof(MessageIdentifier), message[0])); switch ((MessageIdentifier)message[0]) { case MessageIdentifier.Heartbeat: clientInter.SendTo(clientInfo, BuildMessage(MessageIdentifier.Heartbeat, null)); break; case MessageIdentifier.SetIdentity: if (status != ClientStatus.NoIdentity) { break; } log.Debug("Setting up encryption with new client..."); status = ClientStatus.NoEncryption; //Begin encryption exchange clientInter.SendTo(clientInfo, BuildMessage(MessageIdentifier.BeginEncryption, null)); break; //Coming from client, this is the encryption md5. case MessageIdentifier.BeginEncryption: if (status != ClientStatus.NoEncryption) { log.Error("Unexpected BeginEncryption from host."); break; } //Get the encryption key MD5. byte[] keymd5 = data; AES encrypt = MmoEncrypt.ByHash(keymd5); if (encrypt == null) { log.Info("Key not valid for client, rejecting and disconnecting."); clientInter.SendTo(clientInfo, BuildMessage(MessageIdentifier.InvalidKey, null)); clientInter.Disconnect(clientInfo); status = ClientStatus.Disconnected; } else { log.Debug("Client accepted, beginning login."); status = ClientStatus.LoggingIn; encryption = encrypt; clientInter.SendTo(clientInfo, BuildMessage(MessageIdentifier.ConfirmEncryption, Encoding.UTF8.GetBytes(passwordSalt))); } break; case MessageIdentifier.LoginVerify: if(status != ClientStatus.LoggingIn) { log.Error("Client tried to log in when not in login state."); break; } LoginRequest request = data.Deserialize<LoginRequest>(); log.Debug("Login request, "+request.Username); User user; ISession session = MmoDatabase.Session; using(var transaction = session.BeginTransaction()) { user = session.CreateCriteria(typeof (User)) .Add(Restrictions.Eq("Username", request.Username)) .UniqueResult<User>(); } LoginResponse response; if(user == null) { response = new LoginResponse() {Success = false, Message = "User does not exist."}; }else { string hashedPassword = StringMD5.CreateMD5Hash(StringMD5.CreateMD5Hash(passwordSalt + user.Password)+passwordSalt); if (request.MD5Pass != hashedPassword) { response = new LoginResponse() { Success = false, Message = "Password is incorrect." }; } else { //check if the user is logged in if(controller.IsUserLoggedIn(user.Username)){ log.Error("User '"+user.Username.Truncate(5)+"' is already logged in, rejecting..."); response = new LoginResponse() { Success = false, Message = "User is already logged in!" }; }else{ //Here we should actually be logged in log.Debug("Client logged in, username: "******"CLIENT "+user.Username.Truncate(4)); thisUser = user; status = ClientStatus.CharacterSelect; response = new LoginResponse() {Success = true}; } } } clientInter.SendTo(clientInfo, BuildMessage(MessageIdentifier.LoginVerify, response.Serialize())); break; case MessageIdentifier.CharacterData: if(status != ClientStatus.CharacterSelect){ log.Error("Client tried to retreive characters while not in character select state."); break; } if(thisUser.Characters.Count == 0) { thisUser.Characters.Add(new Character() {Gender = true, Name = "Test Character"+(new Random().Next(0,100)), User = thisUser, XP = 5000, CurrentRealm = MmoWorld.Realms.First()}); MmoDatabase.Save(thisUser); } CharacterData[] characters = new CharacterData[thisUser.Characters.Count]; int i = 0; foreach(var character in thisUser.Characters) { if (character.CurrentRealm == null) { character.CurrentRealm = MmoWorld.Realms.First(); MmoDatabase.Save(character); } characters[i] = new CharacterData(){Id = character.Id, Name = character.Name, XP = character.XP, Gender=character.Gender, Realm = character.CurrentRealm.Name}; i++; } clientInter.SendTo(clientInfo, BuildMessage(MessageIdentifier.CharacterData, characters.Serialize())); break; case MessageIdentifier.CharacterVerify: if(status != ClientStatus.CharacterSelect){ log.Error("Client tried to select a character while not in character select state."); break; } int characterId = BitConverter.ToInt32(data, 0); Character selChar = thisUser.Characters.SingleOrDefault(x=>x.Id == characterId); clientInter.SendTo(clientInfo, BuildMessage(MessageIdentifier.CharacterVerify, BitConverter.GetBytes(selChar != null))); if(selChar != null){ //todo: do something after logging in and selecting character } selectedCharacter = selChar; break; case MessageIdentifier.Disconnect: DisconnectClient(); break; } }
/// <summary> /// Process a message for response. /// </summary> /// <param name="inter">Interface.</param> /// <param name="message">Received message.</param> public void ProcessMessage(HostInterface inter, byte[] message) { lastInter = inter; if (status == HostStatus.Disconnected) return; //Reset heartbeat heartbeat.Stop (); heartbeat.Start (); if (status > HostStatus.NoEncryption && message.Length > 1) { //Decrypt message var decrypt = encryption.Decrypt (message.Skip (1).ToArray ()); byte[] finalMessage = new byte[1 + decrypt.Length]; decrypt.CopyTo (finalMessage, 1); finalMessage [0] = message [0]; message = finalMessage; } if (message [0] != (byte)MessageIdentifier.Heartbeat) log.Debug ("Received message: " + Enum.GetName (typeof(MessageIdentifier), message [0])); switch ((MessageIdentifier)message [0]) { case MessageIdentifier.Heartbeat: inter.SendTo (hostInfo, BuildMessage (MessageIdentifier.Heartbeat, null)); break; //Coming from client, this is confirming an identity. case MessageIdentifier.SetIdentity: if (status != HostStatus.NoIdentity) { log.Debug ("Host already has registered."); break; } log.Debug ("Identity confirmed, beginning encryption sequence."); status = HostStatus.NoEncryption; //Begin encryption exchange inter.SendTo (hostInfo, BuildMessage (MessageIdentifier.BeginEncryption, null)); break; //Coming from client, this is the encryption md5. case MessageIdentifier.BeginEncryption: if (status != HostStatus.NoEncryption) { log.Error ("Unexpected BeginEncryption from host."); break; } //Get the encryption key MD5. byte[] keymd5 = message.Skip (1).ToArray (); log.Debug ("Encryption key confirmation request: " + BitConverter.ToString (keymd5).Replace ("-", "").ToLower ()); AES encrypt = EncryptionKeyDB.Instance.ByHash (keymd5); if (encrypt == null) { log.Info ("Key not valid for host, rejecting and disconnecting."); inter.SendTo (hostInfo, BuildMessage (MessageIdentifier.InvalidKey, null)); inter.DisconnectHost (hostInfo); status = HostStatus.Disconnected; } else { log.Debug ("Host accepted, beginning node sync."); status = HostStatus.SyncNodes; inter.SendTo (hostInfo, BuildMessage (MessageIdentifier.ConfirmEncryption, null)); encryption = encrypt; } break; case MessageIdentifier.NodeSync: var inputIndex = Serializer.Deserialize<Dictionary<string, byte[]>> (new MemoryStream (message.Skip (1).ToArray ())); var syncJob = NodeLibraryManager.Instance.CreateSyncJob (inputIndex); if (syncJob == null) { inter.SendTo (hostInfo, BuildMessage (MessageIdentifier.BeginOperation, null)); status = HostStatus.LoadingNodes; } else { byte[] serializedJob; using (var ms = new MemoryStream ()) { Serializer.Serialize (ms, syncJob); serializedJob = ms.ToArray (); status = HostStatus.SyncNodes; } inter.SendTo (hostInfo, BuildMessage (MessageIdentifier.NodeSync, serializedJob)); } break; case MessageIdentifier.GetLibraryURL: //Retreive the library url for the path string dataString = Encoding.Unicode.GetString (message, 1, message.Length - 1); int reqId = int.Parse (dataString.Split (':') [0]); string library = dataString.Split (':') [1]; var libraryUrl = Encoding.UTF8.GetBytes (reqId + ":" + NodeHost.Instance.GetDownloadUrl (library)); inter.SendTo (hostInfo, BuildMessage (MessageIdentifier.GetLibraryURL, libraryUrl)); break; case MessageIdentifier.BeginOperation: if (status == HostStatus.LoadingNodes) { status = HostStatus.Operating; log.Info ("New host ready for operation."); try { Task.Factory.StartNew (() => inter.Controller.OnHostAdded (hostInfo)); } catch (Exception ex) { log.Error ("Error not caught by Controller, " + ex.ToString ()); } } break; case MessageIdentifier.NodeVerify: int verId = BitConverter.ToInt32 (message, 1); NodeInfo info; using (MemoryStream ms = new MemoryStream ()) { var inputBytes = message.Skip (1 + sizeof(int)).ToArray (); ms.Write (inputBytes, 0, inputBytes.Length); ms.Position = 0; info = Serializer.Deserialize<NodeInfo> (ms); } var response = NodePool.Instance.CheckNodeExists (info); var respBytes = new byte[sizeof(int) + sizeof(bool)]; BitConverter.GetBytes (verId).CopyTo (respBytes, 0); BitConverter.GetBytes (response).CopyTo (respBytes, sizeof(int)); inter.SendTo (hostInfo, BuildMessage (MessageIdentifier.NodeVerify, respBytes)); break; case MessageIdentifier.RMIResponse: if (status != HostStatus.Operating) return; var data = message.Skip (1).ToArray (); var rmi = data.Deserialize<NodeRMI> (); var destoNode = NodePool.Instance.NodeForId (rmi.SNodeID); if (destoNode == null) return; if (destoNode.Id == 0) NodePool.Instance.HandleRMIResponse (rmi); else { lastInter.RouteRMIResponse (rmi); } break; case MessageIdentifier.ReqNodeList: if (status != HostStatus.Operating) return; SendEntireNodeList (); break; case MessageIdentifier.RMIInvoke: if (status != HostStatus.Operating) return; NodeRMI trmi = message.Skip (1).ToArray ().Deserialize<NodeRMI> (); var tdestoNode = NodePool.Instance.NodeForId (trmi.NodeID); if (tdestoNode == null) { trmi.SerializeReturnValue (new NodeNotExistException ()); lastInter.SendTo (hostInfo, BuildMessage (MessageIdentifier.RMIResponse, trmi.Serialize ())); break; } lastInter.RouteRMIRequest (trmi, tdestoNode); break; } }