Last active
May 21, 2020 00:55
-
-
Save griga/96eddc6cc604609dafdbf2fff5ee717a to your computer and use it in GitHub Desktop.
just listing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// [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