public static byte[] GetJsonEncoded(Context context, IJType message, long receiverId, byte[] attechment = null) { byte[] aesBinKey = context.Contacts .Where(u => u.PublicId == receiverId) .Select(u => u.SendAesKey) .SingleOrDefault(); AESPassword key = new AESPassword(aesBinKey); MemoryStream stream = new MemoryStream(); BinaryEncoder.SendInt(stream, (int)message.GetJsonType()); string json = JsonConvert.SerializeObject(message); TextEncoder.SendString(stream, json); if (attechment == null) { BinaryEncoder.SendInt(stream, 0); } else { BinaryEncoder.SendInt(stream, 1); BinaryEncoder.SendBytes(stream, attechment); } byte[] notEncrypted = stream.ToArray(); return(key.Encrypt(notEncrypted)); }
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 static byte[] EncryptAndSign(byte[] data, X509Certificate2 receiverCert, X509Certificate2 myCert) { RSA publicKey = receiverCert.GetRSAPublicKey(); MemoryStream stream = new MemoryStream(); byte[] encrypted = publicKey.Encrypt(data, encryptionPadding); byte[] signiture = Sign(data, myCert); BinaryEncoder.SendBytes(stream, signiture); BinaryEncoder.SendBytes(stream, encrypted); stream.Flush(); return(stream.GetBuffer()); }
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 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 void Push() { ThrowExceptionIfNotConnected(); lock (mutex) { Log("Sending PUSH command."); BinaryEncoder.SendCommand(stream, ConnectionCommand.PUSH); using (Context context = new Context(config)) { List <long> selfMessages = new List <long>(); var toSend = context.ToSendMessages.ToList(); PushCapsula capsula = new PushCapsula(); foreach (var message in toSend) { if (message.RecepientId == UserId) { selfMessages.Add((long)message.BlobMessagesId); } capsula.PushMessages.Add(new PushMessage() { RecepientId = (int)message.RecepientId, Priority = (int)message.Priority }); } capsula.MessageToDeleteIds = context.BlobMessages .Where(u => u.DoDelete == 1) .Select(u => (long)u.PublicId).ToList(); #if (DEBUG) Log($"Sending capsula with {toSend.Count} messages. {capsula.MessageToDeleteIds.Count} will be deleted."); #endif TextEncoder.SendJson(stream, capsula); #if (DEBUG) Log($"Sending message blobs."); #endif foreach (var message in toSend) { BinaryEncoder.SendBytes(stream, message.Blob); } #if (DEBUG) Log($"Receiving PushResponse"); #endif PushResponse response = TextEncoder.ReadJson <PushResponse>(stream); var selfMessagesZip = selfMessages.Zip(response.MessageIds, (u, v) => new { PrivateId = u, PublicId = v }); foreach (var message in selfMessagesZip) { context.BlobMessages.Where(u => u.Id == message.PrivateId) .SingleOrDefault().PublicId = message.PublicId; } #if (DEBUG) Log("Saving new public ids."); #endif context.SaveChanges(); #if (DEBUG) Log("Cleaning queue."); #endif context.Database.ExecuteSqlCommand("delete from TO_SEND_MESSAGES;"); context.Database.ExecuteSqlCommand("delete from BLOB_MESSAGES where DO_DELETE=1 and PUBLIC_ID<>null;;"); context.SaveChanges(); } Log("Push have been done."); } }
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); }
private void Push() { #if (DEBUG) Log("Pushing started."); #endif ClientPullCapsula clientPullCapsula = TextEncoder.ReadJson <ClientPullCapsula>(stream); using (Context context = new Context(config)) { ServerPullCapsula capsula = new ServerPullCapsula(); List <byte[]> messagesBlobsToSend = new List <byte[]>(); List <byte[]> aesBlobsToSend = new List <byte[]>(); var messagesIdsUploaded = context.ClientsMessagesDownloaded .Where(u => u.ClientsId == connectionInfo.ClientId) .Select(u => u.BlobMessagesId); List <PullMessage> pullMessages = new List <PullMessage>(); foreach (var message in from messages in context.BlobMessages orderby messages.Priority descending, messages.Id ascending //Message order must be respected where messages.RecepientId == connectionInfo.UserId //Messages of connected user where !messagesIdsUploaded.Contains(messages.Id) //New messages join keys in context.UsersKeys on messages.RecepientId equals keys.SenderId //Keys sended by connected user where keys.Trusted == true //Only trusted where messages.SenderId == keys.RecepientId //Trusted information just only about sending user select new { messages.SenderId, messages.Content, messages.Id } ) { pullMessages.Add(new PullMessage() { PublicId = message.Id, SenderId = message.SenderId }); messagesBlobsToSend.Add(message.Content); context.ClientsMessagesDownloaded.Add(new ClientsMessagesDownloaded() { BlobMessagesId = message.Id, ClientsId = connectionInfo.ClientId }); } capsula.Messages = pullMessages; #if (DEBUG) Log($"{messagesBlobsToSend.Count} messageBlobs will be pushed."); #endif capsula.AesKeysUserIds = new List <long>(); foreach (var user in from userKeys in context.UsersKeys where userKeys.RecepientId == connectionInfo.UserId where clientPullCapsula.AesKeysUserIds.Contains(userKeys.SenderId) select new { userKeys.SenderId, userKeys.AesKey }) { capsula.AesKeysUserIds.Add(user.SenderId); aesBlobsToSend.Add(user.AesKey); } #if (DEBUG) Log($"{capsula.AesKeysUserIds.Count} AES keys will be pushed."); Log($"Sending PullCapsula."); #endif TextEncoder.SendJson(stream, capsula); #if (DEBUG) Log($"Sending AES keys."); #endif foreach (byte[] data in aesBlobsToSend) { BinaryEncoder.SendBytes(stream, data); } #if (DEBUG) Log($"Sending Messages content."); #endif foreach (byte[] data in messagesBlobsToSend) { BinaryEncoder.SendBytes(stream, data); } stream.Flush(); context.SaveChanges(); } #if (DEBUG) Log("Pushing completed."); #endif }
private void Push() { #if (DEBUG) Log("Pushing started."); #endif using (Context context = new Context(config)) { PullCapsula capsula = new PullCapsula(); List <PullUser> pullUsers = new List <PullUser>(); foreach (Users user in context.Users.Where(u => !userIdsUploaded.Contains(u.Id))) { PullUser pullUser = new PullUser() { PublicCertificate = user.PublicCertificate, UserId = user.Id, UserName = user.UserName }; pullUsers.Add(pullUser); userIdsUploaded.Add(user.Id); } capsula.Users = pullUsers; #if (DEBUG) Log($"{pullUsers.Count} users will be pushed."); #endif capsula.TrustedUserIds = new List <long>(); foreach (var userId in ( from userKeys in context.UsersKeys where userKeys.Trusted == true && userKeys.SenderId == user.UserId select new { userKeys.RecepientId })) { capsula.TrustedUserIds.Add(userId.RecepientId); } #if (DEBUG) Log($"{capsula.TrustedUserIds.Count} users is trusted by host."); #endif List <byte[]> messagesBlobsToSend = new List <byte[]>(); List <byte[]> aesBlobsToSend = new List <byte[]>(); List <PullMessage> pullMessages = new List <PullMessage>(); foreach (var message in from messages in context.BlobMessages orderby messages.Id ascending //Message order must be respected where messages.RecepientId == user.UserId //Messages of connected user where !messagesIdsUploaded.Contains(messages.Id) //New messages join keys in context.UsersKeys on messages.RecepientId equals keys.SenderId //Keys sended by connected user where keys.Trusted == true //Only trusted where messages.SenderId == keys.RecepientId //Trusted information just only about sending user select new { messages.SenderId, messages.Content, messages.Id } ) { pullMessages.Add(new PullMessage() { PublicId = message.Id, SenderId = message.SenderId }); messagesBlobsToSend.Add(message.Content); messagesIdsUploaded.Add(message.Id); } capsula.Messages = pullMessages; #if (DEBUG) Log($"{messagesBlobsToSend.Count} messageBlobs will be pushed."); #endif capsula.AesKeysUserIds = new List <long>(); foreach (var user in from userKeys in context.UsersKeys where userKeys.RecepientId == user.UserId where !aesKesUserIdsUploaded.Contains(userKeys.SenderId) select new { userKeys.SenderId, userKeys.EncryptedAesKey }) { capsula.AesKeysUserIds.Add(user.SenderId); aesKesUserIdsUploaded.Add(user.SenderId); aesBlobsToSend.Add(user.EncryptedAesKey); } #if (DEBUG) Log($"{capsula.AesKeysUserIds.Count} AES keys will be pushed."); Log($"Sending PullCapsula."); #endif TextEncoder.SendJson(stream, capsula); #if (DEBUG) Log($"Sending AES keys."); #endif foreach (byte[] data in aesBlobsToSend) { BinaryEncoder.SendBytes(stream, data); } #if (DEBUG) Log($"Sending Messages content."); #endif foreach (byte[] data in messagesBlobsToSend) { BinaryEncoder.SendBytes(stream, data); } } #if (DEBUG) Log("Pushing completed."); #endif }