Initial Commit
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
/packages/
|
||||||
|
riderModule.iml
|
||||||
|
/_ReSharper.Caches/
|
||||||
13
.idea/.idea.Encryption/.idea/.gitignore
generated
vendored
Normal file
13
.idea/.idea.Encryption/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Rider ignored files
|
||||||
|
/modules.xml
|
||||||
|
/contentModel.xml
|
||||||
|
/.idea.Encryption.iml
|
||||||
|
/projectSettingsUpdater.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
4
.idea/.idea.Encryption/.idea/encodings.xml
generated
Normal file
4
.idea/.idea.Encryption/.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||||
|
</project>
|
||||||
8
.idea/.idea.Encryption/.idea/indexLayout.xml
generated
Normal file
8
.idea/.idea.Encryption/.idea/indexLayout.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="UserContentModel">
|
||||||
|
<attachedFolders />
|
||||||
|
<explicitIncludes />
|
||||||
|
<explicitExcludes />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/.idea.Encryption/.idea/vcs.xml
generated
Normal file
6
.idea/.idea.Encryption/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
11
AESExample/AESExample.csproj
Normal file
11
AESExample/AESExample.csproj
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<RootNamespace>RsaExample</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
86
AESExample/Program.cs
Normal file
86
AESExample/Program.cs
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
// See https://aka.ms/new-console-template for more information
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace xxx
|
||||||
|
{
|
||||||
|
public class AesEncryption
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
internal class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
string plaintext = "Hello, World!";
|
||||||
|
Console.WriteLine(plaintext);
|
||||||
|
// Generate a random key and IV
|
||||||
|
byte[] key = new byte[32]; // 256-bit key
|
||||||
|
byte[] iv = new byte[16]; // 128-bit IV
|
||||||
|
using (var rng = new RNGCryptoServiceProvider())
|
||||||
|
{
|
||||||
|
rng.GetBytes(key);
|
||||||
|
rng.GetBytes(iv); //IV == initialization vector
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt
|
||||||
|
byte[] ciphertext = Encrypt(plaintext, key, iv);
|
||||||
|
string encryptedText = Convert.ToBase64String(ciphertext);
|
||||||
|
Console.WriteLine("Encrypted Text: " + encryptedText);
|
||||||
|
// Decrypt
|
||||||
|
byte[] bytes = Convert.FromBase64String(encryptedText);
|
||||||
|
string decryptedText = Decrypt(bytes, key, iv);
|
||||||
|
Console.WriteLine("Decrypted Text: " + decryptedText);
|
||||||
|
//point
|
||||||
|
Console.ReadLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] Encrypt(string plaintext, byte[] key, byte[] iv)
|
||||||
|
{
|
||||||
|
using (Aes aesAlg = Aes.Create())
|
||||||
|
{
|
||||||
|
aesAlg.Key = key;
|
||||||
|
aesAlg.IV = iv;
|
||||||
|
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
|
||||||
|
byte[] encryptedBytes;
|
||||||
|
using (var msEncrypt = new System.IO.MemoryStream())
|
||||||
|
{
|
||||||
|
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
|
||||||
|
{
|
||||||
|
byte[] plainBytes = Encoding.UTF8.GetBytes(plaintext);
|
||||||
|
csEncrypt.Write(plainBytes, 0, plainBytes.Length);
|
||||||
|
}
|
||||||
|
encryptedBytes = msEncrypt.ToArray();
|
||||||
|
}
|
||||||
|
return encryptedBytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Decrypt(byte[] ciphertext, byte[] key, byte[] iv)
|
||||||
|
{
|
||||||
|
using (Aes aesAlg = Aes.Create())
|
||||||
|
{
|
||||||
|
aesAlg.Key = key;
|
||||||
|
aesAlg.IV = iv;
|
||||||
|
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
|
||||||
|
byte[] decryptedBytes;
|
||||||
|
using (var msDecrypt = new System.IO.MemoryStream(ciphertext))
|
||||||
|
{
|
||||||
|
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
|
||||||
|
{
|
||||||
|
using (var msPlain = new System.IO.MemoryStream())
|
||||||
|
{
|
||||||
|
csDecrypt.CopyTo(msPlain);
|
||||||
|
decryptedBytes = msPlain.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Encoding.UTF8.GetString(decryptedBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
40
Encryption.sln
Normal file
40
Encryption.sln
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Encryption", "Encryption\Encryption.csproj", "{27A19568-4CA9-4D3A-90CE-5E50B0D5E877}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TcpServer", "TcpServer\TcpServer.csproj", "{FC388EC8-8FF0-473D-8F5D-3C9A9DE9D035}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TcpClient", "TcpClient\TcpClient.csproj", "{3BC68F54-52EE-4A2C-BC7C-AA332BBA3669}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AESExample", "AESExample\AESExample.csproj", "{C200386F-913B-4415-B69C-1BC693E2BCCF}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RSAExample", "RSAExample\RSAExample.csproj", "{F97848B3-93A6-48D9-BB3D-A37D81B59AD3}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{27A19568-4CA9-4D3A-90CE-5E50B0D5E877}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{27A19568-4CA9-4D3A-90CE-5E50B0D5E877}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{27A19568-4CA9-4D3A-90CE-5E50B0D5E877}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{27A19568-4CA9-4D3A-90CE-5E50B0D5E877}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{FC388EC8-8FF0-473D-8F5D-3C9A9DE9D035}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{FC388EC8-8FF0-473D-8F5D-3C9A9DE9D035}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{FC388EC8-8FF0-473D-8F5D-3C9A9DE9D035}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{FC388EC8-8FF0-473D-8F5D-3C9A9DE9D035}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{3BC68F54-52EE-4A2C-BC7C-AA332BBA3669}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{3BC68F54-52EE-4A2C-BC7C-AA332BBA3669}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{3BC68F54-52EE-4A2C-BC7C-AA332BBA3669}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{3BC68F54-52EE-4A2C-BC7C-AA332BBA3669}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C200386F-913B-4415-B69C-1BC693E2BCCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C200386F-913B-4415-B69C-1BC693E2BCCF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C200386F-913B-4415-B69C-1BC693E2BCCF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C200386F-913B-4415-B69C-1BC693E2BCCF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{F97848B3-93A6-48D9-BB3D-A37D81B59AD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F97848B3-93A6-48D9-BB3D-A37D81B59AD3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F97848B3-93A6-48D9-BB3D-A37D81B59AD3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F97848B3-93A6-48D9-BB3D-A37D81B59AD3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
10
Encryption/Encryption.csproj
Normal file
10
Encryption/Encryption.csproj
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
24
Encryption/Program.cs
Normal file
24
Encryption/Program.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// See https://aka.ms/new-console-template for more information
|
||||||
|
|
||||||
|
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Text;
|
||||||
|
using Encryption;
|
||||||
|
|
||||||
|
var gen = new RsaKeyGenerator(512);
|
||||||
|
var keys = gen.GetKeys();
|
||||||
|
|
||||||
|
Console.WriteLine($"====BEGIN RSA PRIVATE KEY====\n{keys.PrivateKey}\n====END RSA PRIVATE KEY====");
|
||||||
|
Console.WriteLine($"====BEGIN RSA PUBLIC KEY====\n{keys.PublicKey}\n====END RSA PUBLIC KEY====");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var message = "Привет, мир!";
|
||||||
|
var encryptedMessage = RSA.Encrypt(keys.PublicKey, Encoding.UTF8.GetBytes(message));
|
||||||
|
var decryptedMessage = RSA.Decrypt(keys.PrivateKey, encryptedMessage);
|
||||||
|
|
||||||
|
Console.WriteLine($"Original message: {message}");
|
||||||
|
Console.WriteLine($"Cipher: {Convert.ToBase64String(encryptedMessage)}");
|
||||||
|
Console.WriteLine($"DecryptedMessage: {Encoding.UTF8.GetString(decryptedMessage)}");
|
||||||
|
|
||||||
|
|
||||||
49
Encryption/RSA.cs
Normal file
49
Encryption/RSA.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace Encryption;
|
||||||
|
|
||||||
|
public static class RSA
|
||||||
|
{
|
||||||
|
// Hash funciton to use. Only cryptographic hash functions can be used.
|
||||||
|
private static Func<byte[], byte[]> _hash = (data) => SHA256.HashData(data);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Encrypt message with (message^e) mod n
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="publicKey"></param>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static byte[] Encrypt(RsaPublicKey publicKey, byte[] data)
|
||||||
|
{
|
||||||
|
var dataAsBigint = new BigInteger(data);
|
||||||
|
return BigInteger.ModPow(dataAsBigint, publicKey.E, publicKey.N).ToByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decrypt cipher with (cipher^d) mod n
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="publicKey"></param>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static byte[] Decrypt(RsaPrivateKey privateKey, byte[] data)
|
||||||
|
{
|
||||||
|
var dataAsBigint = new BigInteger(data);
|
||||||
|
return BigInteger.ModPow(dataAsBigint, privateKey.D, privateKey.N).ToByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] Sign(RsaPrivateKey privateKey, byte[] data)
|
||||||
|
{
|
||||||
|
var dataHash = _hash(data);
|
||||||
|
return Decrypt(privateKey, dataHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool Verify(RsaPublicKey publicKey, byte[] data, byte[] signature)
|
||||||
|
{
|
||||||
|
var dataHash = _hash(data);
|
||||||
|
var encryptedSignature = Encrypt(publicKey, signature);
|
||||||
|
|
||||||
|
return dataHash == encryptedSignature;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
297
Encryption/RsaKeyGenerator.cs
Normal file
297
Encryption/RsaKeyGenerator.cs
Normal file
@@ -0,0 +1,297 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace Encryption;
|
||||||
|
|
||||||
|
public class RsaKeyGenerator
|
||||||
|
{
|
||||||
|
private static readonly Random _random = new(Environment.TickCount);
|
||||||
|
private BigInteger _d;
|
||||||
|
private BigInteger _e;
|
||||||
|
private BigInteger _n;
|
||||||
|
private BigInteger _p;
|
||||||
|
private BigInteger _q;
|
||||||
|
private BigInteger _r;
|
||||||
|
|
||||||
|
public RsaKeyGenerator(int bitLength)
|
||||||
|
{
|
||||||
|
//The "e" value for low compute time RSA encryption.
|
||||||
|
//Only has two bits of value 1.
|
||||||
|
const int e = 0x10001;
|
||||||
|
|
||||||
|
//Generating primes, checking if the GCD of (n-1)(p-1) and e is 1.
|
||||||
|
do
|
||||||
|
{
|
||||||
|
_q = FindPrime(bitLength / 2);
|
||||||
|
} while (_q % e == 1);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
_p = FindPrime(bitLength / 2);
|
||||||
|
} while (_p % e == 1);
|
||||||
|
|
||||||
|
//Setting n as QP, phi (represented here as r) to tortiary.
|
||||||
|
_n = _q * _p;
|
||||||
|
_r = (_p - 1) * (_q - 1);
|
||||||
|
|
||||||
|
//Computing D such that ed = 1%x.
|
||||||
|
_d = ModularInverse(e, _r);
|
||||||
|
|
||||||
|
_e = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds a prime of the given bit length, to be used as n and p in RSA key calculations.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bitlength"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static BigInteger FindPrime(int bitlength)
|
||||||
|
{
|
||||||
|
//Generating a random number of bit length.
|
||||||
|
if (bitlength % 8 != 0) throw new Exception("Invalid bit length for key given, cannot generate primes.");
|
||||||
|
|
||||||
|
//Filling bytes with pseudorandom.
|
||||||
|
var randomBytes = new byte[bitlength / 8 + 1];
|
||||||
|
_random.NextBytes(randomBytes);
|
||||||
|
//Making the extra byte 0x0 so the BigInts are unsigned (little endian).
|
||||||
|
randomBytes[randomBytes.Length - 1] = 0x0;
|
||||||
|
|
||||||
|
//Setting the bottom bit and top two bits of the number.
|
||||||
|
//This ensures the number is odd, and ensures the high bit of N is set when generating keys.
|
||||||
|
SetBitInByte(0, ref randomBytes[0]);
|
||||||
|
SetBitInByte(7, ref randomBytes[randomBytes.Length - 2]);
|
||||||
|
SetBitInByte(6, ref randomBytes[randomBytes.Length - 2]);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
//Performing a Rabin-Miller primality test.
|
||||||
|
var isPrime = RabinMillerTest(randomBytes, 40);
|
||||||
|
if (isPrime)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
IncrementByteArrayLE(ref randomBytes, 2);
|
||||||
|
var upper_limit = new byte[randomBytes.Length];
|
||||||
|
|
||||||
|
//Clearing upper bit for unsigned, creating upper and lower bounds.
|
||||||
|
upper_limit[randomBytes.Length - 1] = 0x0;
|
||||||
|
var upper_limit_bi = new BigInteger(upper_limit);
|
||||||
|
var lower_limit = upper_limit_bi - 20;
|
||||||
|
var current = new BigInteger(randomBytes);
|
||||||
|
|
||||||
|
if (lower_limit < current && current < upper_limit_bi)
|
||||||
|
//Failed to find a prime, returning -1.
|
||||||
|
//Reached limit with no solutions.
|
||||||
|
return new BigInteger(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Returning working BigInt.
|
||||||
|
return new BigInteger(randomBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A Rabin Miller primality test which returns true or false.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="num">The number to check for being likely prime.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static bool RabinMillerTest(BigInteger source, int certainty)
|
||||||
|
{
|
||||||
|
//Filter out basic primes.
|
||||||
|
if (source == 2 || source == 3) return true;
|
||||||
|
//Below 2, and % 0? Not prime.
|
||||||
|
if (source < 2 || source % 2 == 0) return false;
|
||||||
|
|
||||||
|
//Finding even integer below number.
|
||||||
|
var d = source - 1;
|
||||||
|
var s = 0;
|
||||||
|
|
||||||
|
while (d % 2 == 0)
|
||||||
|
{
|
||||||
|
d /= 2;
|
||||||
|
s += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Getting a random BigInt using bytes.
|
||||||
|
var rng = new Random(Environment.TickCount);
|
||||||
|
var bytes = new byte[source.ToByteArray().LongLength];
|
||||||
|
BigInteger a;
|
||||||
|
|
||||||
|
//Looping to check random factors.
|
||||||
|
for (var i = 0; i < certainty; i++)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
//Generating new random bytes to check as a factor.
|
||||||
|
rng.NextBytes(bytes);
|
||||||
|
a = new BigInteger(bytes);
|
||||||
|
} while (a < 2 || a >= source - 2);
|
||||||
|
|
||||||
|
//Checking for x=1 or x=s-1.
|
||||||
|
var x = BigInteger.ModPow(a, d, source);
|
||||||
|
if (x == 1 || x == source - 1) continue;
|
||||||
|
|
||||||
|
//Iterating to check for prime.
|
||||||
|
for (var r = 1; r < s; r++)
|
||||||
|
{
|
||||||
|
x = BigInteger.ModPow(x, 2, source);
|
||||||
|
if (x == 1)
|
||||||
|
return false;
|
||||||
|
if (x == source - 1) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x != source - 1) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//All tests have failed to prove composite, so return prime.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An overload wrapper for the RabinMillerTest which accepts a byte array.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bytes"></param>
|
||||||
|
/// <param name="acc_amt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static bool RabinMillerTest(byte[] bytes, int acc_amt)
|
||||||
|
{
|
||||||
|
var b = new BigInteger(bytes);
|
||||||
|
return RabinMillerTest(b, acc_amt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs a modular inverse on u and v,
|
||||||
|
/// such that d = gcd(u,v);
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>D, such that D = gcd(u,v).</returns>
|
||||||
|
private static BigInteger ModularInverse(BigInteger u, BigInteger v)
|
||||||
|
{
|
||||||
|
//Declaring new variables on the heap.
|
||||||
|
BigInteger inverse, u1, u3, v1, v3, t1, t3, q = new();
|
||||||
|
//Staying on the stack, quite small, so no need for extra memory time.
|
||||||
|
BigInteger iteration;
|
||||||
|
|
||||||
|
//Stating initial variables.
|
||||||
|
u1 = 1;
|
||||||
|
u3 = u;
|
||||||
|
v1 = 0;
|
||||||
|
v3 = v;
|
||||||
|
|
||||||
|
//Beginning iteration.
|
||||||
|
iteration = 1;
|
||||||
|
while (v3 != 0)
|
||||||
|
{
|
||||||
|
//Divide and sub q, t3 and t1.
|
||||||
|
q = u3 / v3;
|
||||||
|
t3 = u3 % v3;
|
||||||
|
t1 = u1 + q * v1;
|
||||||
|
|
||||||
|
//Swap variables for next pass.
|
||||||
|
u1 = v1;
|
||||||
|
v1 = t1;
|
||||||
|
u3 = v3;
|
||||||
|
v3 = t3;
|
||||||
|
iteration = -iteration;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (u3 != 1)
|
||||||
|
//No inverse, return 0.
|
||||||
|
return 0;
|
||||||
|
if (iteration < 0)
|
||||||
|
inverse = v - u1;
|
||||||
|
else
|
||||||
|
inverse = u1;
|
||||||
|
|
||||||
|
//Return.
|
||||||
|
return inverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the greatest common denominator of both BigIntegers given.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The GCD of A and B.</returns>
|
||||||
|
private static BigInteger GCD(BigInteger a, BigInteger b)
|
||||||
|
{
|
||||||
|
//Looping until the numbers are zero values.
|
||||||
|
while (a != 0 && b != 0)
|
||||||
|
if (a > b)
|
||||||
|
a %= b;
|
||||||
|
else
|
||||||
|
b %= a;
|
||||||
|
|
||||||
|
//Returning check.
|
||||||
|
return a == 0 ? b : a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets a bit in a given ref byte, using an index from 0-7 from the right.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bitNumFromRight">The index of the bit number from the lesser side of the byte.</param>
|
||||||
|
/// <param name="toSet">The referenced byte to set.</param>
|
||||||
|
private static void SetBitInByte(int bitNumFromRight, ref byte toSet)
|
||||||
|
{
|
||||||
|
var mask = (byte)(1 << bitNumFromRight);
|
||||||
|
toSet |= mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Increments the byte array as a whole, by a given amount. Assumes little endian.
|
||||||
|
/// Assumes unsigned randomBytes.
|
||||||
|
/// </summary>
|
||||||
|
private static void IncrementByteArrayLE(ref byte[] randomBytes, int amt)
|
||||||
|
{
|
||||||
|
var n = new BigInteger(randomBytes);
|
||||||
|
n += amt;
|
||||||
|
randomBytes = n.ToByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decrements the byte array as a whole, by a given amount. Assumes little endian.
|
||||||
|
/// Assumes unsigned randomBytes.
|
||||||
|
/// </summary>
|
||||||
|
private static void DecrementByteArrayLE(ref byte[] randomBytes, int amt)
|
||||||
|
{
|
||||||
|
var n = new BigInteger(randomBytes);
|
||||||
|
n -= amt;
|
||||||
|
randomBytes = n.ToByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public RsaKeyPair GetKeys()
|
||||||
|
{
|
||||||
|
return new RsaKeyPair(new RsaPrivateKey(_d, _n), new RsaPublicKey(_e, _n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record RsaPublicKey(BigInteger E, BigInteger N)
|
||||||
|
{
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Convert.ToBase64String(Encoding.UTF8.GetBytes($"e:{E};n:{N}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToJsonString()
|
||||||
|
{
|
||||||
|
var e = E.ToString();
|
||||||
|
var n = N.ToString();
|
||||||
|
|
||||||
|
var obj = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
["E"] = e,
|
||||||
|
["N"] = n,
|
||||||
|
};
|
||||||
|
|
||||||
|
return JsonSerializer.Serialize(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record RsaPrivateKey(BigInteger D, BigInteger N)
|
||||||
|
{
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Convert.ToBase64String(Encoding.UTF8.GetBytes($"d:{D};n:{N}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record RsaKeyPair(RsaPrivateKey PrivateKey, RsaPublicKey PublicKey);
|
||||||
25
RSAExample/Program.cs
Normal file
25
RSAExample/Program.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using (RSA rsa = RSA.Create())
|
||||||
|
{
|
||||||
|
rsa.KeySize = 2048;
|
||||||
|
|
||||||
|
// Export the public key
|
||||||
|
var publicKey = rsa.ExportRSAPublicKey();
|
||||||
|
Console.WriteLine("Public Key: " + Convert.ToBase64String(publicKey));
|
||||||
|
|
||||||
|
// Export the private key
|
||||||
|
var privateKey = rsa.ExportRSAPrivateKey();
|
||||||
|
Console.WriteLine("Private Key: " + Convert.ToBase64String(privateKey));
|
||||||
|
|
||||||
|
var message = "Some secret message";
|
||||||
|
Console.WriteLine("Original message: " + message);
|
||||||
|
|
||||||
|
// There are some of the paddings, but most common is PKCS
|
||||||
|
var encryptedBytes = rsa.Encrypt(Encoding.UTF8.GetBytes(message), RSAEncryptionPadding.Pkcs1);
|
||||||
|
Console.WriteLine("Encrypted message: " + Convert.ToBase64String(encryptedBytes));
|
||||||
|
|
||||||
|
var decryptedBytes = rsa.Decrypt(encryptedBytes, RSAEncryptionPadding.Pkcs1);
|
||||||
|
Console.WriteLine("Decrypted message: " + Encoding.UTF8.GetString(decryptedBytes));
|
||||||
|
}
|
||||||
10
RSAExample/RSAExample.csproj
Normal file
10
RSAExample/RSAExample.csproj
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
142
TcpClient/Program.cs
Normal file
142
TcpClient/Program.cs
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using Encryption;
|
||||||
|
|
||||||
|
enum ConversationState
|
||||||
|
{
|
||||||
|
Initial = 0,
|
||||||
|
RsaPublicKeyGiven,
|
||||||
|
AesKeySended,
|
||||||
|
RsaPublicKeySended,
|
||||||
|
AesKeyGiven
|
||||||
|
}
|
||||||
|
|
||||||
|
class TcpClientProgram
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
TcpClient client = new TcpClient();
|
||||||
|
client.Connect("127.0.0.1", 5000);
|
||||||
|
Console.WriteLine("Connected to server.");
|
||||||
|
|
||||||
|
NetworkStream stream = client.GetStream();
|
||||||
|
bool isRunning = true;
|
||||||
|
ConversationState state = ConversationState.Initial;
|
||||||
|
while (isRunning)
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int bytesRead;
|
||||||
|
|
||||||
|
RsaPublicKey publicKey = null;
|
||||||
|
RsaPrivateKey privateKey = null;
|
||||||
|
string? aesKey = null;
|
||||||
|
|
||||||
|
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
|
||||||
|
{
|
||||||
|
string receivedData = Encoding.ASCII.GetString(buffer, 0, bytesRead);
|
||||||
|
Console.WriteLine("Received: " + receivedData);
|
||||||
|
|
||||||
|
// Split the message into command and data
|
||||||
|
string[] messageParts = receivedData.Split(new char[] { ':' }, 2);
|
||||||
|
if (messageParts.Length < 2) continue; // Ignore malformed messages
|
||||||
|
|
||||||
|
string command = messageParts[0];
|
||||||
|
string message = messageParts[1];
|
||||||
|
|
||||||
|
switch (command)
|
||||||
|
{
|
||||||
|
case "PUBKEY":
|
||||||
|
Console.WriteLine("Received RSA Public Key: " + message);
|
||||||
|
state = ConversationState.RsaPublicKeyGiven;
|
||||||
|
var json = Convert.FromBase64String(message);
|
||||||
|
var dict = JsonSerializer.Deserialize<Dictionary<string, string>>(json);
|
||||||
|
publicKey = new RsaPublicKey(BigInteger.Parse((string)dict["E"]),
|
||||||
|
BigInteger.Parse((string)dict["N"]));
|
||||||
|
break;
|
||||||
|
case "AESKEY":
|
||||||
|
Console.WriteLine("Received Encrypted AES Key: " + message);
|
||||||
|
state = ConversationState.AesKeyGiven;
|
||||||
|
aesKey = Encoding.UTF8.GetString(Convert.FromBase64String(message));
|
||||||
|
break;
|
||||||
|
case "MSG":
|
||||||
|
Console.WriteLine("Received AES Encrypted Message: " + message);
|
||||||
|
// todo: decrypt message and print it
|
||||||
|
var decodedMessage = Convert.FromBase64String(message);
|
||||||
|
var decryptedMessageBytes = RSA.Decrypt(privateKey, decodedMessage);
|
||||||
|
Console.WriteLine($"Decrypted message: {Encoding.UTF8.GetString(decryptedMessageBytes)}");
|
||||||
|
break;
|
||||||
|
case "EXIT":
|
||||||
|
Console.WriteLine("Client is disconnecting...");
|
||||||
|
client.Close();
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
Console.WriteLine("Unknown command received: " + command);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("1. Send RSA public key");
|
||||||
|
Console.WriteLine("4. Send AES key encrypted with RSA");
|
||||||
|
Console.WriteLine("5. Send/receive AES encrypted message");
|
||||||
|
Console.WriteLine("6. Exit");
|
||||||
|
|
||||||
|
string choice = Console.ReadLine();
|
||||||
|
if (state == ConversationState.RsaPublicKeyGiven && choice == "1")
|
||||||
|
{
|
||||||
|
Console.WriteLine("You already recieved Public Key from participant. It's time to send him your AES key back");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state == ConversationState.AesKeyGiven && choice == "4")
|
||||||
|
{
|
||||||
|
Console.WriteLine("You already have AES key from participant. It's time to send him encrypted message.");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (choice)
|
||||||
|
{
|
||||||
|
case "1":
|
||||||
|
// Placeholder: Send a simulated RSA public key
|
||||||
|
var json = publicKey.ToJsonString();
|
||||||
|
var message = Convert.ToBase64String(Encoding.UTF8.GetBytes(json));
|
||||||
|
SendMessage(stream, "PUBKEY", message);
|
||||||
|
state = ConversationState.RsaPublicKeySended;
|
||||||
|
break;
|
||||||
|
case "4":
|
||||||
|
// Placeholder: Send an AES key encrypted with RSA
|
||||||
|
aesKey = ""; //todo: generate random
|
||||||
|
var aesKeyEncryptedBytes = RSA.Encrypt(publicKey, Encoding.UTF8.GetBytes(aesKey));
|
||||||
|
SendMessage(stream, "AESKEY", Convert.ToBase64String(aesKeyEncryptedBytes));
|
||||||
|
state = ConversationState.AesKeySended;
|
||||||
|
break;
|
||||||
|
case "5":
|
||||||
|
string msg = Console.ReadLine();
|
||||||
|
// Placeholder: Send an AES encrypted message
|
||||||
|
SendMessage(stream, "MSG", Convert.ToBase64String(RSA.Encrypt(publicKey, Encoding.UTF8.GetBytes(msg))));
|
||||||
|
break;
|
||||||
|
case "6":
|
||||||
|
SendMessage(stream, "EXIT", "Disconnecting");
|
||||||
|
isRunning = false;
|
||||||
|
Console.WriteLine("Exiting...");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Console.WriteLine("Invalid choice. Please try again.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SendMessage(NetworkStream stream, string command, string message)
|
||||||
|
{
|
||||||
|
string formattedMessage = $"{command}:{message}";
|
||||||
|
byte[] data = Encoding.ASCII.GetBytes(formattedMessage);
|
||||||
|
stream.Write(data, 0, data.Length);
|
||||||
|
Console.WriteLine($"Sent [{command}]: {message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
14
TcpClient/TcpClient.csproj
Normal file
14
TcpClient/TcpClient.csproj
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Encryption\Encryption.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
129
TcpServer/Program.cs
Normal file
129
TcpServer/Program.cs
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
// See https://aka.ms/new-console-template for more information
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
class TcpServer
|
||||||
|
{
|
||||||
|
private static TcpListener server;
|
||||||
|
private static bool isRunning = true;
|
||||||
|
private static List<TcpClient> connectedClients = new List<TcpClient>();
|
||||||
|
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
server = new TcpListener(IPAddress.Any, 5000);
|
||||||
|
server.Start();
|
||||||
|
Console.WriteLine("Server started on port 5000.");
|
||||||
|
|
||||||
|
while (isRunning)
|
||||||
|
{
|
||||||
|
var client = server.AcceptTcpClient();
|
||||||
|
Console.WriteLine("Client connected!");
|
||||||
|
|
||||||
|
lock (connectedClients)
|
||||||
|
{
|
||||||
|
connectedClients.Add(client); // Add new client to the list
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle each client connection in a new thread
|
||||||
|
Thread clientThread = new Thread(HandleClient);
|
||||||
|
clientThread.Start(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void HandleClient(object obj)
|
||||||
|
{
|
||||||
|
TcpClient client = (TcpClient)obj;
|
||||||
|
NetworkStream stream = client.GetStream();
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int bytesRead;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
|
||||||
|
{
|
||||||
|
string receivedData = Encoding.ASCII.GetString(buffer, 0, bytesRead);
|
||||||
|
Console.WriteLine("Received: " + receivedData);
|
||||||
|
|
||||||
|
// Split the message into command and data
|
||||||
|
string[] messageParts = receivedData.Split(new char[] { ':' }, 2);
|
||||||
|
if (messageParts.Length < 2) continue; // Ignore malformed messages
|
||||||
|
|
||||||
|
string command = messageParts[0];
|
||||||
|
string message = messageParts[1];
|
||||||
|
|
||||||
|
switch (command)
|
||||||
|
{
|
||||||
|
case "PUBKEY":
|
||||||
|
Console.WriteLine("Received RSA Public Key: " + message);
|
||||||
|
// Broadcast the message to all connected clients (excluding the sender)
|
||||||
|
BroadcastMessageToClients(client, $"{command}:{message}");
|
||||||
|
break;
|
||||||
|
case "AESKEY":
|
||||||
|
Console.WriteLine("Received Encrypted AES Key: " + message);
|
||||||
|
// Broadcast the message to all connected clients (excluding the sender)
|
||||||
|
BroadcastMessageToClients(client, $"{command}:{message}");
|
||||||
|
break;
|
||||||
|
case "MSG":
|
||||||
|
Console.WriteLine("Received AES Encrypted Message: " + message);
|
||||||
|
// Broadcast the message to all connected clients (excluding the sender)
|
||||||
|
BroadcastMessageToClients(client, $"{command}:{message}");
|
||||||
|
break;
|
||||||
|
case "EXIT":
|
||||||
|
Console.WriteLine("Client is disconnecting...");
|
||||||
|
client.Close();
|
||||||
|
lock (connectedClients)
|
||||||
|
{
|
||||||
|
connectedClients.Remove(client); // Remove client from the list
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
Console.WriteLine("Unknown command received: " + command);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Client disconnected with error: " + ex.Message);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
client.Close();
|
||||||
|
lock (connectedClients)
|
||||||
|
{
|
||||||
|
connectedClients.Remove(client);
|
||||||
|
}
|
||||||
|
Console.WriteLine("Client disconnected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void BroadcastMessageToClients(TcpClient senderClient, string message)
|
||||||
|
{
|
||||||
|
byte[] data = Encoding.ASCII.GetBytes("Broadcast: " + message);
|
||||||
|
|
||||||
|
lock (connectedClients)
|
||||||
|
{
|
||||||
|
foreach (var client in connectedClients)
|
||||||
|
{
|
||||||
|
// Send to all clients except the sender
|
||||||
|
if (client != senderClient)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
NetworkStream stream = client.GetStream();
|
||||||
|
stream.Write(data, 0, data.Length);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Error sending to client: " + ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
TcpServer/TcpServer.csproj
Normal file
10
TcpServer/TcpServer.csproj
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
Reference in New Issue
Block a user