Updated
This commit is contained in:
parent
0c659e9d34
commit
7e9d8a0d47
|
@ -11,7 +11,7 @@
|
|||
<Copyright>EonaCat (Jeroen Saey)</Copyright>
|
||||
<PackageReadmeFile>readme.md</PackageReadmeFile>
|
||||
<PackageId>EonaCat.Connections</PackageId>
|
||||
<Version>1.0.5</Version>
|
||||
<Version>1.0.6</Version>
|
||||
<Authors>EonaCat (Jeroen Saey)</Authors>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageIcon>EonaCat.png</PackageIcon>
|
||||
|
|
|
@ -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<Aes> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue