Skip to content

Commit

Permalink
Merge pull request #13 from martinmladenov/authenticate-incoming-conn…
Browse files Browse the repository at this point in the history
…ections

Authenticate incoming connections
  • Loading branch information
martinmladenov authored Jul 23, 2019
2 parents 677f984 + 5d547f0 commit b8044c3
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 51 deletions.
66 changes: 43 additions & 23 deletions EncryptedChat/EncryptedChat.Client.App/Engine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,14 @@ public class Engine

private async Task SetUpConnection()
{
this.communicationsManager = new EncryptedCommunicationsManager();

Console.WriteLine(Messages.ConnectingToServer, Constants.ServerUrl);

this.connection = new HubConnectionBuilder()
.WithUrl(Constants.ServerUrl)
.Build();

this.connection.On<User[]>(nameof(this.UpdateWaitingList), this.UpdateWaitingList);
this.connection.On<string, string>(nameof(this.AcceptConnection), this.AcceptConnection);
this.connection.On<string, string, string, string>(nameof(this.AcceptConnection), this.AcceptConnection);
this.connection.On<string, string>(nameof(this.NewMessage), this.NewMessage);
this.connection.On(nameof(this.Disconnect), this.Disconnect);

Expand Down Expand Up @@ -65,6 +63,10 @@ private void LoadConfiguration()
this.configurationManager = new ConfigurationManager<MainConfiguration>(Constants.ConfigurationFilePath);

this.LoadUsername();

this.communicationsManager = new EncryptedCommunicationsManager();

this.LoadPrivateKey();
}

public async Task Setup()
Expand Down Expand Up @@ -161,22 +163,29 @@ private async Task UserSelect(string input)

private async Task ConnectWithUser(User selectedUser)
{
this.state = State.InChat;

Console.Clear();
Console.WriteLine(Messages.GeneratingSessionKey);

this.communicationsManager.ImportRsaKey(selectedUser.PublicKey);
this.communicationsManager.ImportOtherRsaKey(selectedUser.PublicKey);
string aesKey = this.communicationsManager.GenerateEncryptedAesKey();
string key = this.communicationsManager.ExportOwnRsaKey();
string signature = this.communicationsManager.SignData(aesKey);

Console.WriteLine(Messages.InitialisingEncryptedConnection);

await this.connection.InvokeCoreAsync("ConnectToUser", new object[]
{
this.username, selectedUser.ConnectionId, aesKey
this.username, selectedUser.ConnectionId, aesKey, key, signature
});

this.otherUser = selectedUser;
this.CreateChatWithUser(selectedUser);
}

private void CreateChatWithUser(User user)
{
this.state = State.InChat;

this.otherUser = user;

bool isTrusted = this.IsUserTrusted(this.otherUser);

Expand All @@ -185,13 +194,17 @@ private async Task ConnectWithUser(User selectedUser)
: Messages.UserNotTrustedBadge;

Console.WriteLine();
Console.WriteLine(Messages.ConnectedWithUser, selectedUser.Username, trustedBadge);
Console.WriteLine(Messages.ConnectedWithUser, user.Username, trustedBadge);
Console.WriteLine();
Console.WriteLine(Messages.KeyFingerprint, this.communicationsManager.GetRsaFingerprint());
Console.WriteLine(Messages.CurrentUserFingerprint, this.communicationsManager.GetOwnRsaFingerprint());
Console.WriteLine();

if (!isTrusted)
{
Console.WriteLine(Messages.OtherUserFingerprint, this.otherUser.Username,
this.communicationsManager.GetOtherRsaFingerprint());
Console.WriteLine();

Console.WriteLine(new string('-', 30));
Console.WriteLine();
Console.WriteLine(Messages.UserNotTrustedMessage);
Expand Down Expand Up @@ -274,9 +287,7 @@ private void UpdateWaitingList(User[] users)

private async Task JoinAsWaitingUser()
{
this.LoadPrivateKey();

string pubKey = this.communicationsManager.ExportRsaKey();
string pubKey = this.communicationsManager.ExportOwnRsaKey();

Console.WriteLine(Messages.SendingKeyToServer);

Expand All @@ -301,19 +312,19 @@ private void LoadPrivateKey()
this.communicationsManager.GenerateNewRsaKey();

this.configurationManager.Configuration.PrivateKey =
this.communicationsManager.ExportRsaKey(true);
this.communicationsManager.ExportOwnRsaKey(true);

this.configurationManager.SaveChanges();
}
else
{
Console.WriteLine(Messages.LoadingPrivateKey);

this.communicationsManager.ImportRsaKey(this.configurationManager.Configuration.PrivateKey);
this.communicationsManager.ImportOwnRsaKey(this.configurationManager.Configuration.PrivateKey);
}
}

private void AcceptConnection(string key, string otherUsername)
private void AcceptConnection(string aesKey, string otherUsername, string rsaKey, string signature)
{
if (this.state != State.Waiting)
{
Expand All @@ -322,15 +333,24 @@ private void AcceptConnection(string key, string otherUsername)

Console.WriteLine(Messages.InitialisingEncryptedConnection);

this.communicationsManager.ImportEncryptedAesKey(key);
this.communicationsManager.ImportOtherRsaKey(rsaKey);
var signatureValid = this.communicationsManager.VerifySignature(aesKey, signature);
if (!signatureValid)
{
Console.WriteLine(Messages.IncomingConnectionSignatureInvalid);
this.Disconnect();
return;
}

this.state = State.InChat;
this.communicationsManager.ImportEncryptedAesKey(aesKey);

Console.WriteLine();
Console.WriteLine(Messages.ConnectedWithUser, otherUsername, Messages.UserNotTrustedBadge); // TODO
Console.WriteLine();
Console.WriteLine(Messages.KeyFingerprint, this.communicationsManager.GetRsaFingerprint());
Console.WriteLine();
var user = new User
{
Username = otherUsername,
PublicKey = rsaKey
};

this.CreateChatWithUser(user);
}

private void NewMessage(string encryptedMessage, string messageUsername)
Expand Down
6 changes: 4 additions & 2 deletions EncryptedChat/EncryptedChat.Client.App/Messages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public static class Messages
public const string InvalidUserIdSelectedError = "Please type a number from 0 to {0}";
public const string GeneratingSessionKey = "Generating session key...";
public const string InitialisingEncryptedConnection = "Initialising encrypted connection...";
public const string IncomingConnectionSignatureInvalid = "Could not verify user identity.";
public const string ConnectedWithUser = "Connected with {0} - {1}!";
public const string UserListHeader = "Users:";
public const string UserListItem = "{0} - {1} {2}";
Expand All @@ -20,13 +21,14 @@ public static class Messages
public const string LoadingPrivateKey = "Loading private key...";
public const string SendingKeyToServer = "Sending public key to server...";
public const string WaitingForUser = "Waiting for other user";
public const string KeyFingerprint = "Fingerprint: {0}";
public const string CurrentUserFingerprint = "Your fingerprint: {0}";
public const string OtherUserFingerprint = "{0}'s fingerprint: {1}";
public const string MessageFormat = "<{0}> {1}";
public const string LoadingConfiguration = "Loading configuration...";
public const string UserTrusted = "User trusted.";
public const string CouldNotTrustUser = "Could not trust user";

public const string UserNotTrustedMessage = "User not trusted. Verify key fingerprint and type "
public const string UserNotTrustedMessage = "User not trusted. Verify key fingerprints and type "
+ Constants.TrustCommand + " to trust user";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ public class EncryptedCommunicationsManager
{
private const char Delimiter = '-';

private readonly RsaCryptographyManager rsa;
private readonly RsaCryptographyManager otherRsa;
private readonly RsaCryptographyManager ownRsa;
private readonly AesCryptographyManager aes;

public EncryptedCommunicationsManager()
{
this.rsa = new RsaCryptographyManager();
this.otherRsa = new RsaCryptographyManager();
this.ownRsa = new RsaCryptographyManager();
this.aes = new AesCryptographyManager();
}

Expand All @@ -34,29 +36,42 @@ public string DecryptMessage(string encryptedData)
return decrypted;
}

public void GenerateNewRsaKey() => this.rsa.GenerateNewKey();
public void GenerateNewRsaKey() => this.ownRsa.GenerateNewKey();

public string ExportRsaKey(bool includePrivate = false)
=> this.rsa.ExportKeyAsXml(includePrivate);
public string ExportOwnRsaKey(bool includePrivate = false)
=> this.ownRsa.ExportKeyAsXml(includePrivate);

public void ImportRsaKey(string key)
public void ImportOwnRsaKey(string key)
{
this.rsa.LoadKeyFromXml(key);
this.ownRsa.LoadKeyFromXml(key);
}

public void ImportOtherRsaKey(string key)
{
this.otherRsa.LoadKeyFromXml(key);
}

public string GenerateEncryptedAesKey()
{
var aesKey = this.aes.GenerateKey();
var encryptedKey = this.rsa.EncryptData(aesKey);
var encryptedKey = this.otherRsa.EncryptData(aesKey);
return encryptedKey;
}

public string SignData(string data)
=> this.ownRsa.SignData(data);

public bool VerifySignature(string data, string signature)
=> this.otherRsa.VerifySignature(data, signature);

public void ImportEncryptedAesKey(string key)
{
var aes1KeyDec = this.rsa.DecryptDataAsByteArray(key);
var aes1KeyDec = this.ownRsa.DecryptDataAsByteArray(key);
this.aes.LoadKey(aes1KeyDec);
}

public string GetRsaFingerprint() => this.rsa.GetSha256Fingerprint();
public string GetOwnRsaFingerprint() => this.ownRsa.GetSha256Fingerprint();

public string GetOtherRsaFingerprint() => this.otherRsa.GetSha256Fingerprint();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,37 +26,47 @@ public string EncryptData(byte[] data)
);
}

public string EncryptData(string data)
public byte[] DecryptDataAsByteArray(string data)
{
if (string.IsNullOrWhiteSpace(data))
{
throw new ArgumentNullException(nameof(data));
}

return this.EncryptData(Encoding.UTF8.GetBytes(data));
}

public string DecryptData(string data)
{
var decryptedData = this.DecryptDataAsByteArray(data);
if (this.rsa == null)
{
throw new InvalidOperationException();
}

return Encoding.UTF8.GetString(decryptedData);
return this.rsa.Decrypt(Convert.FromBase64String(data),
RSAEncryptionPadding.OaepSHA256);
}

public byte[] DecryptDataAsByteArray(string data)
public string SignData(string data)
{
if (string.IsNullOrWhiteSpace(data))
if (this.rsa == null)
{
throw new ArgumentNullException(nameof(data));
throw new InvalidOperationException();
}

var signature = this.rsa.SignData(Encoding.UTF8.GetBytes(data),
HashAlgorithmName.SHA256, RSASignaturePadding.Pss);

return Convert.ToBase64String(signature);
}

public bool VerifySignature(string data, string signature)
{
if (this.rsa == null)
{
throw new InvalidOperationException();
}

return this.rsa.Decrypt(Convert.FromBase64String(data),
RSAEncryptionPadding.OaepSHA256);
var isValid = this.rsa.VerifyData(Encoding.UTF8.GetBytes(data),
Convert.FromBase64String(signature),
HashAlgorithmName.SHA256, RSASignaturePadding.Pss);

return isValid;
}

public void GenerateNewKey(int keySize = 4096)
Expand Down
7 changes: 4 additions & 3 deletions EncryptedChat/EncryptedChat.Server.Web/Hubs/ChatHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,19 @@ private async Task UpdateClientWaitingList(string recipientId = null)
await recipient.SendCoreAsync("UpdateWaitingList", new object[] {freeUsers});
}

public async Task ConnectToUser(string username, string otherConnectionId, string key)
public async Task ConnectToUser(string username, string otherConnectionId, string aesKey,
string rsaKey, string signature)
{
var result = this.chatService.SetupConnectionToUser(
username, otherConnectionId, this.Context.ConnectionId, key);
username, otherConnectionId, this.Context.ConnectionId, aesKey);

if (!result)
{
return;
}

await this.Clients.Client(otherConnectionId)
.SendCoreAsync("AcceptConnection", new object[] {key, username});
.SendCoreAsync("AcceptConnection", new object[] {aesKey, username, rsaKey, signature});

await this.UpdateClientWaitingList();
}
Expand Down

0 comments on commit b8044c3

Please sign in to comment.