experiments/csharp/E034-EncryptionNetwork/Program.cs

111 lines
3.9 KiB
C#

using System.IO.Compression;
using System.Net;
using System.Net.Sockets;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;
await Task.WhenAll(ServerTask(), ClientTask());
await Task.Delay(-1);
return;
static async Task ClientTask()
{
using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
await socket.ConnectAsync(new IPEndPoint(IPAddress.Loopback, 1234));
using var aes = Aes.Create();
aes.GenerateKey();
aes.GenerateIV();
await using var stream = new NetworkStream(socket);
SendAesKey(stream, aes);
const string message = "Hello";
Console.WriteLine($"Client sending message: {message}");
SendEncryptedMessage(Encoding.UTF8.GetBytes(message), stream, aes);
await Task.Delay(-1);
}
static async Task ServerTask()
{
using var listener = new Socket(SocketType.Stream, ProtocolType.Tcp);
listener.Bind(new IPEndPoint(IPAddress.Any, 1234));
listener.Listen(1);
using Socket client = await listener.AcceptAsync();
await using var stream = new NetworkStream(client);
using var aes = Aes.Create();
ReadAesKey(stream, aes);
Console.WriteLine($"Server received message: {Encoding.UTF8.GetString(ReadEncryptedMessage(stream, aes))}");
await Task.Delay(-1);
}
static void ReadAesKey(Stream stream, SymmetricAlgorithm aes)
{
using var reader = new BinaryReader(stream, Encoding.UTF8, true);
aes.Key = reader.ReadBytes(IPAddress.NetworkToHostOrder(reader.ReadInt32()));
aes.IV = reader.ReadBytes(IPAddress.NetworkToHostOrder(reader.ReadInt32()));
}
static void SendAesKey(Stream stream, SymmetricAlgorithm aes)
{
using var writer = new BinaryWriter(stream, Encoding.UTF8, true);
writer.Write(IPAddress.HostToNetworkOrder(aes.Key.Length));
writer.Write(aes.Key);
writer.Write(IPAddress.HostToNetworkOrder(aes.IV.Length));
writer.Write(aes.IV);
}
static byte[] ReadEncryptedMessage(Stream inputStream, SymmetricAlgorithm aes)
{
using var inputReader = new BinaryReader(inputStream, Encoding.UTF8, true);
using ICryptoTransform cryptoTransform = aes.CreateDecryptor();
// read unencrypted length header
using var buffer = new MemoryStream();
int length = IPAddress.NetworkToHostOrder(inputReader.ReadInt32());
Console.WriteLine($"Reading {length} bytes");
buffer.Write(inputReader.ReadBytes(length));
// read encrypted data
Console.WriteLine($"Read {buffer.Length} bytes");
Console.WriteLine("Decrypting...");
buffer.Position = 0;
using var cryptoStream = new CryptoStream(buffer, cryptoTransform, CryptoStreamMode.Read);
using var gzip = new GZipStream(cryptoStream, CompressionMode.Decompress);
using var cryptoReader = new BinaryReader(gzip, Encoding.UTF8);
length = IPAddress.NetworkToHostOrder(cryptoReader.ReadInt32());
Console.WriteLine($"Need to read {length} bytes");
return cryptoReader.ReadBytes(length);
}
static void SendEncryptedMessage(byte[] message, Stream outputStream, SymmetricAlgorithm aes)
{
using var outputWriter = new BinaryWriter(outputStream, Encoding.UTF8, true);
using ICryptoTransform cryptoTransform = aes.CreateEncryptor();
// encrypt data
using var buffer = new MemoryStream();
using var cryptoStream = new CryptoStream(buffer, cryptoTransform, CryptoStreamMode.Write);
using var gzip = new GZipStream(cryptoStream, CompressionMode.Compress);
using var cryptoWriter = new BinaryWriter(gzip, Encoding.UTF8);
cryptoWriter.Write(IPAddress.HostToNetworkOrder(message.Length));
cryptoWriter.Write(message);
cryptoWriter.Flush();
cryptoStream.FlushFinalBlock();
buffer.Position = 0;
// sent encrypted data with unencrypted length header
Console.WriteLine($"Writing {buffer.Length} bytes");
outputWriter.Write(IPAddress.HostToNetworkOrder((int)BitOperations.RoundUpToPowerOf2((uint)buffer.Length)));
buffer.CopyTo(outputStream);
outputStream.Flush();
Console.WriteLine("Message sent");
}