Skip to content

Instantly share code, notes, and snippets.

@griga
Last active May 21, 2020 00:55
Show Gist options
  • Save griga/96eddc6cc604609dafdbf2fff5ee717a to your computer and use it in GitHub Desktop.
Save griga/96eddc6cc604609dafdbf2fff5ee717a to your computer and use it in GitHub Desktop.
just listing
// [0] файл program.java
// стартовий файл. запускає форму StartForm [1] в якій можна обрати режим 'сервера' або режим 'клієнта'
using System;
using System.Net;
using System.Net.Sockets;
namespace ChatRSA
{
class Program
{
static void Main()
{
System.Windows.Forms.Application.EnableVisualStyles();
StartForm s = new StartForm();
s.ShowDialog();
System.Diagnostics.Process.GetCurrentProcess().Kill();
}
}
}
// [1] файл start-form.java
// стартова форма программи
// з неї можна запустити прогу в режимі 'сервер' [2], 'клієнт' [5] або вийти нафіг
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace ChatRSA
{
public partial class StartForm : Form
{
public StartForm()
{
InitializeComponent();
}
// старт проги в режимі 'сервер' [2]
private void button1_Click(object sender, EventArgs e)
{
ServerForm s = new ServerForm();
this.Visible = false;
s.ShowDialog();
this.Close();
}
// старт проги в режимі 'клієнт' [5]
private void button2_Click(object sender, EventArgs e)
{
ClientForm c = new ClientForm();
this.Visible = false;
c.ShowDialog();
this.Close();
}
private void вихідToolStripMenuItem_Click(object sender, EventArgs e)
{
StartForm.ActiveForm.Close();
}
private void проПрограмуToolStripMenuItem_Click(object sender, EventArgs e)
{
AboutBox1 a = new AboutBox1();
a.Show();
}
}
}
// [2] файл server-form.java - юзер інтерфейс 'сервера' (форма з кнопками для 'адміна')
//
//
//
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;
namespace ChatRSA
{
public partial class ServerForm : Form
{
// сервер [3]
Server server;
//
bool keysExist = false;
// шифрувалник сервера [4]
private readonly RSAServer _rsaserver;
// тут зберігаються ключі під'єднаних до сервера клієнтів. Чому тільки 100 ? хз
string[] clientsNames = new string[100];
string[] clientsKeysE = new string[100];
string[] clientsKeysN = new string[100];
int i;
int j;
int m;
// конструктор. ініціфлізація форми з дефолтними значеннями
public ServerForm()
{
InitializeComponent();
box_ip.Text = IPAddress.Loopback.ToString(); // loopback це 127.0.0.1 - "обратная петля". тобто це звертання компа по мережі до самого себе
box_port.Text = "8080";
box_name.Text = "Адміністратор";
}
// старт сервера.
private void button_createServer_Click(object sender, EventArgs e, Client client)
{
server = new Server(box_name.Text, IPAddress.Parse(box_ip.Text), int.Parse(box_port.Text));
server.Start();
// коли [сервер] отримує данні від клієнта він виконує 'reciveData' [2][6]
server.ReciveData += new ServerReciveData(reciveData);
// коли до [сервера] під'єднується клієнт він виконує 'addClients' [2][3]
server.ClientJoint += new ServerClientJoint(addClients);
box_param.Enabled = false;
if (!keysExist)
{
generateServerKeys();
}
}
// [2][1] згенерувати ключі сервера
void generateServerKeys()
{
_rsaserver.generatePQ();
_rsaserver.generateED();
}
// [2][2] відправити ключі [сервера] E та N клієнту
void sendToClientENKeys(Client client)
{
client.Writer.Write(_rsaserver.E.ToString());
client.Writer.Write(_rsaserver.N.ToString());
}
// [2][3] додати клієнта в список клієнтів
void addClients(Client client)
{
// нах 3 лічильника i j m ? хз, сожна було юзати спокійно 1 лічильник
i++;
j++;
m++;
// записати ім'я клієнта під індексом i
clientsNames[i] = client.Name;
// записати ключ E клієнта під індексом j
clientsKeysE[j] = client.E;
// записати ключ N клієнта під індексом m
clientsKeysN[m] = client.N;
// відправити ключі [сервера] E та N клієнту [2][2]
sendToClientENKeys();
// показати клієнта в списку під'єднаних клієнтів
box_clients.Items.Add(client.Name);
}
// [2][4] відправка зашифрованого тексту клієнту
private void button_send_Click(object sender, EventArgs e)
{
Client c = server.GetClient(box_resiver.Text);
if (c == null)
{
MessageBox.Show("Клієнта не знайдено!");
return;
}
if (c.ServerEnabled == false)
{
MessageBox.Show("Нема зв'язку з клієнтом!");
return;
}
// знайти ключі клієнта в списку
for (int i = 0; count(clientsNames) < i; i++ )
{
if (clientsNames[i] == client.Name)
{
_rsaserver.E = clientsKeysE[i];
_rsaserver.N = clientsKeysN[i];
}
}
// зашифрувати месседж
string text = _rsaserver.Encryption(box_message.Text);
// відправити зашифрований месседж клієнту
c.Writer.Write(text);
// додати меседж у вікно переписки 'Я [05/20] : привіт! '
box_messages.Items.Add("Я" + " [" + DateTime.Now.ToString() + "] " + " : " + box_message.Text);
// очисти поле вводу тексту
box_message.Text = "";
}
// [2][5] коли форму закривають - спинити сервер
private void ServerForm_FormClosed(object sender, FormClosedEventArgs e)
{
if (server != null) server.Dispose();
}
// [2][6] виконується коли сервер отримує данні від клієнта
void reciveData(Client client)
{
// розшифровка месседжа кліента
var text = _rsaserver.Decryption(client.Reader.ReadString());
// додати розшифрований текст на екран 'Аліса [05/20] >> привіт! '
box_messages.Items.Add(client.Name + " [" + DateTime.Now.ToString() + "] " + " >> " + text );
}
}
}
// [3] файл server.java - 'сервер'
// можна назвати його диспечером подій всередені програми
// виконує більше транспортну функцію - слухає на підключення клієнтів і
// 127.0.0.1:4000
using System;
using System.IO;
using System.Net;
using System.Threading;
using System.Net.Sockets;
using System.Collections.Generic;
namespace ChatRSA
{
public delegate void ServerClientJoint(Client client);
public delegate void ServerReciveData(Client client);
public class Server : IDisposable
{
string name;
TcpListener server;
Thread ThreadAcceptSocket;
bool isStarted = false;
public List<Client> Clients;
public ServerClientJoint ClientJoint;
public ServerReciveData ReciveData;
// конструктор
public Server(String name, IPAddress ip, int port)
{
this.name = name;
server = new TcpListener(ip, port);
// список клієнтів
Clients = new List<Client>();
ThreadAcceptSocket = new Thread(new ThreadStart(_ThreadAcceptSocket));
}
// [3][1] стартує сервер. входить в режим очікування на підключення нових клієнтів
public bool Start()
{
if (isStarted == true) return false;
try
{
server.Start();
ThreadAcceptSocket.Start();
isStarted = true;
return true;
}
catch
{
isStarted = false;
return false;
}
}
// [3][2] вимкнутись. зупиняє сервак і всіх клієнтів
public void Dispose()
{
try
{
server.Stop();
ThreadAcceptSocket.Abort();
for (int n = 0; n < Clients.Count; n++)
{
Clients[n].Dispose();
}
}
catch
{
}
}
// [3][3] підєднує нового клієнта, налаштовує транспортний канал для отримання і передачі (Reader Writer)
void _ThreadAcceptSocket()
{
while (true)
{
Client newC = new Client("");
newC.client = server.AcceptTcpClient();
newC.reader = new BinaryReader(newC.client.GetStream());
newC.writer = new BinaryWriter(newC.client.GetStream());
Thread.Sleep(25);
newC.name = newC.reader.ReadString();
newC.writer.Write(name);
newC.ReciveData += new ClienReciveData(ClientResiveData);
Clients.Add(newC);
newC.ThreadReciveData.Start();
if (ClientJoint != null) ClientJoint.Invoke(newC);
}
}
// [3][4] отримання данних від клієнта
void ClientResiveData(Client client)
{
if (ReciveData != null) ReciveData.Invoke(client);
}
// [3][5] знайти клієнта по імені
public Client GetClient(string name)
{
for (int n = 0; n < Clients.Count; n++)
{
if (Clients[n].name == name) return Clients[n];
}
return null;
}
// перевірка чи сервер запущений
public bool IsStarted
{
get { return isStarted; }
}
}
}
// [4] файл rsa-server.java - власне шифрувальник - дешифрувальник
// займається генерацією пар ключів та шифруванням/дешифруванням згенерованими ключами
using System;
using System.Text;
namespace ChatRSA
{
public class RSAServer
{
private readonly Random _rnd;
public long P { get; private set; }
public long Q { get; private set; }
public long N { get; private set; }
public long FN { get; private set; }
public long D { get; set; }
public long E { get; set; }
// конструткор
public RSAServer()
{
// випадкове число для початкової ентропії
_rnd = new Random();
}
// [4][1] створити ключі P Q
public void generatePQ()
{
P = Prime32();
Q = Prime32();
N = P * Q;
FN = (P - 1) * (Q - 1);
}
// [4][2] створити ключі E D
public void generateED()
{
Int64 x, y;
D = _rnd.Next(100000);
while (gcd(D, FN, out x, out y) != 1)
{
D = _rnd.Next(100000);
}
E = (x % FN + FN) % FN;
}
// [4][3] зашифрувати месседж
public string Encryption(string text)
{
int i;
var textToByte = Encoding.Default.GetBytes(text);
var encryption = "";
for (i = 0; i < textToByte.Length; i++)
{
encryption += powmod(textToByte[i], E, N);
encryption += ' ';
}
return encryption;
}
// [4][4] розшифрувати месседж
public string Decryption(string text)
{
int i;
var words = text.Split(' ');
var decText = new byte[words.Length - 1];
for (i = 0; i < words.Length - 1; i++)
{
var s = Convert.ToByte(powmod(Convert.ToInt32(words[i]), D, N));
decText[i] = s;
}
return Encoding.Default.GetString(decText);
}
public Int64 gcd(Int64 a, Int64 b, out Int64 x, out Int64 y)
{
if (a == 0)
{
x = 0;
y = 1;
return b;
}
Int64 x1, y1;
Int64 d = gcd(b % a, a, out x1, out y1);
x = y1 - (b / a) * x1;
y = x1;
return d;
}
public Int64 Prime32()
{
var pr = (Int64)_rnd.Next(100, 1000) * 2 + 1;
var isprime = false;
while (!isprime)
{
isprime = true;
var ub = (Int64)Math.Sqrt(pr);
int i;
for (i = 3; i <= ub; i += 2)
{
if ((pr % i) == 0)
{
isprime = false;
break;
}
}
if (!isprime)
{
pr += 2;
}
}
return pr;
}
public Int64 powmod(int a1, Int64 b, Int64 p)
{
Int64 res = 1;
Int64 a = a1;
while (b > 0)
if (b % 2 == 1)
{
res = (res * a) % p;
--b;
}
else
{
a = (a * a) % p;
b >>= 1;
}
return res % p;
}
}
}
// [5] файл client-form.java - інтерфейс 'клієнта' (форма з кнопками і текстом)
//
//
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
namespace ChatRSA
{
public partial class ClientForm : Form
{
private readonly RSAClient _rsaclient;
bool sendKeys = false;
string keyFromServerE;
string keyFromServerN;
Client client;
// конструктор
public ClientForm()
{
InitializeComponent();
box_ip.Text = IPAddress.Loopback.ToString(); // loopback це 127.0.0.1 - "обратная петля". тобто це звертання компа по мережі до самого себе
box_port.Text = "8080";
box_name.Text = "Користувач";
}
// [5][1] під'єднатись до сервера
private void button_createClient_Click(object sender, EventArgs e)
{
client = new Client(box_name.Text);
this.Text = client.Name;
client.Connect(IPAddress.Parse(box_ip.Text), int.Parse(box_port.Text));
box_param.Enabled = false;
client.ReciveData += new ClienReciveData(resiveData);
if (!sendKeys)
{
generateClientKeys();
client.ReciveData += new ClienReciveData(sendToServerENKeys);
}
box_resiver.Text = client.ServerName;
}
// [5][2] генерація ключів клієнта
void generateClientKeys()
{
_rsaclient.generatePQ();
_rsaclient.generateED();
}
// [5][3] відправка ключів E та N на сервак
void sendToServerENKeys(Client c)
{
client.Writer.Write(_rsaclient.E.ToString());
client.Writer.Write(_rsaclient.N.ToString());
}
// [5][4] при отримані данних з сервера
void resiveData(Client c)
{
// переконатись в наявності ключів з сервера
if (!keyFromServerE)
{
keyFromServerE = server.E;
}
if (!keyFromServerN)
{
keyFromServerE = server.N;
}
// розшифрувати текст ключами сервера
var text = _rsaclient.Decryption(client.Reader.ReadString());
// додати розшифрований текст на екран ' привіт! '
box_messages.Items.Add(text);
}
// [5][5] вимкнутись
private void ClientForm_FormClosed(object sender, FormClosedEventArgs e)
{
if (client != null) client.Dispose();
}
// [5][6] відправити зашифрований текст на сервер
private void button_send_Click(object sender, EventArgs e)
{
// зашифровка текста
string text = _rsaclient.Encryption(box_message.Text);
// відправка на сервер
client.Writer.Write(text);
// додати свій текст на екран 'Я [05/20] >> привіт! '
box_messages.Items.Add("Я " + " [" + DateTime.Now.ToString() + "] " + " : " + box_message.Text);
box_message.Text = "";
}
}
}
// [6] файл client.java
using System;
using System.IO;
using System.Net;
using System.Threading;
using System.Net.Sockets;
using System.Collections.Generic;
namespace ChatRSA
{
public delegate void ClienReciveData(Client client);
public class Client : IDisposable
{
public static int TimeOutUpdate = 25;
internal string name;
internal TcpClient client;
internal BinaryWriter writer;
internal BinaryReader reader;
internal Thread ThreadReciveData;
internal bool isConnect = false;
internal string serverName = "";
int oldReciveDataSize = 0;
public ClienReciveData ReciveData;
// конструктор
public Client(string name)
{
this.name = name;
client = new TcpClient();
ThreadReciveData = new Thread(new ThreadStart(_ThreadReciveData));
}
// [6][1]
public bool Connect(IPAddress ip, int port)
{
if (isConnect == true) return false;
try
{
client.Connect(ip, port);
writer = new BinaryWriter(client.GetStream());
reader = new BinaryReader(client.GetStream());
writer.Write(name);
Thread.Sleep(50);
serverName = reader.ReadString();
ThreadReciveData.Start();
isConnect = true;
return true;
}
catch
{
isConnect = false;
return false;
}
}
// [6][2]
void _ThreadReciveData()
{
while (true)
{
if (client.Available == 0) oldReciveDataSize = 0;
if (client.Available > oldReciveDataSize)
{
oldReciveDataSize = client.Available;
if (ReciveData != null) ReciveData.Invoke(this);
}
Thread.Sleep(TimeOutUpdate);
}
}
public string Name
{
get
{
return name;
}
}
public BinaryReader Reader
{
get
{
return reader;
}
}
public BinaryWriter Writer
{
get
{
return writer;
}
}
public void Dispose()
{
try
{
client.EndConnect(null);
ThreadReciveData.Abort();
}
catch
{
}
}
public bool IsConnect
{
get
{
return isConnect;
}
}
public bool ServerEnabled
{
get
{
return client.Connected;
}
}
public string ServerName
{
get
{
return serverName;
}
}
}
}
// [7] файл rsa-client.java
// класс RSAClient - повний повтор класса RSAServer (той що [4])
// ті ж самі методи і цілі - один в один. не зрозуміло чому автор зробив такий дубляж...
using System;
using System.Text;
namespace ChatRSA
{
public class RSAClient
{
private readonly Random _rnd;
public long P { get; private set; }
public long Q { get; private set; }
public long N { get; set; }
public long FN { get; private set; }
public long D { get; private set; }
public long E { get; set; }
public RSAClient()
{
_rnd = new Random();
}
public void generatePQ()
{
P = Prime32();
Q = Prime32();
N = P * Q;
FN = (P - 1) * (Q - 1);
}
public void generateED()
{
Int64 x, y;
D = _rnd.Next(100000);
while (gcd(D, FN, out x, out y) != 1)
{
D = _rnd.Next(100000);
}
E = (x % FN + FN) % FN;
}
// зашифровка
public string Encryption(string text)
{
int i;
var textToByte = Encoding.Default.GetBytes(text);
var encryption = "";
for (i = 0; i < textToByte.Length; i++)
{
encryption += powmod(textToByte[i], E, N);
encryption += ' ';
}
return encryption;
}
// розшифровка
public string Decryption(string text)
{
int i;
var words = text.Split(' ');
var decText = new byte[words.Length - 1];
for (i = 0; i < words.Length - 1; i++)
{
var s = Convert.ToByte(powmod(Convert.ToInt32(words[i]), D, N));
decText[i] = s;
}
return Encoding.Default.GetString(decText);
}
public Int64 gcd(Int64 a, Int64 b, out Int64 x, out Int64 y)
{
if (a == 0)
{
x = 0;
y = 1;
return b;
}
Int64 x1, y1;
Int64 d = gcd(b % a, a, out x1, out y1);
x = y1 - (b / a) * x1;
y = x1;
return d;
}
public Int64 Prime32()
{
var pr = (Int64)_rnd.Next(100, 1000) * 2 + 1;
var isprime = false;
while (!isprime)
{
isprime = true;
var ub = (Int64)Math.Sqrt(pr);
int i;
for (i = 3; i <= ub; i += 2)
{
if ((pr % i) == 0)
{
isprime = false;
break;
}
}
if (!isprime)
{
pr += 2;
}
}
return pr;
}
public Int64 powmod(int a1, Int64 b, Int64 p)
{
Int64 res = 1;
Int64 a = a1;
while (b > 0)
if (b % 2 == 1)
{
res = (res * a) % p;
--b;
}
else
{
a = (a * a) % p;
b >>= 1;
}
return res % p;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment