public void TrustContact(int contactId) { Pull(); Log("Sending TRUST_CONTACT command."); TextEncoder.SendCommand(stream, ConnectionCommand.TRUST_CONTACT); TextEncoder.SendInt(stream, contactId); using (Context context = new Context(config)) { var contact = context.Contacts .Where(u => u.PublicId == contactId) .SingleOrDefault(); contact.Trusted = 1; context.SaveChanges(); if (contact.SendAesKey == null) { AESPassword password = AESPassword.GenerateAESPassword(); JAESKey key = new JAESKey(contactId, password); PushOperations.SendIJType(context, key, UserId, UserId); X509Certificate2 cert = X509Certificate2Utils.ImportFromPem( context.Contacts .Where(u => u.PublicId == contactId) .Select(u => u.PublicCertificate) .SingleOrDefault()); BinaryEncoder.SendBytes(stream, RSAEncoder.Encrypt(password.Password, cert)); context.SaveChanges(); } } Push(); }
public bool AppCertificateValidation(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { if (sslPolicyErrors.Equals(SslPolicyErrors.RemoteCertificateNotAvailable)) { logger.Log(this, "Remote certificate not available.", true); return(false); } if (!X509Certificate2Utils.ExportToPem(certificate).Equals(acceptedPublicKey)) { logger.Log(this, $"Remote certificate has other public key.\n{X509Certificate2Utils.ExportToPem(certificate)}", true); return(false); } return(true); }
private async void LoadFromFile() { IsLoadingFile = true; try { var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Storage); if (status != PermissionStatus.Granted) { if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Permission.Storage)) { await DisplayAlert("Need access storage", "It is nessecary for certificate loading.", "OK"); } var results = await CrossPermissions.Current.RequestPermissionsAsync(Permission.Storage); status = results[Permission.Storage]; } if (status == PermissionStatus.Denied) { await DisplayAlert("Error", "Storage permission is not granted.", "OK"); IsLoadingFile = false; return; } FileData fileData = await CrossFilePicker.Current.PickFile(); if (fileData == null) { IsLoadingFile = false; return; } X509Certificate2 cert = X509Certificate2Utils.ImportFromPkcs12(fileData.DataArray, true); app.AfterCertificateSelected(cert); } catch (Exception ex) { logger.LogException(this, ex); await DisplayAlert("Error", "Certificate loading failed.", "OK"); IsLoadingFile = false; } }
private async void exportButton_Pressed(object sender, EventArgs e) { var answer = await DisplayAlert("Export", "Do you really want to export your certificate to your documents?", "Yes", "No"); if (answer) { try { app.saveFile(X509Certificate2Utils.ExportToPkcs12(app.settings.ClientCertificate), "chatovatkoCert.p12"); } catch (Exception ex) { ShowError(ex); } } }
public static void Register(out Connection connection, out SettingsCapsula settings, Logger logger, Action <String> log, String serverAddress, X509Certificate2 clientCert, IClientDatabaseConfig config, String userName, SettingsLoader settingsLoader, ServerInfo info) { IConnectionVerificator verificator = new ConnectionVerificator(logger, info.PublicCertificate); connection = new Connection(logger, verificator, serverAddress, clientCert, config, userName); connection.Connect(); log("Saving settings."); settingsLoader.Create(clientCert, connection.UserId, connection.UserName, info.Name, serverAddress, info.PublicCertificate, (int)connection.ClientId); settings = settingsLoader.GetSettingsCapsula(); log("Saving the self AES key."); //The only user outside of the chain using (Context context = new Context(config)) { context.Contacts.Add(new Contacts() { PublicId = connection.UserId, UserName = connection.UserName, AlarmPermission = 1, BlobMessagesId = null, NickName = null, Trusted = 1, ReceiveAesKey = connection.SelfAesPassword?.Password, SendAesKey = connection.SelfAesPassword?.Password, PublicCertificate = X509Certificate2Utils.ExportToPem(clientCert) }); context.SaveChanges(); } log("Self-trustification begin."); connection.TrustContact(connection.UserId); log("Self-trustification done."); log("Updating."); connection.Pull(); connection.Push(); log("Updating done."); }
static void Main(string[] args) { Console.WriteLine("Chatovatko at your service!"); Logger logger = new Logger(new ConsoleLoggerOutput()); try { ServerConfig config = new ServerConfig(logger); if (args.Length == 0) { config.LoadConfig(); } else { config.LoadConfig(args[0]); } X509Certificate2 certificate = X509Certificate2Utils.ImportFromPkcs12File(config.CertAddress); logger.LoggerOutputs.Add(new DatabaseLoggerOutput(config)); logger.Log("Program", "Core", "First phase of booting up ended", false); InfoService infoService = new InfoService(logger, config, certificate); infoService.RunInBackground(); GodotFountain godotFountain = new GodotFountain(logger, config, certificate); godotFountain.Run(); } catch (Exception ex) { logger.LogException(ex, "Program", "Core", "Program has crashed."); } finally { logger.Close(); Console.ReadLine(); System.Environment.Exit(1); } }
public static HandshakeReturnCapsula Login(Logger logger, Stream stream, X509Certificate2 cert, string password, string userName = null, int?clientId = null) { ClientHandshake clientHandshake = new ClientHandshake() { PemCertificate = X509Certificate2Utils.ExportToPem(cert), UserName = userName, ClientId = clientId, ServerPassword = password }; if (userName != null && userName.Length > DataConstants.USER_NAME_MAX_LENGHT) { throw new Exception("Username is too long."); } TextEncoder.SendJson(stream, clientHandshake); byte[] encrypted = BinaryEncoder.ReceiveBytes(stream); byte[] decrypted = RSAEncoder.Decrypt(encrypted, cert); BinaryEncoder.SendBytes(stream, decrypted); ServerHandshake serverHandshake = TextEncoder.ReadJson <ServerHandshake>(stream); logger.Log("Handshake", "Handshake", serverHandshake.Errors, false); if (!serverHandshake.Succeeded) { throw new Exception($"Handshake failed\n{serverHandshake.Errors}"); } return(new HandshakeReturnCapsula() { UserId = serverHandshake.UserId, UserName = serverHandshake.UserName, ClientId = serverHandshake.ClientId, SelfAesPassword = serverHandshake.SelfAesKey == null ? null : new AESPassword(RSAEncoder.DecryptAndVerify(serverHandshake.SelfAesKey, cert, cert)) }); }
public void Create(X509Certificate2 clientCert, int userId, String userName, String serverName, String serverAddress, String serverPublicKey, long clientId) { if (Exists()) { throw new Exception("Settings already exists"); } Settings settings = new Settings() { UserPublicId = userId, PrivateCertificate = X509Certificate2Utils.ExportToBase64(clientCert), ServerAddress = serverAddress, ServerName = serverName, ServerPublicCertificate = serverPublicKey, UserName = userName, ClientId = clientId, LastUniqueId = clientId << 26 }; using (Context context = new Context(config)) { context.Settings.Add(settings); context.SaveChanges(); } }
public ServerInfo GetServerInfo() { String publicKey = X509Certificate2Utils.ExportToPem(cert); return(new ServerInfo(config.ServerName, publicKey, config.Password != null)); }
public static ConnectionInfo Run(Stream stream, Action <string> log, ServerConfig config) { ClientHandshake clientHandshake = TextEncoder.ReadJson <ClientHandshake>(stream); X509Certificate2 clientCertificate = X509Certificate2Utils.ImportFromPem(clientHandshake.PemCertificate); log($"Logging user sent username {clientHandshake.UserName}\n Certificate:\n {clientHandshake.PemCertificate}"); ServerHandshake errorHandshake = new ServerHandshake() { Errors = "", NewUser = false, Succeeded = false, UserId = -1, UserName = "" }; if (config.Password != null && !config.Password.Equals(clientHandshake.ServerPassword)) { errorHandshake.Errors = "Server password is wrong."; TextEncoder.SendJson(stream, errorHandshake); throw new Exception(errorHandshake.Errors); } log("Generating random bytes"); byte[] randomBytes = LUtils.GenerateRandomBytes(TcpConstants.HANDSHAKE_LENGHT); log("Sending encrypted bytes"); BinaryEncoder.SendBytes(stream, RSAEncoder.Encrypt(randomBytes, clientCertificate)); byte[] received = BinaryEncoder.ReceiveBytes(stream); if (!randomBytes.SequenceEqual(received)) { log("Client's certificate verification failed."); errorHandshake.Errors = "Client's certificate verification failed."; TextEncoder.SendJson(stream, errorHandshake); throw new Exception(errorHandshake.Errors); } log("Certificate verification succeeded."); Users user; String message; Clients client; byte[] aesKey = null; bool newUser = false; using (Context context = new Context(config)) { byte[] hash = SHA256Utils.ComputeByteSha256Hash(clientCertificate); user = context.Users.SingleOrDefault(u => u.PublicCertificateSha256.SequenceEqual(hash)); if (user == null) { log("User doesn't exist yet. I'll try to create him."); newUser = true; log("Checking the uniquity of username."); String userName = clientHandshake.UserName; if (context.Users.SingleOrDefault(u => u.UserName.Equals(userName)) != null) { errorHandshake.Errors = "Username isn't unique."; TextEncoder.SendJson(stream, errorHandshake); throw new Exception(errorHandshake.Errors); } else if (userName.Length > 45) { errorHandshake.Errors = "Username is too long (max. 45 chars)"; TextEncoder.SendJson(stream, errorHandshake); throw new Exception(errorHandshake.Errors); } else if (userName.Length < 4) { errorHandshake.Errors = "Username is too short (min. 4 chars)"; TextEncoder.SendJson(stream, errorHandshake); throw new Exception(errorHandshake.Errors); } else if (!Validators.ValidateRegexUserName(userName)) { errorHandshake.Errors = "Username must match this regex ^[a-zA-Z][-a-zA-Z0-9_]+$ (Vaguely can't contain special chars and spaces)"; TextEncoder.SendJson(stream, errorHandshake); throw new Exception(errorHandshake.Errors); } log("Creating user."); user = new Users() { PublicCertificate = clientHandshake.PemCertificate, PublicCertificateSha256 = hash, UserName = clientHandshake.UserName }; context.Users.Add(user); context.SaveChanges(); message = "User successfully created."; log("User successfully created."); } else { message = "User exists."; log("User exists."); } client = new Clients() { UserId = user.Id }; if (clientHandshake.ClientId == null) { log($"Loading self-aes key."); aesKey = context.UsersKeys .Where(u => u.RecepientId == user.Id) .Where(u => u.SenderId == user.Id) .Select(u => u.AesKey) .SingleOrDefault(); context.Add(client); context.SaveChanges(); log($"Added client with Id {client.Id}."); } else { client.Id = (int)clientHandshake.ClientId; if (context.Clients.Where(u => u.Id == client.Id).Single().UserId != user.Id) { errorHandshake.Errors = "This client id isn't owned by this user."; TextEncoder.SendJson(stream, errorHandshake); throw new Exception(errorHandshake.Errors); } log($"Client with Id {client.Id} has logged in."); } } ServerHandshake toSend = new ServerHandshake() { Errors = message, NewUser = newUser, Succeeded = true, UserId = user.Id, UserName = user.UserName, ClientId = client.Id, SelfAesKey = aesKey }; TextEncoder.SendJson(stream, toSend); ConnectionInfo ret = new ConnectionInfo(user, clientCertificate, client.Id); log($"Handshake successeded. User {ret.UserName} with id {ret.UserId} has logged in. Client has id {client.Id}."); return(ret); }
public void TrustContact(int contactId) { ThrowExceptionIfNotConnected(); Pull(); lock (mutex) { Log("Sending TRUST_CONTACT command."); BinaryEncoder.SendCommand(stream, ConnectionCommand.TRUST_CONTACT); BinaryEncoder.SendInt(stream, contactId); using (Context context = new Context(config)) { var contact = new UContact(context.Contacts .Where(u => u.PublicId == contactId) .SingleOrDefault()) { Trusted = true }; if (contact.SendAesKey == null) { Log("Sending new key."); BinaryEncoder.SendInt(stream, 1); AESPassword password = AESPassword.GenerateAESPassword(); contact.SendAesKey = password.Password; X509Certificate2 recepientCert = X509Certificate2Utils.ImportFromPem( context.Contacts .Where(u => u.PublicId == contactId) .Select(u => u.PublicCertificate) .SingleOrDefault()); byte[] toSend = RSAEncoder.EncryptAndSign(password.Password, recepientCert, MyCertificate); BinaryEncoder.SendBytes(stream, toSend); } else { Log("No new key will be sended."); BinaryEncoder.SendInt(stream, 0); } if (contactId != this.UserId) { PushOperations.SendJsonCapsula(context, contact.GetSelfUpdate(), UserId, UserId); } else { var me = context.Contacts .Where(u => u.PublicId == UserId) .Single(); me.SendAesKey = contact.SendAesKey; me.ReceiveAesKey = contact.ReceiveAesKey; } context.SaveChanges(); } Log("Trustification has been done."); } Push(); }
public int Pull() { int changes = 0; ThrowExceptionIfNotConnected(); lock (mutex) { Log("Sending PULL command."); BinaryEncoder.SendCommand(stream, ConnectionCommand.PULL); #if (DEBUG) Log("Sending ClientPullCapsula."); #endif ClientPullCapsula clientCapsula; using (Context context = new Context(config)) { clientCapsula = new ClientPullCapsula() { AesKeysUserIds = context.Contacts .Where(u => u.ReceiveAesKey == null) .Select(u => u.PublicId) .ToArray() }; } TextEncoder.SendJson(stream, clientCapsula); ServerPullCapsula capsula = TextEncoder.ReadJson <ServerPullCapsula>(stream); #if (DEBUG) Log("Received ServerPullCapsula."); #endif changes += capsula.AesKeysUserIds.Count; changes += capsula.Messages.Count; using (Context context = new Context(config)) { #if (DEBUG) Log("Receiving and saving AES keys."); #endif foreach (var id in capsula.AesKeysUserIds) { var user = new UContact(context.Contacts.Where(con => con.PublicId == id).SingleOrDefault()); try { user.ReceiveAesKey = RSAEncoder.DecryptAndVerify(BinaryEncoder.ReceiveBytes(stream), MyCertificate, X509Certificate2Utils.ImportFromPem(user.PublicCertificate)); } catch (Exception ex) { Log($"Loading of Receive AESKey from {user.PublicId} has failed."); logger.LogException(this, ex); } PushOperations.Update(context, user, UserId, UserId); } context.SaveChanges(); #if (DEBUG) Log("Receiving and saving messages."); #endif foreach (PullMessage metaMessage in capsula.Messages) { BlobMessages metaBlob = new BlobMessages() { PublicId = metaMessage.PublicId, SenderId = metaMessage.SenderId, Failed = 0, DoDelete = 0 }; context.BlobMessages.Add(metaBlob); context.SaveChanges(); try { PullMessageParser.ParseEncryptedMessage(context, BinaryEncoder.ReceiveBytes(stream), metaBlob.SenderId, metaBlob.Id, UserId); } catch (Exception ex) { Log($"Loading of message {metaMessage.PublicId} has failed."); metaBlob.Failed = 1; logger.LogException(this, ex); } context.SaveChanges(); } } Log("Pull have been done."); } return(changes); }
static void Main(string[] args) { main: logger = new Logger(new ConsoleLoggerOutput()); WriteLine("Chatovatko client at your service!"); try { config = new ConsoleClientDatabaseConfig(); initializator = new DBInitializator(config, logger); initializator.DBEnsureCreated(); settingsLoader = new SettingsLoader(config, logger); if (settingsLoader.Exists()) { Log("Settings exists and will be loaded."); settings = settingsLoader.GetSettingsCapsula(); } else { Log("Settings doesn't exist."); } bool running = true; while (running) { try { String command = ReadLine().Trim(); String[] commandParts = command.Split(' '); switch (commandParts[0]) { case "init": if (commandParts.Length < 3) { WriteNotEnoughParameters(); break; } if (settings != null) { WriteLine("Chatovatko is initialized already."); break; } bool? newUser = null; string userName = null; string serverAddress = commandParts[2]; switch (commandParts[1]) { case "new": newUser = true; break; case "login": newUser = false; break; default: WriteSyntaxError(commandParts[1]); break; } if (newUser != null) { X509Certificate2 clientCert; if (newUser == true) { WriteLine("Your certificate is being created. Please, be patient."); clientCert = X509Certificate2Generator.GenerateCACertificate(logger); WriteLine("Your certificate has been generated. Enter path to save it: [default: ~/.chatovatko/mykey.p12]"); string path = ReadLine(); if (path.Equals("")) { path = $"{Utils.GetConfigDirectory()}/mykey.p12"; } X509Certificate2Utils.ExportToPkcs12File(clientCert, path); WriteLine("----------------------------------------------------------------"); WriteLine("Enter your new unique username:"******"Enter path to your certificate please: [default: ~/.chatovatko/mykey.p12]"); string path = ReadLine(); if (path.Equals("")) { path = $"{Utils.GetConfigDirectory()}/mykey.p12"; } WriteLine("If you are logining to this server first time, it is nessary to enter you new unique username:"******"Do you trust this server (y/n):"); string pushed = ReadLine(); if (!pushed.Equals("y")) { break; } IConnectionVerificator verificator = new ConnectionVerificator(logger, info.PublicKey); connection = new Connection(logger, verificator, serverAddress, clientCert, config, userName); connection.Connect(); Log("Saving settings."); settingsLoader.Create(clientCert, connection.UserId, connection.UserName, info.Name, serverAddress, info.PublicKey, (int)connection.ClientId); settings = settingsLoader.GetSettingsCapsula(); Log("Self-trustification begin."); connection.TrustContact(connection.UserId); Log("Self-trustification done."); Log("Updating."); connection.Pull(); connection.Push(); Log("Updating done."); } break; case "connect": CreateOpenedConnection(true); break; case "disconnect": if (!VerifyConnectionOpened(true)) { break; } connection.Disconnect(); break; case "push": if (!VerifyConnectionOpened(true)) { break; } connection.Push(); break; case "pull": if (!VerifyConnectionOpened(true)) { break; } connection.Pull(); break; case "delete": if (commandParts.Length < 2) { WriteNotEnoughParameters(); break; } switch (commandParts[1]) { case "database": initializator.DBDelete(); WriteLine(); running = false; config = null; initializator = null; settingsLoader = null; settings = null; connection = null; goto main; case "message": if (commandParts.Length < 3) { WriteNotEnoughParameters(); break; } DeleteMessage(Int32.Parse(commandParts[2])); break; case "thread": if (commandParts.Length < 3) { WriteNotEnoughParameters(); break; } DeleteThread(Int32.Parse(commandParts[2])); break; default: WriteSyntaxError(commandParts[1]); break; } break; case "download": if (commandParts.Length < 3) { WriteNotEnoughParameters(); break; } switch (commandParts[1]) { case "info": WriteServerInfo(commandParts[2]); break; default: WriteSyntaxError(commandParts[1]); break; } break; case "ls": if (commandParts.Length < 2) { WriteNotEnoughParameters(); break; } switch (commandParts[1]) { case "users": WriteUsers(); break; case "threads": WriteThreads(); break; case "messages": if (commandParts.Length < 3) { WriteNotEnoughParameters(); break; } WriteMessages(Int32.Parse(commandParts[2])); break; default: WriteSyntaxError(commandParts[1]); break; } break; case "post": if (commandParts.Length < 4) { WriteNotEnoughParameters(); break; } switch (commandParts[1]) { case "thread": PostThread(Int32.Parse(commandParts[2]), BuildFromRest(commandParts, 3)); break; case "message": PostMessage(Int32.Parse(commandParts[2]), commandParts[3]); break; default: WriteSyntaxError(commandParts[1]); break; } break; case "rename": if (commandParts.Length < 4) { WriteNotEnoughParameters(); break; } switch (commandParts[1]) { case "thread": RenameThread(Int32.Parse(commandParts[2]), BuildFromRest(commandParts, 3)); break; default: WriteSyntaxError(commandParts[1]); break; } break; case "trust": if (commandParts.Length < 2) { WriteNotEnoughParameters(); break; } VerifyConnectionOpened(true); connection.TrustContact(Int32.Parse(commandParts[1])); break; case "untrust": if (commandParts.Length < 2) { WriteNotEnoughParameters(); break; } VerifyConnectionOpened(true); connection.UntrustContact(Int32.Parse(commandParts[1])); break; case "generate": if (commandParts.Length < 2) { WriteNotEnoughParameters(); break; } switch (commandParts[1]) { case "X509Certificate2": X509Certificate2 cert = X509Certificate2Generator.GenerateCACertificate(logger); WriteLine(X509Certificate2Utils.ExportToBase64(cert)); break; default: WriteSyntaxError(commandParts[1]); break; } break; case "aesTrial": if (!VerifyConnectionOpened(true)) { break; } AesTrial(); break; case "exit": case "quit": running = false; break; case "--": case "": case "#": break; case "status": WriteStatus(settings.Settings, config); break; default: WriteSyntaxError(commandParts[0]); break; } } catch (ChatovatkoException ex) { logger.Log("Program", "Core", "The command has failed.", true); logger.LogException(ex); } catch (Exception ex) { logger.LogException(ex, "Program", "Core", "The command has failed."); } } //Config config; //Connection.Connect(); } catch (Exception ex) { logger.Log("Program", "Core", String.Format("The client has crashed. Exception:\n{0}\n{1}", ex.Message, ex.StackTrace), true); } finally { logger.Close(); logger = null; } }
public static UserCapsula Run(Stream stream, Action <string> log, ServerConfig config) { ClientHandshake clientHandshake = TextEncoder.ReadClientHandshake(stream); X509Certificate2 clientCertificate = X509Certificate2Utils.ImportFromPem(clientHandshake.PemCertificate); log($"Logging user sent username {clientHandshake.UserName}\n Certificate:\n {clientHandshake.PemCertificate}"); log("Generating random bytes"); byte[] randomBytes = LUtils.GenerateRandomBytes(TcpConstants.HANDSHAKE_LENGHT); log("Sending encrypted bytes"); BinaryEncoder.SendBytes(stream, RSAEncoder.Encrypt(randomBytes, clientCertificate)); ServerHandshake errorHandshake = new ServerHandshake() { Errors = "", NewUser = false, Succeeded = false, UserId = -1, UserName = "" }; byte[] received = BinaryEncoder.ReceiveBytes(stream); if (!randomBytes.SequenceEqual(received)) { log("Sending error to client."); errorHandshake.Errors = "Client's certificate verification failed."; TextEncoder.SendJson(stream, errorHandshake); throw new Exception(errorHandshake.Errors); } log("Certificate verification succeeded."); Users user; String message; Clients client; bool newUser = false; using (Context context = new Context(config)) { SHA1 sha = new SHA1CryptoServiceProvider(); byte[] hash = sha.ComputeHash(clientCertificate.RawData); user = context.Users.SingleOrDefault(u => u.PublicCertificateSha1.SequenceEqual(hash)); if (user == null) { log("User doesn't exist yet. I'll try to create him."); newUser = true; log("Checking the uniquity of username."); String userName = clientHandshake.UserName; if (context.Users.SingleOrDefault(u => u.UserName.Equals(userName)) != null) { log("Username isn't unique."); errorHandshake.Errors = "Username isn't unique."; TextEncoder.SendJson(stream, errorHandshake); throw new Exception(errorHandshake.Errors); } log("Creating user."); user = new Users() { PublicCertificate = clientHandshake.PemCertificate, PublicCertificateSha1 = hash, UserName = clientHandshake.UserName }; context.Users.Add(user); context.SaveChanges(); message = "User successfully created."; log("User successfully created."); } else { message = "User exists."; log("User exists."); } client = new Clients() { UserId = user.Id }; if (clientHandshake.ClientId == null) { context.Add(client); context.SaveChanges(); log($"Added client with Id {client.Id}."); } else { log($"Client with Id {client.Id} has logged in."); } } ServerHandshake toSend = new ServerHandshake() { Errors = message, NewUser = newUser, Succeeded = true, UserId = user.Id, UserName = user.UserName, ClientId = client.Id }; TextEncoder.SendJson(stream, toSend); UserCapsula ret = new UserCapsula(user, clientCertificate); log($"Handshake successeded. User {ret.UserName} with id {ret.UserId} has logged in"); return(ret); }