diff --git a/EonaCat.Connections/EonaCat.Connections.csproj b/EonaCat.Connections/EonaCat.Connections.csproj index 5b9754b..a8b8836 100644 --- a/EonaCat.Connections/EonaCat.Connections.csproj +++ b/EonaCat.Connections/EonaCat.Connections.csproj @@ -11,7 +11,7 @@ EonaCat (Jeroen Saey) readme.md EonaCat.Connections - 1.0.5 + 1.0.6 EonaCat (Jeroen Saey) LICENSE EonaCat.png diff --git a/EonaCat.Connections/Helpers/AesKeyExchange.cs b/EonaCat.Connections/Helpers/AesKeyExchange.cs index 312c980..8391b4f 100644 --- a/EonaCat.Connections/Helpers/AesKeyExchange.cs +++ b/EonaCat.Connections/Helpers/AesKeyExchange.cs @@ -7,24 +7,24 @@ namespace EonaCat.Connections.Helpers public static class AesKeyExchange { - private const int SaltSize = 16; - private const int KeySize = 32; - private const int IvSize = 16; - private const int HmacSize = 32; - private const int Pbkdf2Iterations = 100_000; + private const int _saltSize = 16; + private const int _keySize = 32; + private const int _ivSize = 16; + private const int _hmacSize = 32; + private const int _pbkdf2Iterations = 100_000; // Returns an AES object derived from the password and salt public static async Task ReceiveAesKeyAsync(Stream stream, string password) { // Read salt - byte[] salt = new byte[SaltSize]; - await stream.ReadExactlyAsync(salt, 0, SaltSize); + byte[] salt = new byte[_saltSize]; + await stream.ReadExactlyAsync(salt, 0, _saltSize); // Derive key byte[] key; - using (var kdf = new Rfc2898DeriveBytes(password, salt, Pbkdf2Iterations, HashAlgorithmName.SHA256)) + using (var kdf = new Rfc2898DeriveBytes(password, salt, _pbkdf2Iterations, HashAlgorithmName.SHA256)) { - key = kdf.GetBytes(KeySize); + key = kdf.GetBytes(_keySize); } var aes = Aes.Create(); @@ -41,7 +41,7 @@ namespace EonaCat.Connections.Helpers public static async Task SendAesKeyAsync(Stream stream, Aes aes, string password) { // Generate random salt - byte[] salt = new byte[SaltSize]; + byte[] salt = new byte[_saltSize]; using (var rng = RandomNumberGenerator.Create()) { rng.GetBytes(salt); @@ -49,9 +49,9 @@ namespace EonaCat.Connections.Helpers // Derive AES key byte[] key; - using (var kdf = new Rfc2898DeriveBytes(password, salt, Pbkdf2Iterations, HashAlgorithmName.SHA256)) + using (var kdf = new Rfc2898DeriveBytes(password, salt, _pbkdf2Iterations, HashAlgorithmName.SHA256)) { - key = kdf.GetBytes(KeySize); + key = kdf.GetBytes(_keySize); } aes.Key = key; @@ -66,7 +66,11 @@ namespace EonaCat.Connections.Helpers while (read < count) { int readBytes = await stream.ReadAsync(buffer, offset + read, count - read); - if (readBytes == 0) throw new EndOfStreamException(); + if (readBytes == 0) + { + throw new EndOfStreamException(); + } + read += readBytes; } } diff --git a/EonaCat.Connections/NetworkClient.cs b/EonaCat.Connections/NetworkClient.cs index d5b78c2..d2cebd6 100644 --- a/EonaCat.Connections/NetworkClient.cs +++ b/EonaCat.Connections/NetworkClient.cs @@ -45,9 +45,13 @@ namespace EonaCat.Connections _cancellation = new CancellationTokenSource(); if (_config.Protocol == ProtocolType.TCP) + { await ConnectTcpAsync(); + } else + { await ConnectUdpAsync(); + } } private async Task ConnectTcpAsync() @@ -65,9 +69,13 @@ namespace EonaCat.Connections { var sslStream = new SslStream(stream, false, _config.GetRemoteCertificateValidationCallback()); if (_config.Certificate != null) + { sslStream.AuthenticateAsClient(_config.Host, new X509CertificateCollection { _config.Certificate }, _config.CheckCertificateRevocation); + } else + { sslStream.AuthenticateAsClient(_config.Host); + } stream = sslStream; } @@ -136,9 +144,16 @@ namespace EonaCat.Connections if (_config.UseAesEncryption && _aesEncryption != null) { var lengthBuffer = new byte[4]; - if (await ReadExactAsync(_stream, lengthBuffer, 4, ct) == 0) break; + if (await ReadExactAsync(_stream, lengthBuffer, 4, ct) == 0) + { + break; + } + + if (BitConverter.IsLittleEndian) + { + Array.Reverse(lengthBuffer); + } - if (BitConverter.IsLittleEndian) Array.Reverse(lengthBuffer); int length = BitConverter.ToInt32(lengthBuffer, 0); var encrypted = new byte[length]; @@ -150,7 +165,10 @@ namespace EonaCat.Connections { data = new byte[_config.BufferSize]; int bytesRead = await _stream.ReadAsync(data, 0, data.Length, ct); - if (bytesRead == 0) break; + if (bytesRead == 0) + { + break; + } if (bytesRead < data.Length) { @@ -180,7 +198,11 @@ namespace EonaCat.Connections while (offset < length) { int read = await stream.ReadAsync(buffer, offset, length - offset, ct); - if (read == 0) return 0; + if (read == 0) + { + return 0; + } + offset += read; } return offset; @@ -236,7 +258,10 @@ namespace EonaCat.Connections public async Task SendAsync(byte[] data) { - if (!_isConnected) return; + if (!_isConnected) + { + return; + } try { @@ -245,7 +270,10 @@ namespace EonaCat.Connections data = await AesCryptoHelpers.EncryptDataAsync(data, _aesEncryption); var lengthPrefix = BitConverter.GetBytes(data.Length); - if (BitConverter.IsLittleEndian) Array.Reverse(lengthPrefix); + if (BitConverter.IsLittleEndian) + { + Array.Reverse(lengthPrefix); + } var framed = new byte[lengthPrefix.Length + data.Length]; Buffer.BlockCopy(lengthPrefix, 0, framed, 0, lengthPrefix.Length); @@ -275,7 +303,10 @@ namespace EonaCat.Connections private async Task AutoReconnectAsync() { - if (!_config.EnableAutoReconnect || IsAutoReconnecting) return; + if (!_config.EnableAutoReconnect || IsAutoReconnecting) + { + return; + } int attempt = 0; @@ -300,7 +331,9 @@ namespace EonaCat.Connections } if (!_isConnected) + { OnGeneralError?.Invoke(this, new ErrorEventArgs { Message = "Failed to reconnect" }); + } } public async Task DisconnectAsync() diff --git a/EonaCat.Connections/NetworkServer.cs b/EonaCat.Connections/NetworkServer.cs index ddd08b4..15d7db4 100644 --- a/EonaCat.Connections/NetworkServer.cs +++ b/EonaCat.Connections/NetworkServer.cs @@ -58,9 +58,13 @@ namespace EonaCat.Connections _serverCancellation = new CancellationTokenSource(); if (_config.Protocol == ProtocolType.TCP) + { await StartTcpServerAsync(); + } else + { await StartUdpServerAsync(); + } } private async Task StartTcpServerAsync() @@ -121,7 +125,9 @@ namespace EonaCat.Connections { tcpClient.NoDelay = !_config.EnableNagle; if (_config.EnableKeepAlive) + { tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); + } Stream stream = tcpClient.GetStream(); @@ -225,8 +231,16 @@ namespace EonaCat.Connections if (client.IsEncrypted && client.AesEncryption != null) { - if (await ReadExactAsync(client.Stream, lengthBuffer, 4, client.CancellationToken.Token) == 0) break; - if (BitConverter.IsLittleEndian) Array.Reverse(lengthBuffer); + if (await ReadExactAsync(client.Stream, lengthBuffer, 4, client.CancellationToken.Token) == 0) + { + break; + } + + if (BitConverter.IsLittleEndian) + { + Array.Reverse(lengthBuffer); + } + int length = BitConverter.ToInt32(lengthBuffer, 0); var encrypted = new byte[length]; @@ -238,7 +252,11 @@ namespace EonaCat.Connections { data = new byte[_config.BufferSize]; int bytesRead = await client.Stream.ReadAsync(data, 0, data.Length, client.CancellationToken.Token); - if (bytesRead == 0) break; + if (bytesRead == 0) + { + break; + } + if (bytesRead < data.Length) { var tmp = new byte[bytesRead]; @@ -263,7 +281,11 @@ namespace EonaCat.Connections while (offset < length) { int read = await stream.ReadAsync(buffer, offset, length - offset, ct); - if (read == 0) return 0; + if (read == 0) + { + return 0; + } + offset += read; } return offset; @@ -334,7 +356,9 @@ namespace EonaCat.Connections // Prepend 4-byte length (big-endian) for framing var lengthPrefix = BitConverter.GetBytes(data.Length); if (BitConverter.IsLittleEndian) + { Array.Reverse(lengthPrefix); + } var framed = new byte[lengthPrefix.Length + data.Length]; Buffer.BlockCopy(lengthPrefix, 0, framed, 0, lengthPrefix.Length);