using System;
 
using System.Collections.Generic;
 
using System.ComponentModel;
 
using System.Data;
 
using System.Drawing;
 
using System.Linq;
 
using System.Text;
 
using System.Windows.Forms;
 
using System.IO;
 
using System.Numerics;
 
namespace RSA
 
{
 
   public partial class MainForm : Form
 
    {
 
        public long P, Q, D, E, M, N = 0;
 
        string Source, fn = "";
 
        public long[] cipherText;
 
        public struct Key
 
        {
 
            public long index;
 
            public long N;
 
            public Key(long lIndex, long lN)
 
            {
 
                index = lIndex;
 
                N = lN;
 
            }
 
        }
 
        public static long[] Encode(string sMessage, Key oKey)
 
        {
 
            long[] numericMessage = new long[sMessage.Length];
 
            int length = sMessage.Length;
 
            for (int i = 0; i < length; i++)
 
            {
 
                numericMessage[i] = (long)sMessage[i];
 
            }
 
 
 
            return Process(numericMessage, oKey);
 
        }
 
 
 
              public static string Decode(long[] numericMessage, Key oKey)
 
        {
 
            long[] processedMessage = Process(numericMessage, oKey);
 
 
 
            StringBuilder message = new StringBuilder();
 
 
 
            int length = processedMessage.Length;
 
            for (int i = 0; i < length; i++)
 
            {
 
                message.Append((char)processedMessage[i]);
 
            }
 
            
 
            return message.ToString();
 
               }
 
        public static long ModularExponantiation(long num, Key oKey)
 
        {
 
            long C = 1;
 
            long E = 0;
 
 
 
            while (E++ < oKey.index)
 
            {
 
                C = (C * num) % oKey.N;
 
            }
 
 
 
            return C;
 
        }
 
public static long[] Process(long[] src_text, Key oKey)
 
        {
 
            long[] ciphertext = new long[src_text.Length];
 
            int length = src_text.Length;
 
            for (int i = 0; i < length; i++)
 
            {
 
                ciphertext[i] = ModularExponantiation(src_text[i], oKey);
 
            }
 
 
 
            return ciphertext;
 
        }        
 
        public MainForm()
 
        {
 
            InitializeComponent();
 
            label1.Visible = false;
 
            #region FileDialog Settings
 
            openFileDialog1.DefaultExt = "txt";
 
            openFileDialog1.Filter = "Текстовые документы|*.txt";
 
            openFileDialog1.Title = "Открыть документ";
 
            openFileDialog1.Multiselect = false;
 
            #endregion
 
        }
 
        private void OpenDocument()                                        // Функция открытия документа
 
        {
 
            openFileDialog1.FileName = string.Empty;
 
                       if (openFileDialog1.ShowDialog() == DialogResult.OK)
 
            {
 
                fn = openFileDialog1.FileName;
 
 
 
                Encoding enc = Encoding.GetEncoding(1251);
 
                try
 
                {
 
                    // Чтение файла
 
                    StreamReader sr = new StreamReader(fn, enc); //Открывает поток для чтения файла
 
                    SourceTextBox.Text = sr.ReadToEnd(); // Считываем документ до конца
 
                    SourceTextBox.SelectionStart = SourceTextBox.TextLength;
 
                    sr.Close(); // Закрываем поток
 
                }
 
                catch (Exception exc) // Отлавливаем ошибку
 
                {
 
                    MessageBox.Show("Ошибка чтения файла.\n"
 
                        + exc.ToString(), "Error!",
 
                        MessageBoxButtons.OK,
 
                        MessageBoxIcon.Error);
 
                }
 
            }
 
        }
 
        private void button3_Click(object sender, EventArgs e)
 
        {
 
            OpenDocument();
 
            TextBox1Length.Text = Convert.ToString(SourceTextBox.TextLength);
 
        }          // Кнопка "Открыть Документ"
 
        // Наибольший общий делитель
 
        private static long gcd(long x, long y)
 
        {
 
            long g;
 
            g = y;
 
            while (x > 0) // Пока не равен 0
 
            {
 
                g = x;
 
                x = y % x;
 
                y = g;
 
            }
 
            return g;
 
        }
 
        // Проверка на взаимопростоту
 
        private static long MutuallySimple(long m)
 
        {
 
            Random rd = new Random(DateTime.Now.Millisecond);
 
            int tmp_d; 
 
            long d = 0, check; 
 
            bool quit = false;
 
            while (quit == false)
 
            {
 
                tmp_d = rd.Next(2, 100);
 
                d = Convert.ToInt64(tmp_d);
 
                check = gcd(m, d);
 
                if (check == 1) // Если = 1 то простое число
 
                {
 
                    quit = true;
 
                }
 
            }
 
            return d;
 
        }
 
        // Расширенный алгоритм Евклида
 
        private static long ExtGCD(long x, long y)
 
        {
 
            long a, b, q, r, u1, u2;
 
            long t;
 
 
 
            a = Convert.ToInt64(x);
 
            b = Convert.ToInt64(y);
 
            u1 = 1;
 
            u2 = 0;
 
            while (b != 0)
 
            {
 
                q = a / b;
 
                r = a % b;
 
                a = b; b = r;
 
                t = u2;
 
                u2 = u1 - q * u2;
 
                u1 = t;
 
            }
 
            return u1;
 
        }
 
        private void ApplyPQButton_Click(object sender, EventArgs e)
 
        {
 
            if (PTextBox.Text.Length == 0 && QTextBox.Text.Length == 0 )
 
            {
 
                MessageBox.Show("Введите значение P и Q!");           
 
                return;
 
            } else if (PTextBox.Text.Length == 0)
 
            {
 
                MessageBox.Show("Введите значение P!");
 
                return;
 
            }
 
            else if (QTextBox.Text.Length == 0)
 
            {
 
                MessageBox.Show("Введите значение Q!");
 
                return;
 
            } 
 
            P = Convert.ToUInt32(PTextBox.Text);
 
            Q = Convert.ToUInt32(QTextBox.Text);
 
            N = P * Q;
 
            M = (P-1) * (Q-1);
 
            D = MutuallySimple(M);
 
            long tmp_E;
 
           tmp_E = ExtGCD(D, M);
 
            if (tmp_E <= 0)
 
           {
 
                while (tmp_E < 0)
 
              {
 
                   D = MutuallySimple(M);
 
                   tmp_E = ExtGCD(D, M);
 
               }
 
           }
 
           E = Convert.ToInt64(tmp_E);
 
 
 
            p_label.Text = Convert.ToString(P);
 
            q_label.Text = Convert.ToString(Q);
 
            e_label.Text = Convert.ToString(E);
 
            d_label.Text = Convert.ToString(D);
 
            n_label.Text = Convert.ToString(N);
 
            m_label.Text = Convert.ToString(M);
 
        }
 
        private void ClearButton_Click(object sender, EventArgs e)
 
        {
 
            p_label.Text = "0";
 
            q_label.Text = "0";
 
            n_label.Text = "0";
 
            m_label.Text = "0";
 
            d_label.Text = "0";
 
            e_label.Text = "0";
 
        }
 
        private void CryptButton_Click(object sender, EventArgs e)
 
        {
 
            if (SourceTextBox.Text.Length == 0)
 
            {
 
                MessageBox.Show("Нет текста для шифрации");
 
                return;
 
            }
 
  ResultTextBox.ResetText();
 
            textBox1.ResetText();
 
            Key publicKey = new Key(E, N);
 
              Source = SourceTextBox.Text;
 
            cipherText = Encode(Source, publicKey);
 
            for (int i = 0; i < cipherText.Length - 1; i++)
 
            {
 
                textBox1.Text += Convert.ToString(Convert.ToChar(cipherText[i]));
 
                ResultTextBox.Text += cipherText[i];
 
                ResultTextBox.Text += " ";
 
            }
 
TextBox2Length.Text = Convert.ToString(ResultTextBox.TextLength);
 
 
 
        }
 
 
 
        private void DecryptButton_Click(object sender, EventArgs e)
 
        {
 
            if (ResultTextBox.Text.Length == 0)
 
            {
 
                MessageBox.Show("Нет текста для дешифрации");
 
                return;
 
            }
 
 
 
            ResultTextBox.ResetText();
 
            
 
            Key privateKey = new Key(D, N);
 
            
 
            ResultTextBox.Text = Decode(cipherText, privateKey);
 
            TextBox2Length.Text = Convert.ToString(ResultTextBox.TextLength);
 
 
 
            if (SourceTextBox.Text == ResultTextBox.Text)
 
            {
 
                label1.Visible = true;
 
                label1.Text = "Дешифрование успешно!";
 
                label1.ForeColor = Color.Green;
 
            }
 
            else
 
            {
 
                label1.Visible = true;
 
                label1.Text = "Дешифрование неудачно!";
 
                label1.ForeColor = Color.Red;
 
            }
 
        }
 
 
 
        private void SourceTextBox_TextChanged(object sender, EventArgs e)
 
        {
 
            TextBox1Length.Text = Convert.ToString(SourceTextBox.TextLength);
 
        }
 
 
 
        private void MainForm_Load(object sender, EventArgs e)
 
        {
 
 
 
        }
 
 
 
        private void label12_Click(object sender, EventArgs e)
 
        {
 
 
 
        }
 
 
 
        private void n_label_Click(object sender, EventArgs e)
 
        {
 
 
 
        }
 
 
 
        private void textBox1_TextChanged(object sender, EventArgs e)
 
        {
 
            
 
        }
 
 
 
        private void d_label_Click(object sender, EventArgs e)
 
        {
 
 
 
        }
 
 
 
        private void openFileDialog1_FileOk(object sender, CancelEventArgs e)
 
        {
 
 
 
        }
 
 
 
        private void textBox2_TextChanged(object sender, EventArgs e)
 
        {
 
 
 
        }
 
 
 
        private void label13_Click(object sender, EventArgs e)
 
        {
 
 
 
        }
 
         
 
    }
 
}