
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using SmartCard.Runtime.Remoting.Channels.APDU;
using System.IO;
using System.Xml;
using System.Collections;
using MyCompany.Client;
using MyCompany.Server;
using MyCompany.Client.EncryptionSink;
using System.Security.Cryptography;




namespace MyCompany.Client
{


    public class ClientApp
    {
        static int RSAsize = 2048;
        public static int a_length;
        public static int length;
        public static int b_length;
        public static int m_length;
        public static string SecretKey = "ABC123";
        public static int intsKey = 123;

        public int getA_length()
        {
            return a_length * 8;
        }
        public int getB_length()
        {
            return b_length * 8;
        }
        public int getM_length()
        {
            return m_length * 8;
        }
        public static string Info;
        public string GetInfo()
        {
            return Info;
        }
        #region Pamet
        public static string Memory;
        public string GetMemory()
        {

            //Inicializace komunikace s kartou
            //Inicializace();

            //long memory = getService().getMemory();
            //Inicializace parametru pro RSA funkci na kartě

            //Vrati postupne vystup, modulus. Pro prevod z pole bytu se pouziva fce Arr2Str
            return Memory;
        }
        #endregion

        #region Autentifikace Efficient
        
        public string RemoteAutentification_Efficient(string ID, string PWD)
        {
            //Inicializace komunikace s kartou
            Inicializace();

            //string ID   = "uziv";
            //string PWD  = "heslo";
            
            // Prekonvertuji vstupni promenne do byte
            //byte[] id2 = String2Arr(ID);
            //byte[] pwd2 = String2Arr(PWD);
            //byte[] x2 = String2Arr(x);
            DateTime hashTime1 = DateTime.Now;
            byte[] id2 = System.Text.UTF8Encoding.UTF8.GetBytes(ID);
            byte[] pwd2 = System.Text.UTF8Encoding.UTF8.GetBytes(PWD);
            byte[] x2 = System.Text.UTF8Encoding.UTF8.GetBytes(SecretKey);
            
            // Provedu XOR operaci - Id XOR x
            byte[] IdX = XOR(id2 ,x2);
            
            // Prevedu do md5 hashe, dalsi volba je SHA1 h(Id XOR x)
            MD5CryptoServiceProvider hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(IdX);
            System.Text.StringBuilder s = new System.Text.StringBuilder();
            foreach (byte b in hash.Hash)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            string md5hash = s.ToString();
            byte[] byte_md5 = System.Text.UTF8Encoding.UTF8.GetBytes(md5hash);
            
            // vytvorim vyslednou hodnotu Ri - tahle a hash bude zaslana karte jako prihlaseni
            // h(Id XOR x) XOR PW
            byte[] Ri = XOR(byte_md5, pwd2);
            string strRi = System.Text.UTF8Encoding.UTF8.GetString(Ri);
            DateTime hashTime2 = DateTime.Now;
            
            // Ulozim na kartu
            string Response = getService().Registration(md5hash, strRi);
            DateTime hashTime3 = DateTime.Now;

            // casy
            TimeSpan Hashovani = hashTime2 - hashTime1;
            TimeSpan Zapis = hashTime3 - hashTime2;
            TimeSpan Celkem = hashTime3 - hashTime1;
            // Zprava
            string returnMessage = "\r\n===REGISTRACE===\r\nUživatel '" + ID + "' zaregistrován. \r\n Operace: \r\nHashování: ";
            returnMessage += Hashovani.TotalMilliseconds.ToString() + " ms";
            returnMessage += "\r\nZápis na kartu: ";
            returnMessage += Zapis.TotalMilliseconds.ToString() + " ms";
            returnMessage += "\r\nCelkem: ";
            returnMessage += Celkem.TotalMilliseconds.ToString() + " ms\r\n";
            
            //Ukonceni spojeni s kartou
            UkonciSpojeni();

            return returnMessage; //+ md5hash;
        }

        public string Login_Efficient(string ID, string PWD)
        {
            //Inicializace komunikace s kartou
            Inicializace();

            //string ID = "uziv";
            //string PWD = "heslo";
            //string x = "kkk";

            // Prekonvertuji vstupni promenne do byte
            //byte[] id2 = String2Arr(ID);
            //byte[] pwd2 = String2Arr(PWD);
            //byte[] x2 = String2Arr(x);

            DateTime LoginTime1 = DateTime.Now;
            byte[] id2 = System.Text.UTF8Encoding.UTF8.GetBytes(ID);
            byte[] pwd2 = System.Text.UTF8Encoding.UTF8.GetBytes(PWD);
            byte[] x2 = System.Text.UTF8Encoding.UTF8.GetBytes(SecretKey);

            // Vezmu si Timestamp1
            string timestamp1=DateTime.UtcNow.ToString();
            // kvuli konverzi prevedu nechtene znaky
            timestamp1 = timestamp1.Replace(".","").Replace(":","").Replace(" " ,"");
            // Overim pres kartu - Spocita se (Ri XOR PWD) XOR T
            byte[] LoginCheck = getService().Login( PWD, timestamp1);
            // Provedu hash - C2 = h((Ri XOR PWD) XOR T)
            MD5CryptoServiceProvider hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(LoginCheck);
            System.Text.StringBuilder s = new System.Text.StringBuilder();
            foreach (byte b in hash.Hash)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            string md5hash = s.ToString();
            DateTime LoginTime2 = DateTime.Now;
            // Odesilam zpravu dal
            string VerificationMessage = Verification_Efficient(ID, timestamp1, md5hash);
            DateTime LoginTime3 = DateTime.Now;

            string returnMessage = "\r\n===PŘIHLÁŠENÍ===\r\nProbíhá ověření uživatele '" + ID + "'. \r\n Operace: \r\n";
            TimeSpan Login  = LoginTime2 - LoginTime1;
            TimeSpan LoginaVerifikace  = LoginTime3 - LoginTime1;
            
            //Zprava

            returnMessage += "\r\nPřihlášení...: ";
            returnMessage += Login.TotalMilliseconds.ToString() + " ms";
            returnMessage += "\r\n\r\n" + VerificationMessage;
            returnMessage += "\r\n\r\n===CELKEM===: ";
            returnMessage += LoginaVerifikace.TotalMilliseconds.ToString() + " ms";
            return returnMessage;
        }

        public string Verification_Efficient(string IDi, string Timestamp, string C2)
        {
            //Inicializace komunikace s kartou
            Inicializace();
            DateTime VerifTime1 = DateTime.Now;
            string returnMessage = "\r\n===OVĚŘENÍ===\r\nProbíhá ověření uživatele '" + IDi + "'. \r\n Operace: \r\n";
            string timestamp2 = DateTime.UtcNow.ToString();
            timestamp2 = timestamp2.Replace(".", "").Replace(":", "").Replace(" ", "");
            // Pokud zabere proces dele nez 1s potom se jedna o opakovany utok
            returnMessage += "Kontrola časových otisků...";
            if ((Convert.ToInt64(Timestamp) - Convert.ToInt64(timestamp2)) > 1) 
            {
                returnMessage += "SELHALA\r\n";
                return returnMessage;
            }
            returnMessage += "OK\r\n";
            DateTime VerifTime2 = DateTime.Now;
            //byte[] id2 = System.Text.UTF8Encoding.UTF8.GetBytes(ID);
            //byte[] pwd2 = System.Text.UTF8Encoding.UTF8.GetBytes(PWD);
            //byte[] x2 = String2Arr(x);
            //byte[] IDi2 = String2Arr(IDi);
            
            byte[] x2 = System.Text.UTF8Encoding.UTF8.GetBytes(SecretKey);
            byte[] IDi2 = System.Text.Encoding.UTF8.GetBytes(IDi);
            
            // Provedu XOR (IDi XOR x)
            byte[] idx = XOR(IDi2,x2);

            // Provedu h(IDi XOR x)
            MD5CryptoServiceProvider hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(idx);
            System.Text.StringBuilder s = new System.Text.StringBuilder();
            foreach (byte b in hash.Hash)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            string C1_ = s.ToString();
            

            byte[] C1_2 = System.Text.Encoding.UTF8.GetBytes(C1_);
            //byte[] byte_timestamp = String2Arr(Timestamp);
            byte[] byte_timestamp = System.Text.Encoding.UTF8.GetBytes(Timestamp);
            // Provedu (C'1 XOR T)
            byte[] hC1_ = XOR(C1_2, byte_timestamp);
            // Provedu h(C'1 XOR T)
            MD5CryptoServiceProvider hash2 = new MD5CryptoServiceProvider();
            hash2.ComputeHash(hC1_);
            s = new System.Text.StringBuilder();
            foreach (byte b in hash2.Hash)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            string md5hash_c1 = s.ToString();

            // TEST Spravnosti
            //string tst_Ri = getService().GetRi();
            //string PWD = "heslo";
            //byte[] byteLogin = System.Text.Encoding.UTF8.GetBytes(tst_Ri);
            //byte[] bytePWD = System.Text.Encoding.UTF8.GetBytes(PWD);
            //byte[] xor = XOR(byteLogin, bytePWD);
            //byte[] byteTimestamp = System.Text.Encoding.UTF8.GetBytes(Timestamp);
            //byte[] tC2 = XOR(xor, byteTimestamp);
            //MD5CryptoServiceProvider hash3 = new MD5CryptoServiceProvider();
            //hash3.ComputeHash(tC2);
            //s = new System.Text.StringBuilder();
            //foreach (byte b in hash3.Hash)
            //{
            //    s.Append(b.ToString("x2").ToLower());
            //}
            //string tst_3 = s.ToString();

            DateTime VerifTime3 = DateTime.Now;
            
            returnMessage += "Kontrola Hashů C'1 a C2...";
            if (md5hash_c1 == C2) { returnMessage += "OK\r\n"; }
            else { 
                returnMessage += "SELHALA\r\n";
                return returnMessage;
            }

            // 3. bod - druhe overeni casovych otisku

            string timestamp3 = DateTime.UtcNow.ToString();
            timestamp3 = timestamp3.Replace(".", "").Replace(":", "").Replace(" ", "");
            byte[] byte_timestamp3 = System.Text.Encoding.UTF8.GetBytes(timestamp3);
            byte[] byte_md5hash_c1 = System.Text.Encoding.UTF8.GetBytes(C1_);

            // Provedu C1' XOR T''
            byte[] hC3 = XOR(byte_md5hash_c1, byte_timestamp3);
            
            // Provedu h(C1' XOR T'')
            MD5CryptoServiceProvider hash3 = new MD5CryptoServiceProvider();
            hash3.ComputeHash(hC3);
            s = new System.Text.StringBuilder();
            foreach (byte b in hash3.Hash)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            string C3 = s.ToString();

            byte[] LoginCheck = getService().Verification(timestamp3);

            // Provedu h(C1 XOR T'')
            
            MD5CryptoServiceProvider hash4 = new MD5CryptoServiceProvider();
            hash2.ComputeHash(LoginCheck);
            s = new System.Text.StringBuilder();
            foreach (byte b in hash2.Hash)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            string C3_ = s.ToString();
            
            // Kontrola
            returnMessage += "Kontrola Hashů C3 a h(C1 XOR T'')...";
            if (C3 == C3_) { returnMessage += "OK\r\n"; }
            else
            {
                returnMessage += "SELHALA\r\n";
                return returnMessage;
            }
            returnMessage += "OK\r\n";
            DateTime VerifTime4 = DateTime.Now;
            // casy
            TimeSpan Kontrola_Casu  = VerifTime2 - VerifTime1;
            TimeSpan Kontrola_C2C1_ = VerifTime3 - VerifTime2;
            TimeSpan Kontrola_C3    = VerifTime4 - VerifTime3;
            TimeSpan Celkem         = VerifTime4 - VerifTime1;
            //Zprava

            returnMessage += "\r\n\r\nT a T' (Kontrola časových otisků)...: ";
            returnMessage += Kontrola_Casu.TotalMilliseconds.ToString() + " ms";
            returnMessage += "\r\nKontrola Hashů C'1 a C2...: ";
            returnMessage += Kontrola_C2C1_.TotalMilliseconds.ToString() + " ms";
            returnMessage += "\r\nKontrola Hashů C3 a h(C1 XOR T''): ";
            returnMessage += Kontrola_C3.TotalMilliseconds.ToString() + " ms\r\n";
            returnMessage += "\r\nCelkem: ";
            returnMessage += Celkem.TotalMilliseconds.ToString() + " ms\r\n";
            return returnMessage;
        }
        
        #endregion

        #region Autentifikace Hsiang and Ahih Enhanced

        public string RemoteAutentification_Hsiang(string ID, string PWD,string b)
        {
            //Inicializace komunikace s kartou
            Inicializace();

            //string b = new Random().Next().ToString();

            //ID = "uziv";
            //PWD = "heslo";
            //b = "1";

            // Prekonvertuji vstupni promenne do byte
            //byte[] id2 = String2Arr(ID);
            //byte[] pwd2 = String2Arr(PWD);
            //byte[] x2 = String2Arr(x);
            DateTime hashTime1 = DateTime.Now;
            byte[] id2 = System.Text.UTF8Encoding.UTF8.GetBytes(ID);
            byte[] pwd2 = System.Text.UTF8Encoding.UTF8.GetBytes(PWD);
            byte[] b2 = System.Text.UTF8Encoding.UTF8.GetBytes(b);
            byte[] x2 = System.Text.UTF8Encoding.UTF8.GetBytes(SecretKey);

            // Provedu XOR operaci - Pwd XOR b
            byte[] PwdB = XOR(pwd2, b2);

            // Prevedu do md5 hashe, dalsi volba je SHA1 h(Pwd XOR b)
            MD5CryptoServiceProvider hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(PwdB);
            System.Text.StringBuilder s = new System.Text.StringBuilder();
            foreach (byte byt in hash.Hash)
            {
                s.Append(byt.ToString("x2").ToLower());
            }
            string md5hash_PwdB = s.ToString();
            byte[] byte_md5_PwdB = System.Text.UTF8Encoding.UTF8.GetBytes(md5hash_PwdB);

            // Prevedu do md5 hashe, dalsi volba je SHA1 h(Pwd)
            hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(pwd2);
            s = new System.Text.StringBuilder();
            foreach (byte byt in hash.Hash)
            {
                s.Append(byt.ToString("x2").ToLower());
            }
            string md5hash_Pwd = s.ToString();
            byte[] byte_md5_Pwd = System.Text.UTF8Encoding.UTF8.GetBytes(md5hash_Pwd);

            // Odesilam na server pro zpracovani

            // EID = h(ID||n)
            int n = getN();
            n++;
            saveN(n);
            string eid = ID + n.ToString();
            byte[] byte_eid = System.Text.UTF8Encoding.UTF8.GetBytes(eid);
            // P = h(EID xor x)
            byte[] eidxx = XOR(byte_eid, x2);
            hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(eidxx);
            s = new System.Text.StringBuilder();
            foreach (byte byt in hash.Hash)
            {
                s.Append(byt.ToString("x2").ToLower());
            }
            string md5hash_p = s.ToString();
            byte[] byte_p = System.Text.UTF8Encoding.UTF8.GetBytes(md5hash_p);

            // R = P xor h(b xor PWD)
            byte[] r_hash = XOR(b2,pwd2);
            hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(r_hash);
            s = new System.Text.StringBuilder();
            foreach (byte byt in hash.Hash)
            {
                s.Append(byt.ToString("x2").ToLower());
            }
            string md5hash_r_hash = s.ToString();
            byte[] byte_r_hash = System.Text.UTF8Encoding.UTF8.GetBytes(md5hash_r_hash);
            byte[] R = XOR(byte_p, byte_r_hash);
            string R_str = System.Text.UTF8Encoding.UTF8.GetString(R);
            // V = h(P xor h(b xor Pwd)) = h(R)
            hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(R);
            s = new System.Text.StringBuilder();
            foreach (byte byt in hash.Hash)
            {
                s.Append(byt.ToString("x2").ToLower());
            }
            string md5hash_R = s.ToString();
            byte[] V = System.Text.UTF8Encoding.UTF8.GetBytes(md5hash_R);

            DateTime hashTime2 = DateTime.Now;

            // Ulozim na kartu
            string Response = getService().Registration_Hsiang(md5hash_R, R_str, md5hash_p);
            DateTime hashTime3 = DateTime.Now;

            // casy
            TimeSpan Hashovani = hashTime2 - hashTime1;
            TimeSpan Zapis = hashTime3 - hashTime2;
            TimeSpan Celkem = hashTime3 - hashTime1;
            // Zprava
            string returnMessage = "\r\n===REGISTRACE===\r\nUživatel '" + ID + "' zaregistrován. \r\n Operace: \r\nHashování: ";
            returnMessage += Hashovani.TotalMilliseconds.ToString() + " ms";
            returnMessage += "\r\nZápis na kartu: ";
            returnMessage += Zapis.TotalMilliseconds.ToString() + " ms";
            returnMessage += "\r\nCelkem: ";
            returnMessage += Celkem.TotalMilliseconds.ToString() + " ms\r\n";

            //Ukonceni spojeni s kartou
            UkonciSpojeni();

            return returnMessage; //+ md5hash;
        }

        public string Login_Hsiang(string ID, string PWD, string b)
        {
            //Inicializace komunikace s kartou
            Inicializace();

            //ID = "uziv";
            //PWD = "heslo";
            //b = "1";
            //string x = "kkk";

            // Prekonvertuji vstupni promenne do byte
            //byte[] id2 = String2Arr(ID);
            //byte[] pwd2 = String2Arr(PWD);
            //byte[] x2 = String2Arr(x);

            DateTime LoginTime1 = DateTime.Now;
            byte[] id2 = System.Text.UTF8Encoding.UTF8.GetBytes(ID);
            byte[] pwd2 = System.Text.UTF8Encoding.UTF8.GetBytes(PWD);
            byte[] x2 = System.Text.UTF8Encoding.UTF8.GetBytes(SecretKey);

            #region Vytvorim Ri
                //Vytvorim Ri

                //string b = new Random().Next().ToString();
                byte[] b2 = System.Text.UTF8Encoding.UTF8.GetBytes(b);
                // EID = h(ID||n)
                int n = getN();
                string eid = ID + n.ToString();
                byte[] byte_eid = System.Text.UTF8Encoding.UTF8.GetBytes(eid);
                // P = h(EID xor x)
                byte[] eidxx = XOR(byte_eid, x2);
                MD5CryptoServiceProvider hash = new MD5CryptoServiceProvider();
                hash.ComputeHash(eidxx);
                System.Text.StringBuilder s = new System.Text.StringBuilder();
                foreach (byte byt in hash.Hash)
                {
                    s.Append(byt.ToString("x2").ToLower());
                }
                string md5hash_p = s.ToString();
                byte[] byte_p = System.Text.UTF8Encoding.UTF8.GetBytes(md5hash_p);

                // R = P xor h(b xor PWD)
                byte[] r_hash = XOR(b2, pwd2);
                hash = new MD5CryptoServiceProvider();
                hash.ComputeHash(r_hash);
                s = new System.Text.StringBuilder();
                foreach (byte byt in hash.Hash)
                {
                    s.Append(byt.ToString("x2").ToLower());
                }
                string md5hash_r_hash = s.ToString();
                byte[] byte_r_hash = System.Text.UTF8Encoding.UTF8.GetBytes(md5hash_r_hash);
                byte[] R = XOR(byte_p, byte_r_hash);
            #endregion

            #region Vytvorim V h(P xor h(b xor Pwd)) = h(R)
                // V = h(P xor h(b xor Pwd)) = h(R)
                hash = new MD5CryptoServiceProvider();
                hash.ComputeHash(R);
                s = new System.Text.StringBuilder();
                foreach (byte byt in hash.Hash)
                {
                    s.Append(byt.ToString("x2").ToLower());
                }
                string V = s.ToString();
                byte[] byte_V = System.Text.UTF8Encoding.UTF8.GetBytes(V);
            #endregion

            #region Timestamp1 - Tu
                // Vezmu si Timestamp1
                string timestamp1 = DateTime.UtcNow.ToString();
                timestamp1 += DateTime.UtcNow.Millisecond.ToString();
                // kvuli konverzi prevedu nechtene znaky
                timestamp1 = timestamp1.Replace(".", "").Replace(":", "").Replace(" ", "");
            #endregion
            
            // Overim pres kartu - Zpatky dostavam C2,Tu,Ri
                string[] LoginCheck = getService().Login_Hsiang(byte_r_hash,timestamp1);
            byte[] C2 = System.Text.UTF8Encoding.UTF8.GetBytes(LoginCheck[0]);
            byte[] V_2 = System.Text.UTF8Encoding.UTF8.GetBytes(LoginCheck[2]);
            
            string returnMessage = "\r\n===PŘIHLÁŠENÍ===\r\nProbíhá ověření uživatele '" + ID + "'. \r\n Operace: \r\n";
            if (V == LoginCheck[2])
            {
                returnMessage += "\r\nKontrola V...: OK";
            }
            else{
                returnMessage += "\r\nKontrola V...: FAIL";
            }
            #region Hash C2 = h(C1||Ri||Tu)
                // Provedu hash - C2 = h((Ri XOR PWD) XOR T)
            string R_str = System.Text.UTF8Encoding.UTF8.GetString(R);
                //string C2_str = System.Text.UTF8Encoding.UTF8.GetString(C2);
                //string C1RiTu = C2_str + R_str + timestamp1;
                //byte[] C1RiTu_byte = System.Text.UTF8Encoding.UTF8.GetBytes(C1RiTu);
                hash = new MD5CryptoServiceProvider();
                hash.ComputeHash(C2);
                s = new System.Text.StringBuilder();
                foreach (byte byt in hash.Hash)
                {
                    s.Append(byt.ToString("x2").ToLower());
                }
                string md5hash = s.ToString();
            #endregion

            DateTime LoginTime2 = DateTime.Now;
            // Odesilam zpravu dal
            string VerificationMessage = Verification_Hsiang(ID, timestamp1, md5hash, R_str, byte_r_hash);
            DateTime LoginTime3 = DateTime.Now;

            
            TimeSpan Login = LoginTime2 - LoginTime1;
            TimeSpan LoginaVerifikace = LoginTime3 - LoginTime1;

            //Zprava

            returnMessage += "\r\nPřihlášení...: ";
            returnMessage += Login.TotalMilliseconds.ToString() + " ms";
            returnMessage += "\r\n\r\n" + VerificationMessage;
            returnMessage += "\r\n\r\n===CELKEM===: ";
            returnMessage += LoginaVerifikace.TotalMilliseconds.ToString() + " ms";
            return returnMessage;
        }

        public string Verification_Hsiang(string IDi, string Timestamp, string C2, string Ri, byte[] pwdb)
        {
            //Inicializace komunikace s kartou
            Inicializace();
            DateTime VerifTime1 = DateTime.Now;
            string returnMessage = "\r\n===OVĚŘENÍ===\r\nProbíhá ověření uživatele '" + IDi + "'. \r\n Operace: \r\n";
            
            #region Kontrola casu
                string timestamp2 = DateTime.UtcNow.ToString();
                timestamp2 += DateTime.UtcNow.Millisecond.ToString();
                timestamp2 = timestamp2.Replace(".", "").Replace(":", "").Replace(" ", "");
                // Pokud zabere proces dele nez 1s potom se jedna o opakovany utok, pokud je stejny, potom je to paralelni utok
                returnMessage += "Kontrola časových otisků...";
                if ((Convert.ToInt64(Timestamp) - Convert.ToInt64(timestamp2)) < 1000 && Convert.ToInt64(Timestamp) == Convert.ToInt64(timestamp2))
                {
                    returnMessage += "SELHALA\r\n";
                    return returnMessage;
                }
                returnMessage += "OK\r\n";
            #endregion
            DateTime VerifTime2 = DateTime.Now;
            //byte[] id2 = System.Text.UTF8Encoding.UTF8.GetBytes(ID);
            //byte[] pwd2 = System.Text.UTF8Encoding.UTF8.GetBytes(PWD);
            //byte[] x2 = String2Arr(x);
            //byte[] IDi2 = String2Arr(IDi);

            #region h(EID XOR x)
                byte[] x2 = System.Text.UTF8Encoding.UTF8.GetBytes(SecretKey);
                byte[] IDi2 = System.Text.Encoding.UTF8.GetBytes(IDi);

                // Provedu h(EID XOR x)
                int n = getN();
                string eid = IDi + n.ToString();
                byte[] byte_eid = System.Text.UTF8Encoding.UTF8.GetBytes(eid);
                // P = h(EID xor x)
                byte[] eidxx = XOR(byte_eid, x2);
                MD5CryptoServiceProvider hash = new MD5CryptoServiceProvider();
                hash.ComputeHash(eidxx);
                System.Text.StringBuilder s = new System.Text.StringBuilder();
                foreach (byte byt in hash.Hash)
                {
                    s.Append(byt.ToString("x2").ToLower());
                }
                string md5hash_p = s.ToString();
                byte[] byte_p = System.Text.UTF8Encoding.UTF8.GetBytes(md5hash_p);
            #endregion

            #region C2'
                string C2_ = md5hash_p + Ri + Timestamp;
                byte[] byte_C2_ = System.Text.UTF8Encoding.UTF8.GetBytes(C2_);
                hash = new MD5CryptoServiceProvider();
                hash.ComputeHash(byte_C2_);
                s = new System.Text.StringBuilder();
                foreach (byte byt in hash.Hash)
                {
                    s.Append(byt.ToString("x2").ToLower());
                }
                C2_ = s.ToString();
            #endregion

            returnMessage += "Kontrola Hashů C'2 a C2...";
            if (C2 == C2_) { returnMessage += "OK\r\n"; }
            else
            {
                returnMessage += "SELHALA\r\n";
                return returnMessage;
            }
            DateTime VerifTime3 = DateTime.Now;
            // 3. bod - druhe overeni casovych otisku
            #region C3
            byte[] timestamp_byte = System.Text.Encoding.UTF8.GetBytes(timestamp2);
            hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(timestamp_byte);
            s = new System.Text.StringBuilder();
            foreach (byte b in hash.Hash)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            string hTs = s.ToString();
            string C3 = md5hash_p + hTs;
            byte[] C3_byte = System.Text.Encoding.UTF8.GetBytes(C3);
            hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(C3_byte);
            s = new System.Text.StringBuilder();
            foreach (byte b in hash.Hash)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            C3 = s.ToString();
            #endregion


            #region C3'
                byte[] byte_C1 = getService().Verification_Hsiang(pwdb);
                string C1 = System.Text.Encoding.UTF8.GetString(byte_C1);
                string C3_ = C1 + hTs;
                byte[] byte_c3_ = System.Text.Encoding.UTF8.GetBytes(C3_);
                hash = new MD5CryptoServiceProvider();
                hash.ComputeHash(byte_c3_);
                s = new System.Text.StringBuilder();
                foreach (byte b in hash.Hash)
                {
                    s.Append(b.ToString("x2").ToLower());
                }
                C3_ = s.ToString();
            #endregion

                
            // Kontrola
            returnMessage += "Kontrola Hashů C3 a h(C1 XOR Ts)...";
            if (C3 == C3_) { returnMessage += "OK\r\n"; }
            else
            {
                returnMessage += "SELHALA\r\n";
                return returnMessage;
            }
            returnMessage += "OK\r\n";
            DateTime VerifTime4 = DateTime.Now;

            string Token = C1 + Ri + Timestamp + hTs;
            byte[] byte_token = System.Text.Encoding.UTF8.GetBytes(Token);
            hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(byte_token);
            s = new System.Text.StringBuilder();
            foreach (byte b in hash.Hash)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            Token = s.ToString();
            DateTime VerifTime5 = DateTime.Now;
            // casy
            TimeSpan Kontrola_Casu = VerifTime2 - VerifTime1;
            TimeSpan Kontrola_C2C1_ = VerifTime3 - VerifTime2;
            TimeSpan Kontrola_C3 = VerifTime4 - VerifTime3;
            TimeSpan Kontrola_Token = VerifTime5 - VerifTime4;
            TimeSpan Celkem = VerifTime5 - VerifTime1;
            //Zprava

            

            returnMessage += "\r\n\r\nT a T' (Kontrola časových otisků)...: ";
            returnMessage += Kontrola_Casu.TotalMilliseconds.ToString() + " ms";
            returnMessage += "\r\nKontrola Hashů C'1 a C2...: ";
            returnMessage += Kontrola_C2C1_.TotalMilliseconds.ToString() + " ms";
            returnMessage += "\r\nKontrola Hashů C3 a h(C1 XOR Ts): ";
            returnMessage += Kontrola_C3.TotalMilliseconds.ToString() + " ms\r\n";
            returnMessage += "\r\nTvorba Session Token h(C1||Ri||Tu||(hTs)): ";
            returnMessage += Kontrola_Token.TotalMilliseconds.ToString() + " ms\r\n";
            returnMessage += "\r\nCelkem: ";
            returnMessage += Celkem.TotalMilliseconds.ToString() + " ms\r\n";
            returnMessage += "\r\nToken Hashs: " + Token;
            return returnMessage;
        }

        public int getN()
        {
            int n = 0;
            if (File.Exists("n.txt"))
            {
                System.IO.StreamReader Filen = new System.IO.StreamReader("n.txt");
                n = Convert.ToInt32(Filen.ReadToEnd());
                Filen.Close();
            }
            return n;
        }

        public void saveN(int n)
        {
            System.IO.StreamWriter FileRi = new System.IO.StreamWriter("n.txt");
            FileRi.Write(n);
            FileRi.Close();
        }

        #endregion

        #region Autentifikace Improved

        public string RemoteAutentification_Improved(string ID, string PWD)
        {
            //Inicializace komunikace s kartou
            Inicializace();
            //http://www.wolframalpha.com/input/?i=primitiveroot[1999]&a=ClashPrefs_*MathWorld.PrimitiveRoot-
            //Velke prvocislo
            BigInteger p = 1999;
            //Primitive element
            BigInteger g = 3;

            DateTime hashTime1 = DateTime.Now;
            //byte[] id2 = System.Text.UTF8Encoding.UTF8.GetBytes(ID);

            byte[] id2 = System.Text.UTF8Encoding.UTF8.GetBytes(ID);
            byte[] pwd2 = System.Text.UTF8Encoding.UTF8.GetBytes(PWD);
            byte[] x2 = System.Text.UTF8Encoding.UTF8.GetBytes(SecretKey);

            byte[] idx = System.Text.UTF8Encoding.UTF8.GetBytes(ID + SecretKey);
            int A = (ID + SecretKey).GetHashCode();
            //int hID = ID.GetHashCode();
            //int hPWD = PWD.GetHashCode();
            //int regid = intsKey * hID + hPWD;
            //BigInteger g = 3;

            // B = g^Ah(PW) mod p
            BigInteger exp = Math.Abs(A * PWD.GetHashCode());
            BigInteger B = g.modPow(exp,p);
            //MD5 hash pro A
            //MD5CryptoServiceProvider hash = new MD5CryptoServiceProvider();
            //hash.ComputeHash(idx);
            //System.Text.StringBuilder s = new System.Text.StringBuilder();
            //foreach (byte b in hash.Hash)
            //{
            //    s.Append(b.ToString("x2").ToLower());
            //}
            //string A = s.ToString();
            //byte[] byte_md5 = System.Text.UTF8Encoding.UTF8.GetBytes(A);
            //string A = md5hash;

            DateTime hashTime2 = DateTime.Now;
            string A_byte = A.ToString();
            byte[] B_byte = System.Text.UTF8Encoding.UTF8.GetBytes(B.ToString()); //B.getBytes();
            // Ulozim na kartu
            string Response = getService().Registration_Improved(ID, A.ToString(), B.ToString(), p.ToString(), g.ToString());

            DateTime hashTime3 = DateTime.Now;

            // casy
            TimeSpan Hashovani = hashTime2 - hashTime1;
            TimeSpan Zapis = hashTime3 - hashTime2;
            TimeSpan Celkem = hashTime3 - hashTime1;
            // Zprava
            string returnMessage = "\r\n===REGISTRACE===\r\nUživatel '" + ID + "' zaregistrován. \r\n Operace: \r\nHashování: ";
            returnMessage += Hashovani.TotalMilliseconds.ToString() + " ms";
            returnMessage += "\r\nZápis na kartu: ";
            returnMessage += Zapis.TotalMilliseconds.ToString() + " ms";
            returnMessage += "\r\nCelkem: ";
            returnMessage += Celkem.TotalMilliseconds.ToString() + " ms\r\n";

            //Ukonceni spojeni s kartou
            UkonciSpojeni();

            return returnMessage; //+ md5hash;
        }

        public string Login_Improved(string ID, string PWD, string b)
        {
            //Inicializace komunikace s kartou
            Inicializace();

            //ID = "uziv";
            //PWD = "heslo";
            //b = "1";
            //string x = "kkk";
            
            // Prekonvertuji vstupni promenne do byte
            //byte[] id2 = String2Arr(ID);
            //byte[] pwd2 = String2Arr(PWD);
            //byte[] x2 = String2Arr(x);

            DateTime LoginTime1 = DateTime.Now;

            string[] SmartCard = getService().Login_Improved();
            int A = Convert.ToInt32(SmartCard[1]);
            //byte[] B_byte = System.Text.UTF8Encoding.UTF8.GetBytes(SmartCard[2]);
            BigInteger B = new BigInteger(Convert.ToUInt32( SmartCard[2]));
            BigInteger p = new BigInteger( Convert.ToUInt32(SmartCard[3]));
            BigInteger g = new BigInteger(Convert.ToUInt32(SmartCard[4]));

            BigInteger exp = Math.Abs(A * PWD.GetHashCode());
            BigInteger B_2 = g.modPow(exp, p);
            string BCheck = "";
            if (B == B_2)
            {
                BCheck = "OK";
            }
            else
            {
                BCheck = "SELHALA";
            }

            BigInteger Z = B * (A %p);
            
            string timestamp1 = "";
                
                #region Timestamp1 - Tu
                // Vezmu si Timestamp1
                timestamp1 = DateTime.UtcNow.ToString();
                timestamp1 += DateTime.UtcNow.Millisecond.ToString();
                // kvuli konverzi prevedu nechtene znaky
                timestamp1 = timestamp1.Replace(".", "").Replace(":", "").Replace(" ", "");
                #endregion
            byte[] T_byte = System.Text.UTF8Encoding.UTF8.GetBytes(timestamp1);
            //byte[] B_byte = B.getBytes();

            byte[] TxorB = XOR(T_byte,B.getBytes());

            //MD5 hash pro A
            MD5CryptoServiceProvider hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(TxorB);
            System.Text.StringBuilder s = new System.Text.StringBuilder();
            foreach (byte byt in hash.Hash)
            {
                s.Append(byt.ToString("x2").ToLower());
            }
            string C_1 = s.ToString();
            //byte[] byte_md5 = System.Text.UTF8Encoding.UTF8.GetBytes(A);

            string returnMessage = "\r\n===PŘIHLÁŠENÍ===\r\nProbíhá ověření uživatele '" + ID + "'. \r\n Operace: \r\n";

            DateTime LoginTime2 = DateTime.Now;
            // Odesilam zpravu dal
            string VerificationMessage = Verification_Improved(ID, timestamp1, Z, C_1);
            DateTime LoginTime3 = DateTime.Now;


            TimeSpan Login = LoginTime2 - LoginTime1;
            TimeSpan LoginaVerifikace = LoginTime3 - LoginTime1;

            //Zprava

            returnMessage += "\r\nPřihlášení...: ";
            returnMessage += Login.TotalMilliseconds.ToString() + " ms";
            returnMessage += "\r\n\r\nKontrola B' a B...";
            returnMessage += BCheck + "\r\n";
            returnMessage += VerificationMessage;
            returnMessage += "\r\n\r\n===CELKEM===: ";
            returnMessage += LoginaVerifikace.TotalMilliseconds.ToString() + " ms";
            return returnMessage;
        }

        public string Verification_Improved(string IDi, string Timestamp, BigInteger Z, string C_1)
        {
            //Inicializace komunikace s kartou
            Inicializace();
            DateTime VerifTime1 = DateTime.Now;
            string returnMessage = "\r\n===OVĚŘENÍ===\r\nProbíhá ověření uživatele '" + IDi + "'. \r\n Operace: \r\n";

            #region Kontrola casu
            string timestamp2 = DateTime.UtcNow.ToString();
            timestamp2 += DateTime.UtcNow.Millisecond.ToString();
            timestamp2 = timestamp2.Replace(".", "").Replace(":", "").Replace(" ", "");
            // Pokud zabere proces dele nez 1s potom se jedna o opakovany utok, pokud je stejny, potom je to paralelni utok
            returnMessage += "Kontrola časových otisků...";
            if ((Convert.ToInt64(Timestamp) - Convert.ToInt64(timestamp2)) > 1000 && Convert.ToInt64(Timestamp) == Convert.ToInt64(timestamp2))
            {
                returnMessage += "SELHALA\r\n";
                return returnMessage;
            }
            returnMessage += "OK\r\n";
            #endregion
            DateTime VerifTime2 = DateTime.Now;
            
            string[] SmartCard = getService().Login_Improved();
            int A = Convert.ToInt32(SmartCard[1]);
            //byte[] B_byte = System.Text.UTF8Encoding.UTF8.GetBytes(SmartCard[2]);
            BigInteger B = new BigInteger(Convert.ToUInt32(SmartCard[2]));
            int p = Convert.ToInt32(SmartCard[3]);
            int g = Convert.ToInt32(SmartCard[4]);

            int A_2 = (IDi + SecretKey).GetHashCode();
            BigInteger B_2 = Z / (A_2 % p);
            byte[] B_2_byte = B_2.getBytes();
            byte[] timestamp_byte = System.Text.Encoding.UTF8.GetBytes(Timestamp);
            byte[] TxorB = XOR(timestamp_byte, B_2_byte);

            MD5CryptoServiceProvider hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(TxorB);
            System.Text.StringBuilder s = new System.Text.StringBuilder();
            foreach (byte b in hash.Hash)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            string C_1_2 = s.ToString();

            returnMessage += "Kontrola Hashů C'1 a C1...";
            if (C_1 == C_1_2) { returnMessage += "OK\r\n"; }
            else
            {
                returnMessage += "SELHALA\r\n";
                return returnMessage;
            }
            

            DateTime VerifTime3 = DateTime.Now;

            DateTime VerifTime4 = DateTime.Now;

            DateTime VerifTime5 = DateTime.Now;
            // casy
            TimeSpan Kontrola_Casu = VerifTime2 - VerifTime1;
            TimeSpan Kontrola_C2C1_ = VerifTime3 - VerifTime2;
            //TimeSpan Kontrola_C3 = VerifTime4 - VerifTime3;
            //TimeSpan Kontrola_Token = VerifTime5 - VerifTime4;
            TimeSpan Celkem = VerifTime3 - VerifTime1;
            //Zprava



            returnMessage += "\r\n\r\nT a T' (Kontrola časových otisků)...: ";
            returnMessage += Kontrola_Casu.TotalMilliseconds.ToString() + " ms";
            returnMessage += "\r\nKontrola Hashů C'1 a C1...: ";
            returnMessage += Kontrola_C2C1_.TotalMilliseconds.ToString() + " ms";
            //returnMessage += "\r\nKontrola Hashů C3 a h(C1 XOR T''): ";
            //returnMessage += Kontrola_C3.TotalMilliseconds.ToString() + " ms\r\n";
            //returnMessage += "\r\nTvorba Session Token h(C1||Ri||Tu||(hTs)): ";
            //returnMessage += Kontrola_Token.TotalMilliseconds.ToString() + " ms\r\n";
            returnMessage += "\r\nCelkem: ";
            returnMessage += Celkem.TotalMilliseconds.ToString() + " ms\r\n";
            //returnMessage += "\r\nToken Hashs: " + Token;
            return returnMessage;
        }



        #endregion

        #region Nova autentifikace
        
        public string RemoteAutentification_nova(string ID, string PWD, string b)
        {
            //Inicializace komunikace s kartou
            Inicializace();

            //string b = new Random().Next().ToString();

            //ID = "uziv";
            //PWD = "heslo";
            //b = "1";

            // Prekonvertuji vstupni promenne do byte
            //byte[] id2 = String2Arr(ID);
            //byte[] pwd2 = String2Arr(PWD);
            //byte[] x2 = String2Arr(x);
            DateTime hashTime1 = DateTime.Now;
            byte[] id2 = System.Text.UTF8Encoding.UTF8.GetBytes(ID);
            byte[] pwd2 = System.Text.UTF8Encoding.UTF8.GetBytes(PWD);
            byte[] b2 = System.Text.UTF8Encoding.UTF8.GetBytes(b);
            byte[] x2 = System.Text.UTF8Encoding.UTF8.GetBytes(SecretKey);

            // Provedu XOR operaci - Pwd XOR b
            byte[] PwdB = XOR(pwd2, b2);

            // Prevedu do md5 hashe, dalsi volba je SHA1 h(Pwd XOR b)
            MD5CryptoServiceProvider hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(PwdB);
            System.Text.StringBuilder s = new System.Text.StringBuilder();
            foreach (byte byt in hash.Hash)
            {
                s.Append(byt.ToString("x2").ToLower());
            }
            string md5hash_PwdB = s.ToString();
            byte[] byte_md5_PwdB = System.Text.UTF8Encoding.UTF8.GetBytes(md5hash_PwdB);

            // Prevedu do md5 hashe, dalsi volba je SHA1 h(Pwd)
            hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(pwd2);
            s = new System.Text.StringBuilder();
            foreach (byte byt in hash.Hash)
            {
                s.Append(byt.ToString("x2").ToLower());
            }
            string md5hash_Pwd = s.ToString();
            byte[] byte_md5_Pwd = System.Text.UTF8Encoding.UTF8.GetBytes(md5hash_Pwd);

            // Odesilam na server pro zpracovani

            // EID = h(ID||n)
            int n = getN();
            n++;
            saveN(n);
            string eid = ID + n.ToString();
            byte[] byte_eid = System.Text.UTF8Encoding.UTF8.GetBytes(eid);
            // P = h(EID xor x)
            byte[] eidxx = XOR(byte_eid, x2);
            hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(eidxx);
            s = new System.Text.StringBuilder();
            foreach (byte byt in hash.Hash)
            {
                s.Append(byt.ToString("x2").ToLower());
            }
            string md5hash_p = s.ToString();
            byte[] byte_p = System.Text.UTF8Encoding.UTF8.GetBytes(md5hash_p);

            // R = P xor h(b xor PWD)
            byte[] r_hash = XOR(b2, pwd2);
            hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(r_hash);
            s = new System.Text.StringBuilder();
            foreach (byte byt in hash.Hash)
            {
                s.Append(byt.ToString("x2").ToLower());
            }
            string md5hash_r_hash = s.ToString();
            byte[] byte_r_hash = System.Text.UTF8Encoding.UTF8.GetBytes(md5hash_r_hash);
            byte[] R = XOR(byte_p, byte_r_hash);
            string R_str = System.Text.UTF8Encoding.UTF8.GetString(R);
            // V = h(P xor h(b xor Pwd)) = h(R)
            hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(R);
            s = new System.Text.StringBuilder();
            foreach (byte byt in hash.Hash)
            {
                s.Append(byt.ToString("x2").ToLower());
            }
            string md5hash_R = s.ToString();
            byte[] V = System.Text.UTF8Encoding.UTF8.GetBytes(md5hash_R);

            DateTime hashTime2 = DateTime.Now;

            // Ulozim na kartu
            string Response = getService().Registration_nova(md5hash_R, R_str, md5hash_p);
            DateTime hashTime3 = DateTime.Now;

            // casy
            TimeSpan Hashovani = hashTime2 - hashTime1;
            TimeSpan Zapis = hashTime3 - hashTime2;
            TimeSpan Celkem = hashTime3 - hashTime1;
            // Zprava
            string returnMessage = "\r\n===REGISTRACE===\r\nUživatel '" + ID + "' zaregistrován. \r\n Operace: \r\nHashování: ";
            returnMessage += Hashovani.TotalMilliseconds.ToString() + " ms";
            returnMessage += "\r\nZápis na kartu: ";
            returnMessage += Zapis.TotalMilliseconds.ToString() + " ms";
            returnMessage += "\r\nCelkem: ";
            returnMessage += Celkem.TotalMilliseconds.ToString() + " ms\r\n";

            //Ukonceni spojeni s kartou
            UkonciSpojeni();

            return returnMessage; //+ md5hash;
        }

        public string Login_nova(string ID, string PWD, string b)
        {
            //Inicializace komunikace s kartou
            Inicializace();

            //ID = "uziv";
            //PWD = "heslo";
            //b = "1";
            //string x = "kkk";

            // Prekonvertuji vstupni promenne do byte
            //byte[] id2 = String2Arr(ID);
            //byte[] pwd2 = String2Arr(PWD);
            //byte[] x2 = String2Arr(x);

            DateTime LoginTime1 = DateTime.Now;
            byte[] id2 = System.Text.UTF8Encoding.UTF8.GetBytes(ID);
            byte[] pwd2 = System.Text.UTF8Encoding.UTF8.GetBytes(PWD);
            byte[] x2 = System.Text.UTF8Encoding.UTF8.GetBytes(SecretKey);

            #region Vytvorim Ri
            //Vytvorim Ri

            //string b = new Random().Next().ToString();
            byte[] b2 = System.Text.UTF8Encoding.UTF8.GetBytes(b);
            // EID = h(ID||n)
            int n = getN();
            string eid = ID + n.ToString();
            byte[] byte_eid = System.Text.UTF8Encoding.UTF8.GetBytes(eid);
            // P = h(EID xor x)
            byte[] eidxx = XOR(byte_eid, x2);
            MD5CryptoServiceProvider hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(eidxx);
            System.Text.StringBuilder s = new System.Text.StringBuilder();
            foreach (byte byt in hash.Hash)
            {
                s.Append(byt.ToString("x2").ToLower());
            }
            string md5hash_p = s.ToString();
            byte[] byte_p = System.Text.UTF8Encoding.UTF8.GetBytes(md5hash_p);

            // R = P xor h(b xor PWD)
            byte[] r_hash = XOR(b2, pwd2);
            hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(r_hash);
            s = new System.Text.StringBuilder();
            foreach (byte byt in hash.Hash)
            {
                s.Append(byt.ToString("x2").ToLower());
            }
            string md5hash_r_hash = s.ToString();
            byte[] byte_r_hash = System.Text.UTF8Encoding.UTF8.GetBytes(md5hash_r_hash);
            byte[] R = XOR(byte_p, byte_r_hash);
            #endregion

            #region Vytvorim V h(P xor h(b xor Pwd)) = h(R)
            // V = h(P xor h(b xor Pwd)) = h(R)
            hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(R);
            s = new System.Text.StringBuilder();
            foreach (byte byt in hash.Hash)
            {
                s.Append(byt.ToString("x2").ToLower());
            }
            string V = s.ToString();
            byte[] byte_V = System.Text.UTF8Encoding.UTF8.GetBytes(V);
            #endregion

            #region Timestamp1 - Tu
            // Vezmu si Timestamp1
            string timestamp1 = DateTime.UtcNow.ToString();
            timestamp1 += DateTime.UtcNow.Millisecond.ToString();
            // kvuli konverzi prevedu nechtene znaky
            timestamp1 = timestamp1.Replace(".", "").Replace(":", "").Replace(" ", "");
            #endregion

            // Overim pres kartu - Zpatky dostavam C2,Tu,Ri
            string[] LoginCheck = getService().Login_nova(byte_r_hash, timestamp1);
            byte[] C2 = System.Text.UTF8Encoding.UTF8.GetBytes(LoginCheck[0]);
            byte[] V_2 = System.Text.UTF8Encoding.UTF8.GetBytes(LoginCheck[2]);

            string returnMessage = "\r\n===PŘIHLÁŠENÍ===\r\nProbíhá ověření uživatele '" + ID + "'. \r\n Operace: \r\n";
            if (V == LoginCheck[2])
            {
                returnMessage += "\r\nKontrola V...: OK";
            }
            else
            {
                returnMessage += "\r\nKontrola V...: FAIL";
            }
            #region Hash C2 = h(C1||Ri||Tu)
            // Provedu hash - C2 = h((Ri XOR PWD) XOR T)
            string R_str = System.Text.UTF8Encoding.UTF8.GetString(R);
            //string C2_str = System.Text.UTF8Encoding.UTF8.GetString(C2);
            //string C1RiTu = C2_str + R_str + timestamp1;
            //byte[] C1RiTu_byte = System.Text.UTF8Encoding.UTF8.GetBytes(C1RiTu);
            hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(C2);
            s = new System.Text.StringBuilder();
            foreach (byte byt in hash.Hash)
            {
                s.Append(byt.ToString("x2").ToLower());
            }
            string md5hash = s.ToString();
            #endregion

            DateTime LoginTime2 = DateTime.Now;
            // Odesilam zpravu dal
            string VerificationMessage = Verification_nova(ID, timestamp1, md5hash, R_str, byte_r_hash);
            DateTime LoginTime3 = DateTime.Now;


            TimeSpan Login = LoginTime2 - LoginTime1;
            TimeSpan LoginaVerifikace = LoginTime3 - LoginTime1;

            //Zprava

            returnMessage += "\r\nPřihlášení...: ";
            returnMessage += Login.TotalMilliseconds.ToString() + " ms";
            returnMessage += "\r\n\r\n" + VerificationMessage;
            returnMessage += "\r\n\r\n===CELKEM===: ";
            returnMessage += LoginaVerifikace.TotalMilliseconds.ToString() + " ms";
            return returnMessage;
        }

        public string Verification_nova(string IDi, string Timestamp, string C2, string Ri, byte[] pwdb)
        {
            //Inicializace komunikace s kartou
            Inicializace();
            DateTime VerifTime1 = DateTime.Now;
            string returnMessage = "\r\n===OVĚŘENÍ===\r\nProbíhá ověření uživatele '" + IDi + "'. \r\n Operace: \r\n";

            #region Kontrola casu
            string timestamp2 = DateTime.UtcNow.ToString();
            timestamp2 += DateTime.UtcNow.Millisecond.ToString();
            timestamp2 = timestamp2.Replace(".", "").Replace(":", "").Replace(" ", "");
            // Pokud zabere proces dele nez 1s potom se jedna o opakovany utok, pokud je stejny, potom je to paralelni utok
            returnMessage += "Kontrola časových otisků...";
            if ((Convert.ToInt64(Timestamp) - Convert.ToInt64(timestamp2)) > 1000 && Convert.ToInt64(Timestamp) == Convert.ToInt64(timestamp2))
            {
                returnMessage += "SELHALA\r\n";
                return returnMessage;
            }
            returnMessage += "OK\r\n";
            #endregion
            DateTime VerifTime2 = DateTime.Now;
            //byte[] id2 = System.Text.UTF8Encoding.UTF8.GetBytes(ID);
            //byte[] pwd2 = System.Text.UTF8Encoding.UTF8.GetBytes(PWD);
            //byte[] x2 = String2Arr(x);
            //byte[] IDi2 = String2Arr(IDi);

            #region h(EID XOR x)
            byte[] x2 = System.Text.UTF8Encoding.UTF8.GetBytes(SecretKey);
            byte[] IDi2 = System.Text.Encoding.UTF8.GetBytes(IDi);

            // Provedu h(EID XOR x)
            int n = getN();
            string eid = IDi + n.ToString();
            byte[] byte_eid = System.Text.UTF8Encoding.UTF8.GetBytes(eid);
            // P = h(EID xor x)
            byte[] eidxx = XOR(byte_eid, x2);
            MD5CryptoServiceProvider hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(eidxx);
            System.Text.StringBuilder s = new System.Text.StringBuilder();
            foreach (byte byt in hash.Hash)
            {
                s.Append(byt.ToString("x2").ToLower());
            }
            string md5hash_p = s.ToString();
            byte[] byte_p = System.Text.UTF8Encoding.UTF8.GetBytes(md5hash_p);
            #endregion

            #region C2'
            string C2_ = md5hash_p + Ri + Timestamp;
            byte[] byte_C2_ = System.Text.UTF8Encoding.UTF8.GetBytes(C2_);
            hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(byte_C2_);
            s = new System.Text.StringBuilder();
            foreach (byte byt in hash.Hash)
            {
                s.Append(byt.ToString("x2").ToLower());
            }
            C2_ = s.ToString();
            #endregion

            returnMessage += "Kontrola Hashů C'2 a C2...";
            if (C2 == C2_) { returnMessage += "OK\r\n"; }
            else
            {
                returnMessage += "SELHALA\r\n";
                return returnMessage;
            }
            DateTime VerifTime3 = DateTime.Now;
            
            // 3. - druhe overeni casovych otisku
            #region C3
            byte[] timestamp_byte = System.Text.Encoding.UTF8.GetBytes(timestamp2);
            hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(timestamp_byte);
            s = new System.Text.StringBuilder();
            foreach (byte b in hash.Hash)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            string hTs = s.ToString();
            string C3 = md5hash_p + hTs;
            byte[] C3_byte = System.Text.Encoding.UTF8.GetBytes(C3);
            hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(C3_byte);
            s = new System.Text.StringBuilder();
            foreach (byte b in hash.Hash)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            C3 = s.ToString();
            #endregion


            #region C3'
            byte[] byte_C1 = getService().Verification_nova(pwdb);
            string C1 = System.Text.Encoding.UTF8.GetString(byte_C1);
            string C3_ = C1 + hTs;
            byte[] byte_c3_ = System.Text.Encoding.UTF8.GetBytes(C3_);
            hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(byte_c3_);
            s = new System.Text.StringBuilder();
            foreach (byte b in hash.Hash)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            C3_ = s.ToString();
            #endregion


            // Kontrola
            returnMessage += "Kontrola Hashů C3 a h(C1 XOR Ts)...";
            if (C3 == C3_) { returnMessage += "OK\r\n"; }
            else
            {
                returnMessage += "SELHALA\r\n";
                return returnMessage;
            }
            //returnMessage += "OK\r\n";
            DateTime VerifTime4 = DateTime.Now;

            // Nove overeni
            string timestamp3 = DateTime.UtcNow.ToString();
            timestamp3 = timestamp3.Replace(".", "").Replace(":", "").Replace(" ", "");
            byte[] byte_timestamp3 = System.Text.Encoding.UTF8.GetBytes(timestamp3);
            byte[] byte_md5hash_c1 = System.Text.Encoding.UTF8.GetBytes(C2_);

            // Provedu C1' XOR T''
            byte[] Ri_byte = System.Text.Encoding.UTF8.GetBytes(Ri);
            byte[] hC3 = XOR(Ri_byte, byte_timestamp3);

            // Provedu h(C1' XOR T'')
            MD5CryptoServiceProvider hash3 = new MD5CryptoServiceProvider();
            hash3.ComputeHash(hC3);
            s = new System.Text.StringBuilder();
            foreach (byte b in hash3.Hash)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            string C4 = s.ToString();

            byte[] LoginCheck = getService().GetR_nova(timestamp3);

            // Provedu h(C1 XOR T'')
            MD5CryptoServiceProvider hash4 = new MD5CryptoServiceProvider();
            hash4.ComputeHash(LoginCheck);
            s = new System.Text.StringBuilder();
            foreach (byte b in hash4.Hash)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            string C4_ = s.ToString();

            // Kontrola
            returnMessage += "Kontrola Hashů C4 a h(Ri XOR T'')...";
            if (C4 == C4_) { returnMessage += "OK\r\n"; }
            else
            {
                returnMessage += "SELHALA\r\n";
                return returnMessage;
            }
            returnMessage += "OK\r\n";
            DateTime VerifTime5 = DateTime.Now;

            string Token = C1 + Ri + Timestamp + hTs;
            byte[] byte_token = System.Text.Encoding.UTF8.GetBytes(Token);
            hash = new MD5CryptoServiceProvider();
            hash.ComputeHash(byte_token);
            s = new System.Text.StringBuilder();
            foreach (byte b in hash.Hash)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            Token = s.ToString();
            DateTime VerifTime6 = DateTime.Now;


            // casy
            TimeSpan Kontrola_Casu = VerifTime2 - VerifTime1;
            TimeSpan Kontrola_C2C1_ = VerifTime3 - VerifTime2;
            TimeSpan Kontrola_C3 = VerifTime4 - VerifTime3;
            TimeSpan Kontrola_C4 = VerifTime5 - VerifTime4;
            TimeSpan Kontrola_Token = VerifTime6 - VerifTime5;
            TimeSpan Celkem = VerifTime6 - VerifTime1;
            //Zprava



            returnMessage += "\r\n\r\nT a T' (Kontrola časových otisků)...: ";
            returnMessage += Kontrola_Casu.TotalMilliseconds.ToString() + " ms";
            returnMessage += "\r\nKontrola Hashů C'1 a C2...: ";
            returnMessage += Kontrola_C2C1_.TotalMilliseconds.ToString() + " ms";
            returnMessage += "\r\nKontrola Hashů C3 a h(C1 XOR Ts): ";
            returnMessage += Kontrola_C3.TotalMilliseconds.ToString() + " ms\r\n";
            returnMessage += "\r\nKontrola Hashů C4 a h(Ri XOR T''): ";
            returnMessage += Kontrola_C3.TotalMilliseconds.ToString() + " ms\r\n";
            returnMessage += "\r\nTvorba Session Token h(C1||Ri||Tu||(hTs)): ";
            returnMessage += Kontrola_Token.TotalMilliseconds.ToString() + " ms\r\n";
            returnMessage += "\r\nCelkem: ";
            returnMessage += Celkem.TotalMilliseconds.ToString() + " ms\r\n";
            returnMessage += "\r\nToken Hashs: " + Token;
            return returnMessage;
        }

        #endregion

        #region Autentifikace Improved bilinear pairing - nefunkcni

        //public string RemoteAutentification_Pairing(string ID, string PWD, string b)
        //{
        //    //Inicializace komunikace s kartou
        //    Inicializace();

        //    DateTime hashTime1 = DateTime.Now;
        //    //byte[] id2 = System.Text.UTF8Encoding.UTF8.GetBytes(ID);

        //    int hID = ID.GetHashCode(); 
        //    int hPWD = PWD.GetHashCode();
        //    int regid = intsKey * hID + hPWD;

        //    DateTime hashTime2 = DateTime.Now;

        //    // Ulozim na kartu
        //    string Response = getService().Registration_Pairing(ID, regid);

        //    DateTime hashTime3 = DateTime.Now;

        //    // casy
        //    TimeSpan Hashovani = hashTime2 - hashTime1;
        //    TimeSpan Zapis = hashTime3 - hashTime2;
        //    TimeSpan Celkem = hashTime3 - hashTime1;
        //    // Zprava
        //    string returnMessage = "\r\n===REGISTRACE===\r\nUživatel '" + ID + "' zaregistrován. \r\n Operace: \r\nHashování: ";
        //    returnMessage += Hashovani.TotalMilliseconds.ToString() + " ms";
        //    returnMessage += "\r\nZápis na kartu: ";
        //    returnMessage += Zapis.TotalMilliseconds.ToString() + " ms";
        //    returnMessage += "\r\nCelkem: ";
        //    returnMessage += Celkem.TotalMilliseconds.ToString() + " ms\r\n";

        //    //Ukonceni spojeni s kartou
        //    UkonciSpojeni();

        //    return returnMessage; //+ md5hash;
        //}

        //public string Login_Pairing(string ID, string PWD, string b)
        //{
        //    //Inicializace komunikace s kartou
        //    Inicializace();

        //    //ID = "uziv";
        //    //PWD = "heslo";
        //    //b = "1";
        //    //string x = "kkk";

        //    // Prekonvertuji vstupni promenne do byte
        //    //byte[] id2 = String2Arr(ID);
        //    //byte[] pwd2 = String2Arr(PWD);
        //    //byte[] x2 = String2Arr(x);

        //    DateTime LoginTime1 = DateTime.Now;
        //    byte[] id2 = System.Text.UTF8Encoding.UTF8.GetBytes(ID);
        //    byte[] pwd2 = System.Text.UTF8Encoding.UTF8.GetBytes(PWD);
        //    byte[] x2 = System.Text.UTF8Encoding.UTF8.GetBytes(SecretKey);

        //    // Ulozim na kartu
        //    string verID = "";
        //    int DID = 0;
        //    string regid = getService().Login_Pairing(ID);
        //    string timestamp1 = ""; int V = 0;
        //    if (regid != "False")
        //    {
        //        verID = "OK";
        //        Random ran = new Random();
        //        int r = ran.Next();
        //        V = r * Convert.ToInt32(b);

        //        #region Timestamp1 - Tu
        //        // Vezmu si Timestamp1
        //        timestamp1 = DateTime.UtcNow.ToString();
        //        timestamp1 += DateTime.UtcNow.Millisecond.ToString();
        //        // kvuli konverzi prevedu nechtene znaky
        //        timestamp1 = timestamp1.Replace(".", "").Replace(":", "").Replace(" ", "");
        //        #endregion

        //        string hash = timestamp1 + V.ToString();
        //        DID = (r + hash.GetHashCode()) * (Convert.ToInt32(regid) - PWD.GetHashCode());
        //    }
        //    else
        //    {
        //        verID = "FAIL";
        //    }
        //    string returnMessage = "\r\n===PŘIHLÁŠENÍ===\r\nProbíhá ověření uživatele '" + ID + "'. \r\n Operace: \r\n";
            
        //    DateTime LoginTime2 = DateTime.Now;
        //    // Odesilam zpravu dal
        //    string VerificationMessage = Verification_Pairing(ID, timestamp1,DID,V,Convert.ToInt32(b));
        //    DateTime LoginTime3 = DateTime.Now;


        //    TimeSpan Login = LoginTime2 - LoginTime1;
        //    TimeSpan LoginaVerifikace = LoginTime3 - LoginTime1;

        //    //Zprava

        //    returnMessage += "\r\nPřihlášení...: ";
        //    returnMessage += Login.TotalMilliseconds.ToString() + " ms";
        //    returnMessage += "\r\n\r\n" + VerificationMessage;
        //    returnMessage += "\r\n\r\n===CELKEM===: ";
        //    returnMessage += LoginaVerifikace.TotalMilliseconds.ToString() + " ms";
        //    return returnMessage;
        //}

        //public string Verification_Pairing(string IDi, string Timestamp, int DID, int V,int b)
        //{
        //    //Inicializace komunikace s kartou
        //    Inicializace();
        //    DateTime VerifTime1 = DateTime.Now;
        //    string returnMessage = "\r\n===OVĚŘENÍ===\r\nProbíhá ověření uživatele '" + IDi + "'. \r\n Operace: \r\n";

        //    #region Kontrola casu
        //    string timestamp2 = DateTime.UtcNow.ToString();
        //    timestamp2 += DateTime.UtcNow.Millisecond.ToString();
        //    timestamp2 = timestamp2.Replace(".", "").Replace(":", "").Replace(" ", "");
        //    // Pokud zabere proces dele nez 1s potom se jedna o opakovany utok, pokud je stejny, potom je to paralelni utok
        //    returnMessage += "Kontrola časových otisků...";
        //    if ((Convert.ToInt64(Timestamp) - Convert.ToInt64(timestamp2)) > 1000 && Convert.ToInt64(Timestamp) == Convert.ToInt64(timestamp2))
        //    {
        //        returnMessage += "SELHALA\r\n";
        //        return returnMessage;
        //    }
        //    returnMessage += "OK\r\n";
        //    #endregion
        //    DateTime VerifTime2 = DateTime.Now;
        //    //byte[] id2 = System.Text.UTF8Encoding.UTF8.GetBytes(ID);
        //    //byte[] pwd2 = System.Text.UTF8Encoding.UTF8.GetBytes(PWD);
        //    //byte[] x2 = String2Arr(x);
        //    //byte[] IDi2 = String2Arr(IDi);
        //    int P = intsKey * b;
        //    System.Web.UI.Pair ttt = new System.Web.UI.Pair(DID, P);
        //    int x1 = ttt.GetHashCode();
        //    string hCode = Timestamp + V.ToString();
        //    int argum = V + hCode.GetHashCode()*b;
        //    System.Web.UI.Pair ddd = new System.Web.UI.Pair(IDi.GetHashCode(), argum);
        //    int x2 = ddd.GetHashCode();
        //    bool a = ttt.Equals(ddd);

        //    DateTime VerifTime3 = DateTime.Now;
        //    //#region h(EID XOR x)
        //    //byte[] x2 = System.Text.UTF8Encoding.UTF8.GetBytes(SecretKey);
        //    //byte[] IDi2 = System.Text.Encoding.UTF8.GetBytes(IDi);

        //    //// Provedu h(EID XOR x)
        //    //int n = getN();
        //    //string eid = IDi + n.ToString();
        //    //byte[] byte_eid = System.Text.UTF8Encoding.UTF8.GetBytes(eid);
        //    //// P = h(EID xor x)
        //    //byte[] eidxx = XOR(byte_eid, x2);
        //    //MD5CryptoServiceProvider hash = new MD5CryptoServiceProvider();
        //    //hash.ComputeHash(eidxx);
        //    //System.Text.StringBuilder s = new System.Text.StringBuilder();
        //    //foreach (byte byt in hash.Hash)
        //    //{
        //    //    s.Append(byt.ToString("x2").ToLower());
        //    //}
        //    //string md5hash_p = s.ToString();
        //    //byte[] byte_p = System.Text.UTF8Encoding.UTF8.GetBytes(md5hash_p);
        //    //#endregion

        //    //returnMessage += "Kontrola Hashů C'2 a C2...";
        //    //if (C2 == C2_) { returnMessage += "OK\r\n"; }
        //    //else
        //    //{
        //    //    returnMessage += "SELHALA\r\n";
        //    //    return returnMessage;
        //    //}
            
        //    //// 3. bod - druhe overeni casovych otisku
        //    //#region C3
        //    //byte[] timestamp_byte = System.Text.Encoding.UTF8.GetBytes(timestamp2);
        //    //hash = new MD5CryptoServiceProvider();
        //    //hash.ComputeHash(timestamp_byte);
        //    //s = new System.Text.StringBuilder();
        //    //foreach (byte b in hash.Hash)
        //    //{
        //    //    s.Append(b.ToString("x2").ToLower());
        //    //}
        //    //string hTs = s.ToString();
        //    //string C3 = md5hash_p + hTs;
        //    //byte[] C3_byte = System.Text.Encoding.UTF8.GetBytes(C3);
        //    //hash = new MD5CryptoServiceProvider();
        //    //hash.ComputeHash(C3_byte);
        //    //s = new System.Text.StringBuilder();
        //    //foreach (byte b in hash.Hash)
        //    //{
        //    //    s.Append(b.ToString("x2").ToLower());
        //    //}
        //    //C3 = s.ToString();
        //    //#endregion


        //    //#region C3'
        //    //byte[] byte_C1 = getService().Verification_Hsiang(pwdb);
        //    //string C1 = System.Text.Encoding.UTF8.GetString(byte_C1);
        //    //string C3_ = C1 + hTs;
        //    //byte[] byte_c3_ = System.Text.Encoding.UTF8.GetBytes(C3_);
        //    //hash = new MD5CryptoServiceProvider();
        //    //hash.ComputeHash(byte_c3_);
        //    //s = new System.Text.StringBuilder();
        //    //foreach (byte b in hash.Hash)
        //    //{
        //    //    s.Append(b.ToString("x2").ToLower());
        //    //}
        //    //C3_ = s.ToString();
        //    //#endregion


        //    // Kontrola
        //    //returnMessage += "Kontrola Hashů C3 a h(C1 XOR T'')...";
        //    //if (C3 == C3_) { returnMessage += "OK\r\n"; }
        //    //else
        //    //{
        //    //    returnMessage += "SELHALA\r\n";
        //    //    return returnMessage;
        //    //}
        //    //returnMessage += "OK\r\n";
        //    DateTime VerifTime4 = DateTime.Now;

        //    //string Token = C1 + Ri + Timestamp + hTs;
        //    //byte[] byte_token = System.Text.Encoding.UTF8.GetBytes(Token);
        //    //hash = new MD5CryptoServiceProvider();
        //    //hash.ComputeHash(byte_token);
        //    //s = new System.Text.StringBuilder();
        //    //foreach (byte b in hash.Hash)
        //    //{
        //    //    s.Append(b.ToString("x2").ToLower());
        //    //}
        //    //Token = s.ToString();
        //    DateTime VerifTime5 = DateTime.Now;
        //    // casy
        //    TimeSpan Kontrola_Casu = VerifTime2 - VerifTime1;
        //    TimeSpan Kontrola_C2C1_ = VerifTime3 - VerifTime2;
        //    TimeSpan Kontrola_C3 = VerifTime4 - VerifTime3;
        //    TimeSpan Kontrola_Token = VerifTime5 - VerifTime4;
        //    TimeSpan Celkem = VerifTime5 - VerifTime1;
        //    //Zprava



        //    returnMessage += "\r\n\r\nT a T' (Kontrola časových otisků)...: ";
        //    returnMessage += Kontrola_Casu.TotalMilliseconds.ToString() + " ms";
        //    returnMessage += "\r\nKontrola Hashů C'1 a C2...: ";
        //    returnMessage += Kontrola_C2C1_.TotalMilliseconds.ToString() + " ms";
        //    returnMessage += "\r\nKontrola Hashů C3 a h(C1 XOR T''): ";
        //    returnMessage += Kontrola_C3.TotalMilliseconds.ToString() + " ms\r\n";
        //    returnMessage += "\r\nTvorba Session Token h(C1||Ri||Tu||(hTs)): ";
        //    returnMessage += Kontrola_Token.TotalMilliseconds.ToString() + " ms\r\n";
        //    returnMessage += "\r\nCelkem: ";
        //    returnMessage += Celkem.TotalMilliseconds.ToString() + " ms\r\n";
        //    //returnMessage += "\r\nToken Hashs: " + Token;
        //    return returnMessage;
        //}

        

        #endregion - nefunkcni

        #region Kod pro komunikaci s kartou

        private const string URL = "apdu://selfdiscover/EncryptionSinkService.uri";
        private Service cardServer;                                     //definice nové služby
        private APDUClientChannel channel = new APDUClientChannel();    //definice nového komunikaèního kanálu (channel)

        //metoda pro nastaveni promìnne service
        private void setService(Service cardServer)
        {
            this.cardServer = cardServer;
        }
        //metoda pro získáni hodnoty z promìnne service
        private Service getService()
        {
            return this.cardServer;
        }
        //metoda pro nastavení promìnne channel
        private void setChannel(APDUClientChannel channel)
        {
            this.channel = channel;
        }
        //metoda pro získáni hodnoty z promìnne channel
        private APDUClientChannel getChannel()
        {
            return this.channel;
        }

        public static void Main()
        {
        }

        //----------------------------------------------------------------------------
        //Metoda sloužící k ustanovení komunikaèního kanálu a registraci dané služby
        //---------------------------------------------------------------------------- 
        private void Inicializace()
        {

            //Nastavení pøipojení ke službì "EncryptionSinkClient" na kartì
            setChannel(new APDUClientChannel());

            //Registrace komunikaèního kanálu
            ChannelServices.RegisterChannel(getChannel(), false);

            //Nastavíme požadovanou službu (nacházející se na pøislušné URL adrese)
            setService((Service)Activator.GetObject(typeof(Service), URL));
        }

        //----------------------------------------------------------------------------
        //Metoda sloužící ke zrušní komunikaèního kanálu
        //---------------------------------------------------------------------------- 
        private void UkonciSpojeni()
        {
            ChannelServices.UnregisterChannel(getChannel());
        }

        //----------------------------------------------------------------------------
        //Metoda pro odesílání vybraných parametrù na kartu (jen 1x)
        //----------------------------------------------------------------------------

        #endregion

        
        #region Protokol
        /*
        public void SetParameters()
        {
            //Prevod na String_base
            byte[] g1_byte = String2ArrReverse("2");
            Array.Reverse(g1_byte);
            string g1 = Convert.ToBase64String(g1_byte);

            byte[] g2_byte = String2ArrReverse("10025007711078970032722090924244823753518831265230832543972867812291534909295533755784650421637319882038517189154959272472749590988012213990204130949813293249939236148700631387232858769975421549398744560469069000199468677597593376010508357296484445672716792583456375686616540719444064846258831817642426068745");
            Array.Reverse(g2_byte);
            string g2 = Convert.ToBase64String(g2_byte);

            byte[] g3_byte = String2ArrReverse("3");
            Array.Reverse(g3_byte);
            string g3 = Convert.ToBase64String(g3_byte);

            byte[] n_byte = String2ArrReverse("103591779951956805685632667169764966971843035782519723980331864628213384015286756577861374192939798068409838383020702453300877398991771740795239376052097400553904378258514562638386783011842776923138046086547225696091469644597607554280447576816953516080944301013048157225911981589658664069265537468062555103289");
            Array.Reverse(n_byte);
            string n = Convert.ToBase64String(n_byte);

            byte[] w_byte = String2ArrReverse("1430738032943714738611547866729946237171926281834");
            Array.Reverse(w_byte);
            string w = Convert.ToBase64String(w_byte);

            byte[] wi_byte = String2ArrReverse("103591779951956805685632667169764966971843035782519723980331864628213384015286756577861374192939793383017056439603956430012616534351521140493957559829686699653858220014228482371156807862929291067680419706900390384262530445866376374692484620429009640233312656002550765621627282070462962686741769388798566542662");
            Array.Reverse(wi_byte);
            string wi = Convert.ToBase64String(wi_byte);
            //Inicializace komunikace s kartou
            Inicializace();

            //Test nahrani parametru
            getService().SetParameters(g1, "g1", true, false);
            getService().SetParameters(g2, "g2", false, false);
            getService().SetParameters(g3, "g3", false, false);
            getService().SetParameters(n, "n", false, false);
            getService().SetParameters(w, "w", false, false);
            getService().SetParameters(wi, "wi", false, true);


            //Ukonceni spojeni s kartou
            UkonciSpojeni();
        }
        
        public string RunProtocol()
        {
            byte[] g1_byte = String2ArrReverse("2");
            Array.Reverse(g1_byte);
            string g1 = Convert.ToBase64String(g1_byte);

            byte[] g2_byte = String2ArrReverse("10025007711078970032722090924244823753518831265230832543972867812291534909295533755784650421637319882038517189154959272472749590988012213990204130949813293249939236148700631387232858769975421549398744560469069000199468677597593376010508357296484445672716792583456375686616540719444064846258831817642426068745");
            Array.Reverse(g2_byte);
            string g2 = Convert.ToBase64String(g2_byte);
            byte[] n_byte = String2ArrReverse("103591779951956805685632667169764966971843035782519723980331864628213384015286756577861374192939798068409838383020702453300877398991771740795239376052097400553904378258514562638386783011842776923138046086547225696091469644597607554280447576816953516080944301013048157225911981589658664069265537468062555103289");
            Array.Reverse(n_byte);
            string n = Convert.ToBase64String(n_byte);

            //Inicializace komunikace s kartou
            Inicializace();
            byte[] r1 = String2ArrReverse("1058390237766549893870159222418659010830370154257530759414454613904048164902889234527964999069018657662946711075539");
            Array.Reverse(r1);
            byte[] r1i = String2ArrReverse("2471771760604946311944243905017210604129956002333813852872490707507528194383334396085233675685864951240347238511403583049738135841356415428983639197457584301529434");
            Array.Reverse(r1i);
            byte[] r2 = String2ArrReverse("1903504862866753128964086478881045909024927425063443777180083878088011395140893434541704099110133039878893506905932182913421997133159676012397498930887174069688974529540303424943035");
            Array.Reverse(r2);
            byte[] r2i = String2ArrReverse("3832597006221243113691114298484896729873483213992727081137902827189271452259148193729468874396405666316662048488415414063337513378212537609179357686605951493623864530401732398718104608396870886363449493338729494058172016646678859");
            Array.Reverse(r2i);
            byte[] e1_byte = String2ArrReverse("727255329137909630536094653999912989262169168985");
            Array.Reverse(e1_byte);
            string e1 = Convert.ToBase64String(e1_byte);

            //Ziskani odezvy
            getService().FirstStep();
            getService().LastStep(e1_byte);
            byte[] c11 = getService().Getc11();
            byte[] c22 = getService().Getc22();
            byte[] c3 = getService().Getc3();
            byte[] c33 = getService().Getc33();
            byte[] z1 = getService().Getz1();
            byte[] z1i = getService().Getz1i();
            byte[] z2 = getService().Getz2();
            byte[] z2i = getService().Getz2i();

            string tmp = "c11: " + Arr2String(c11) + "\r\n \r\n" + "c22: " + Arr2String(c22) + "\r\n \r\n" + "c3: " + Arr2String(c3) + "\r\n \r\n" + "\r\n \r\n" + "c22: " + Arr2String(c22) + "\r\n \r\n" + "c33: " + Arr2String(c33) + "\r\n \r\n" + "z1: " + Arr2String(z1) + "\r\n \r\n" + "z1i: " + Arr2String(z1i) + "\r\n \r\n" + "z2: " + Arr2String(z2) + "\r\n \r\n" + "z2i: " + Arr2String(z2i); 
            //Ukonceni spojeni s kartou
            UkonciSpojeni();
            return tmp;
        }
        
        */

        #endregion

        #region Pomocne metody pro vypocet (+,*), pouze pro ladeni

        //public static byte[] ArrAddSimple(byte[] a, byte[] b, byte[] modulus)
        //{
        //    byte[] res = new byte[RSAsize / 8];
        //    int[] carry = new int[2];

        //    for (int i = RSAsize / 8 - 1; i >= 0; i--)
        //    {
        //        carry[(i + 1) % 2] = ((a[i] + b[i] + carry[i % 2]) > 255) ? 0x1 : 0x0;
        //        res[i] = (byte)((a[i] + b[i] + carry[i % 2]) % 256);
        //    }

        //    if (carry[1] == 1)
        //    {
        //        a = ArrSubSimple(a, modulus, modulus);

        //        res = ArrAddSimple(b, a, modulus);
        //    }

        //    return res;
        //}

        // Scitani pro libovolne cisla, rychlejsi pro mensi cisla nez velikost modula

        //public static byte[] ArrAddObecne(byte[] a, byte[] b)
        //{
        //    int size;
        //    byte carry = 0;
        //    if (a.Length > b.Length)
        //    {
        //        size = a.Length;
        //    }
        //    else
        //    {
        //        size = b.Length;
        //    }
        //    byte[] res = new byte[size];
        //    for (int i = res.Length - 1; i >= 0; i--)
        //    {
        //        res[i] = Convert.ToByte((a[i] + b[i] + carry) % 256);
        //        if ((a[i] + b[i] + carry) > 255)
        //        {
        //            carry = 1;
        //        }
        //        else carry = 0;
        //    }
        //    return res;
        //}

        /// <summary>
        /// Obecne nasobeni v modulu, zde pro odladeni
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="modulus"></param>
        /// <returns></returns>
        //public static byte[] ArrMultiSimple(byte[] a, byte[] b)
        //{
        //    byte[] result = new byte[RSAsize / 8];

        //    for (int i = RSAsize / 8; i >= 0; i--)
        //    {

        //        int mcarry = 0;

        //        for (int j = RSAsize / 8; j >= 0; j--)
        //        {
        //            int val = (a[i] * b[j]) +
        //                             result[i + j + 1] + mcarry;

        //            result[i + j + 1] = (byte)(val & 0xFF);
        //            mcarry = (val >> 8);
        //        }

        //        if (mcarry != 0)
        //            result[i + RSAsize / 8] = (byte)mcarry;
        //    }
        //    return result;

        //}

        /// <summary>
        /// tato fce nasobení je použita na karte, metoda schoolbook asi 800 ms
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        //public static byte[] ArrMultiObecne(byte[] a, byte[] b)
        //{
        //    byte[] result = new byte[a.Length + b.Length];

        //    for (int i = a.Length - 1; i >= 0; i--)
        //    {
        //        int mcarry = 0;
        //        for (int j = b.Length - 1; j >= 0; j--)
        //        {
        //            int val = (a[i] * b[j]) +
        //                             result[i + j + 1] + mcarry;

        //            result[i + j + 1] = (byte)(val & 0xFF);
        //            mcarry = (val >> 8);
        //        }

        //        if (mcarry != 0)
        //            result[i + b.Length] = (byte)mcarry;
        //    }
        //    return result;

        //}

        //asi 300 ms
        //public static byte[] ArrMultiObecneOpt(byte[] a, byte[] b)
        //{

        //    byte[] x_red = RedukceByteArr(a);
        //    byte[] y_red = RedukceByteArr(b);
        //    int x_len = x_red.Length;
        //    int y_len = y_red.Length;

        //    byte[] result = new byte[a.Length + b.Length];

        //    for (int i = a.Length - 1; i >= a.Length - x_len - 1; i--)
        //    {
        //        int mcarry = 0;
        //        for (int j = b.Length - 1; j >= b.Length - y_len - 1; j--)
        //        {
        //            int val = (a[i] * b[j]) +
        //                             result[i + j + 1] + mcarry;

        //            result[i + j + 1] = (byte)(val & 0xFF);
        //            mcarry = (val >> 8);
        //        }

        //        if (mcarry != 0)
        //            result[i + y_len] = (byte)mcarry;
        //    }
        //    return result;

        //}

        //jeste rychlejsi kdy redukce nebude na karte ale na pc- asi 100 ms
        //public static byte[] ArrMultiObecneOpt2(byte[] a, byte[] b)
        //{


        //    int x_len = a.Length;
        //    int y_len = b.Length;

        //    byte[] result = new byte[a.Length + b.Length];

        //    for (int i = a.Length - 1; i >= 0; i--)
        //    {
        //        int mcarry = 0;
        //        for (int j = b.Length - 1; j >= 0; j--)
        //        {
        //            int val = (a[i] * b[j]) +
        //                             result[i + j + 1] + mcarry;

        //            result[i + j + 1] = (byte)(val & 0xFF);
        //            mcarry = (val >> 8);
        //        }

        //        if (mcarry != 0)
        //            result[i + y_len] = (byte)mcarry;
        //    }
        //    return result;

        //}

        //public static byte[] ArrSubSimple(byte[] a, byte[] b, byte[] modulus)
        //{
        //    int alen = a.Length;
        //    int blen = b.Length;
        //    int size = blen;
        //    if (alen > blen)
        //        size = RSAsize / 8;

        //    byte[] res = new byte[size];
        //    int[] carry = new int[2];

        //    for (int j = 0; j < size; j++)
        //    {
        //        if (a[j] > b[j])
        //        {
        //            for (int i = size - 1; i >= 0; i--)
        //            {
        //                carry[(i + 1) % 2] = ((a[i] - b[i] - carry[i % 2]) < 0) ? 0x1 : 0x0;
        //                res[i] = (byte)((a[i] - b[i] - carry[i % 2] + 256 * carry[(i + 1) % 2]) % 256);
        //            }
        //            return res;
        //        }




        //        if (a[j] < b[j])
        //        {
        //            for (int i = size - 1; i >= 0; i--)
        //            {
        //                carry[(i + 1) % 2] = ((modulus[i] + a[i] + carry[i % 2]) > 255) ? 0x1 : 0x0;
        //                res[i] = (byte)((modulus[i] + a[i] + carry[i % 2]) % 256);
        //            }

        //            for (int i = size - 1; i >= 0; i--)
        //            {
        //                carry[(i + 1) % 2] = ((res[i] - b[i] - carry[i % 2]) < 0) ? 0x1 : 0x0;
        //                res[i] = (byte)((res[i] - b[i] - carry[i % 2] + 256 * carry[(i + 1) % 2]) % 256);
        //            }


        //            return res;
        //        }

        //    }

        //    for (int i = size - 1; i >= 0; i--)
        //    {
        //        carry[(i + 1) % 2] = ((a[i] - b[i] - carry[i % 2]) < 0) ? 0x1 : 0x0;
        //        res[i] = (byte)((a[i] - b[i] - carry[i % 2] + 256 * carry[(i + 1) % 2]) % 256);
        //    }



        //    return res;

        //}

        //public static byte[] ArrHalfSimple(byte[] input, byte[] modulus)
        //{
        //    if (input[RSAsize / 8 - 1] % 2 == 1)
        //    {
        //        byte[] res = new byte[RSAsize / 8+1];
        //        int[] carry = new int[2];
                
        //        for (int i = RSAsize / 8 - 1; i >= 0; i--)
        //        {
        //            carry[(i + 1) % 2] = ((input[i] + modulus[i] + carry[i % 2]) > 255) ? 0x1 : 0x0;
        //           res[i+1] = (byte)((input[i] + modulus[i] + carry[i % 2]) % 256);
        //        }

        //        res[0] = (byte)carry[1];

        //        int[] carry2 = new int[2];

        //        carry2[1] = (res[0]) * 128;
                
        //        for (int j = 1; j < RSAsize / 8+1; j++)
        //        {
        //            carry2[(j + 1) % 2] = (res[j] % 2) * 128;
        //            input[j-1] = (byte)((res[j] >> 1) + carry2[j % 2]);
        //        };

        //        return input;
    
        //    }

        //    int[] carry3 = new int[2];
        //    for (int j = 0; j < RSAsize / 8; j++)
        //    {
        //        carry3[(j + 1) % 2] = (input[j] % 2) * 128;
        //        input[j] = (byte)((input[j] >> 1) + carry3[j % 2]);
        //    };

        //    return input;
        //}

        #endregion

        #region Simple (schoolbook)

       // public string VypoctiSoucin(string a, string b, string modulus, int iterace)
       // {
       //     //Inicializace komunikace s kartou
       //     bool sw = false;
       //     Inicializace();

       //     //Inicializace parametru RSA
       //     byte[] a_byte = String2ArrReverse(a);
       //     a_length = length;

       //     //korektura pro prenos pokud jsou a b stejne dlouha jako RSAsize
       //     if (a_length * 8 == RSAsize)
       //     {
       //         RSAsize = RSAsize + 8;
       //         sw = true;
       //     }
       //     a_byte = String2ArrReverse(a);

       //     Array.Reverse(a_byte);
       //     byte[] mod_byte = String2ArrReverse(modulus);
       //     m_length = length;
       //     Array.Reverse(mod_byte);
       //     byte[] b_byte = String2ArrReverse(b);
       //     b_length = length;
       //     Array.Reverse(b_byte);

       ////     a_byte = RedukceByteArr(a_byte);
       // //    b_byte = RedukceByteArr(b_byte);

       //     //Vypocte soucin na karte
       //     DateTime startTime = DateTime.Now;
       //  //   byte[] res = getService().ArrMultiObecneOpt2(a_byte, b_byte);
          
    
       //     byte[] res = getService().ArrSubSimple(a_byte, b_byte,mod_byte);
       //   //  byte[] res = getService().ArrHalfSimple(a_byte, mod_byte);
       //    // byte[] res = getService().ArrAddEqual(a_byte, b_byte);

       //     DateTime stopTime = DateTime.Now;
       //     TimeSpan duration = stopTime - startTime;
       //     string strsec = duration.TotalMilliseconds.ToString();
      
       //     res = Modulo(res, mod_byte);


       //     //Ukonceni spojeni s kartou
       //     UkonciSpojeni();

       //     // Vypocet kontrolni hodnoty pomoci bigint
       //     //pro součet
       //     if (sw == true)
       //         RSAsize = RSAsize - 8;
       //     //pro součin
       //    // byte[] res2 = Overeni(a_byte, b_byte, mod_byte);
       //     byte[] res2 = Overeni2(a_byte, b_byte);
       //   //  res2 = Modulo(res2, mod_byte);

       //     //Vrati postupne kryptogra, pouzite parametry RSA a desifrovanou hodnotu. Pro prevod z pole bytu se pouziva fce Arr2Str
       //     return "a * b:\r\n" + Arr2String(res) + "\r\n cas:" +strsec+" ms"+ "\r\n"+  "a * b (overeni):\r\n" + Arr2String(res2) + "\r\n" + "\r\n" + "delky parametru: a= " + a_length * 8 + " bits,  b= " + b_length * 8 + " bits,  mod= " + m_length * 8 + " bits \r\n" + "\r\n";

       // }
        #endregion

        #region Montgomery

        //tato je funkcni
        //public string VypoctiSoucinMont1(string a, string b, string modulus, int iterace)
        //{
        //    //Inicializace komunikace s kartou
        //    Inicializace();

        //    //testovaci menezes
        //    //   a = "5792";

        //    //    b = "1229";
        //    //    modulus = "72639";
        //    int baze = 256;
        //    //Inicializace parametru RSA
        //    byte[] a_byte = String2ArrReverse(a);
        //    a_length = length;
        //    // Array.Reverse(a_byte);

        //    byte[] mod_byte = String2ArrReverse(modulus);
        //    m_length = length;
        //    Array.Reverse(mod_byte);

        //    //zjistit delku n
        //    int N = RedukceByteArr(mod_byte).Length - 1;


        //    // nachystani mQ = -m^1 mod b.

        //    BigInteger mod = new BigInteger(mod_byte);
        //    //masku mam 255 256 uz je prenos 
        //    mod = ((baze - mod).modInverse(baze));
        //    //protoze je minus tak odecte od modula

        //    int mQ = Convert.ToInt32(mod.ToString()); ;//mod.IntValue();

        //    byte[] b_byte = String2ArrReverse(b);
        //    b_length = length;
        //    // Array.Reverse(b_byte);

        //    Array.Reverse(mod_byte);
        //    //Vypocte soucin na karte
        //    DateTime startTime = DateTime.Now;
        //    byte[] res = getService().ArrMultiMontgomeryREV(a_byte, b_byte, mod_byte, N, mQ);
        //    //  byte[] res = ArrMultiMontgomeryREV(a_byte, b_byte, mod_byte, N, mQ);
        //    DateTime stopTime = DateTime.Now;
        //    TimeSpan duration = stopTime - startTime;
        //    string strsec = duration.TotalMilliseconds.ToString();
      
        //    // x * y * R^-1 mod m. je nyni res
        //    // proto vynasobime R coz je R = b^n with gcd(m, b) = 1
        //    // n je delka modula 
        //    //b je vpocetni baze ci radix
        //    // double pom = Math.Pow(256.0, Convert.ToDouble(N));
        //    Array.Reverse(mod_byte);
        //    BigInteger pom = new BigInteger(baze);

        //    BigInteger modulo = new BigInteger(mod_byte);
        //    pom = pom.modPow(N, modulo);
        //    //  pom=pom ^ N;

        //    string p = pom.ToString();

        //    byte[] soucinitel = String2ArrReverse(p);
        //    Array.Reverse(soucinitel);
        //    Array.Reverse(res);

        //    res = ArrMultiObecneOpt2(soucinitel, res);
        //    //projedeme pres modulo
        //    res = Modulo(res, mod_byte);
        //    Array.Reverse(res);


        //    //Ukonceni spojeni s kartou
        //    UkonciSpojeni();

        //    Array.Reverse(a_byte);
        //    Array.Reverse(b_byte);
        //    //pro součin
        //    byte[] res2 = Overeni(a_byte, b_byte, mod_byte);

        //    //Vrati postupne kryptogra, pouzite parametry RSA a desifrovanou hodnotu. Pro prevod z pole bytu se pouziva fce Arr2Str
        //    return "Montgomery a * b:\r\n" + Arr2String(res) + "\r\n casIN: " +strsec +" ms" +"\r\n" + "a * b (overeni):\r\n" + Arr2String(res2) + "\r\n" + "delky parametru: a= " + a_length * 8 + " bits,  b= " + b_length * 8 + " bits,  mod= " + m_length * 8 + " bits \r\n" + "\r\n" + "\r\n";

        //}

        // Montgomery multiplication
        //public static byte[] ArrMultiMontgomeryREV(byte[] x, byte[] y, byte[] m, int N, int mQ)
        //{

        //    //int LONG_MASK = 0xFF; //255
        //    int LONG_MASK = 255;
        //    int BITS = 8;

        //    byte[] a = new byte[N + 1];
        //    // for (int i = 0; i < N; i++)
        //    // {
        //    //     a[i] = 0;
        //    // }


        //    // int Y_0 = y[konst - 1] & LONG_MASK;
        //    // 2. For i from (n - 1) to 0  do the following:
        //    for (int i = 0; i < N; i++)
        //    //   for (int i = 0; i < n; i++)
        //    {
        //        // 2.1 u_i = (a[0] + x[i] * y[0]) * mQ mod b.

        //        int u = ((a[0] + (((x[i] & LONG_MASK) * (y[0] & LONG_MASK)) & LONG_MASK)) * mQ) & LONG_MASK;
        //        // int u = ((a[0] + ((x_i * Y_0) & LONG_MASK)) * mQ) & LONG_MASK;


        //        // 2.2 A = (A + x[i] * y + u_i * m) / b.

        //        int xy = (x[i] & LONG_MASK) * (y[0] & LONG_MASK);

        //        int um = u * (m[0] & LONG_MASK);

        //        int temp = (a[0] & LONG_MASK) + (xy & LONG_MASK) + (um & LONG_MASK);

        //        int carry = (xy >> BITS) + (um >> BITS) + (temp >> BITS);
        //        // pos´=1
        //        // for (int pos = 0; pos < n - 1; pos++)
        //        //smycka pro vypočty xi*y a ui*m
        //        for (int pos = 1; pos < N; pos++)
        //        {
        //            xy = (x[i] & LONG_MASK) * (y[pos] & LONG_MASK);
        //            um = u * (m[pos] & LONG_MASK);

        //            temp = (a[pos] & LONG_MASK) + (xy & LONG_MASK) + (um & LONG_MASK) + (carry & LONG_MASK);
        //            carry = (carry >> BITS) + (xy >> BITS) + (um >> BITS) + (temp >> BITS);

        //            a[pos - 1] = (byte)temp;
        //        }
        //        //celkový přenos do dalši i-te iterace, pro přiklad davam na pevno
        //        //a[0], dle me tohle je nej
        //        carry += (a[N] & LONG_MASK);
        //        //a[1]
        //        a[N - 1] = (byte)carry;
        //        a[N] = (byte)(carry >> BITS);

        //    }

        //    // 3. If A >= m then A = A - m
        //    if (UrciVetsiInt(a, m) == true)
        //    {
        //        ArrSubSimple(a, m, m);

        //    }

        //    // 4. Return (A). abychom dostali a*b mod m tak je treba jeste nasobit R=b^n tj n delka modula, b je baze, a projet modulem 
        //    //  System.Array.Copy(a, 1, a, 0, N);
        //    return a;
        //}



        /// <summary>
        /// porovna dve cisla a vrati true pokud prvni je vetsi
        /// </summary>
        /// <param name="a">prvni pole</param>
        /// <param name="b">druhe pole</param>
        /// <returns>true pokud je prvni vetsi</returns>
        //public static bool UrciVetsiInt(byte[] a, byte[] b)
        //{
        //    byte[] aReduced;
        //    if (a[0] == 0)
        //    {
        //        aReduced = RedukceByteArr(a);
        //    }
        //    else
        //    {
        //        aReduced = new byte[a.Length];
        //        aReduced = a;
        //    }
        //    byte[] bReduced;
        //    if (b[0] == 0)
        //    {
        //        bReduced = RedukceByteArr(b);
        //    }
        //    else
        //    {
        //        bReduced = new byte[b.Length];
        //        bReduced = b;
        //    }
        //    int delkaA = aReduced.Length;
        //    int delkaB = bReduced.Length;
        //    if (delkaA > delkaB)
        //    {
        //        return true;
        //    }
        //    else if (delkaB > delkaA)
        //    {
        //        return false;
        //    }
        //    else
        //    {
        //        for (int i = 0; i < delkaA; i++)
        //        {
        //            if (aReduced[i] > bReduced[i])
        //            {
        //                return true;
        //            }
        //            else if (aReduced[i] < bReduced[i])
        //            {
        //                return false;
        //            }
        //            if ((delkaA - 1) == i)
        //            {
        //                return true;
        //            }
        //        }
        //        return true;
        //    }
        //}

        //Metoda pro odstranění nul ze začátku pole
        //public static byte[] RedukceByteArr(byte[] a)
        //{
        //    int pocetNul = 0;
        //    byte[] aReduced;
        //    int difference = 0;
        //    if (a[0] == 0)
        //    {
        //        for (int i = 0; i < a.Length - 1; i++)
        //        {
        //            if ((i == 0 && a[0] == 0) || (a[0] == 0 && a[i] == 0))
        //            {
        //                pocetNul++;
        //            }
        //            else
        //            {
        //                break;
        //            }
        //        }
        //        //+1 kvuli prenosu u nasobeni
        //        aReduced = new byte[a.Length - pocetNul + 1];
        //        difference = a.Length - aReduced.Length;
        //        for (int i = aReduced.Length - 1; i >= 0; i--)
        //        {
        //            aReduced[i] = a[i + difference];
        //        }
        //    }
        //    else
        //    {
        //        aReduced = new byte[a.Length];
        //        aReduced = a;
        //    }
        //    return aReduced;
        //}

        //public static byte[] VyrovnaniByteArr(byte[] a, int len)
        //{
        //    int pocetB = a.Length;
        //    byte[] aVyr = new byte[len];

        //    for (int i = 0; i < len - pocetB; i++)
        //    {
        //        aVyr[i] = 0;
        //    }
        //    int j = 0;
        //    for (int i = len - pocetB; i < len; i++)
        //    {
        //        aVyr[i] = a[j];
        //        j++;
        //    }


        //    return aVyr;
        //}

        #endregion

        #region Comba

        //public string VypoctiSoucinComba(string a, string b, string modulus, int iterace)
        //{
        //    //Inicializace komunikace s kartou
        //    Inicializace();
        //    //Inicializace parametru RSA
        //    byte[] a_byte = String2ArrReverse(a);
        //    a_length = length;
        //    Array.Reverse(a_byte);

        //    byte[] mod_byte = String2ArrReverse(modulus);
        //    m_length = length;


        //    byte[] b_byte = String2ArrReverse(b);
        //    b_length = length;
        //    Array.Reverse(b_byte);

        //    byte[] ar_byte = RedukceByteArr(a_byte);
        //    byte[] br_byte = RedukceByteArr(b_byte);
        //    int m1 = ar_byte.Length;
        //    int m2 = br_byte.Length;
        //    int m = m2;
        //    if (m1 > m2)
        //        m = m1;

        //    //Vypocte soucin na karte
        //    Array.Reverse(a_byte);
        //    Array.Reverse(b_byte);

        //    DateTime startTime = DateTime.Now;

        //    byte[] res = getService().CombaOpt(a_byte, b_byte, m );

        //    DateTime stopTime = DateTime.Now;
        //    TimeSpan duration = stopTime - startTime;
        //    string strsec = duration.TotalMilliseconds.ToString();
      

        //    Array.Reverse(mod_byte);
        //    Array.Reverse(res);

        //    res = Modulo(res, mod_byte);
        //    //Array.Reverse(res);

        //    //Ukonceni spojeni s kartou
        //    UkonciSpojeni();

        //    Array.Reverse(a_byte);
        //    Array.Reverse(b_byte);
        //    //pro součin
        //    byte[] res2 = Overeni(a_byte, b_byte, mod_byte);

        //    //Vrati postupne kryptogra, pouzite parametry RSA a desifrovanou hodnotu. Pro prevod z pole bytu se pouziva fce Arr2Str
        //    return "Comba a * b:\r\n" + Arr2String(res) + "\r\n cas: " +strsec+" ms"+ "\r\n" + "a * b (overeni):\r\n" + Arr2String(res2) + "\r\n" + "delky parametru: a= " + a_length * 8 + " bits,  b= " + b_length * 8 + " bits,  mod= " + m_length * 8 + " bits \r\n" + "\r\n" + "\r\n";

        //}

        //pro ladeni 
        //public static byte[] CombaOpt(byte[] a, byte[] b, int size)
        //{
        //    int ucarry;
        //    int utv = 0;
        //    byte[] result = new byte[size + size];

        //    for (int i = 0; i < size; i++)
        //    {
        //        for (int j = 0; j <= i; j++)
        //        {
        //            utv = (a[j] * b[i - j]) + utv;
        //        }
        //        result[i] = (byte)(utv & 0xFF);
        //        ucarry = (utv >> 8);
        //        utv = ucarry;
        //    }
        //    for (int i = size; i < size + size; i++)
        //    {
        //        for (int j = i - size + 1; j <= size - 1; j++)
        //        {
        //            utv = (a[j] * b[i - j]) + utv;
        //        }
        //        result[i] = (byte)(utv & 0xFF);
        //        ucarry = (utv >> 8);
        //        utv = ucarry;
        //    }

        //    return result;
        //}


        #endregion

        #region podpurne fce + - /2 prevodyByteStr a overovaci metody

        public static string Arr2String(byte[] input)
        {
            BigInteger BigNum = new BigInteger(input);
            return BigNum.ToString(10);
        }
        public static byte[] String2Arr(string input)
        {
            byte[] b = new byte[RSAsize / 8];
            BigInteger BigNum = new BigInteger(input, 10);
            length = BigNum.getBytes().Length;
            for (int j = 0; j < length; j++)
            {
                b[j] = BigNum.getBytes()[j];
            }
            for (int i = length; i < RSAsize / 8; i++)
            {
                b[i] = 0;
            }
            return b;
        }

        public static byte[] String2ArrReverse2(string input)
        {
            byte[] b = new byte[RSAsize / 8];
            
            BigInteger BigNum = new BigInteger(input, 10);
            byte[] temp = BigNum.getBytes();
            length = temp.Length;
            b = new byte[length];

            Array.Reverse(temp);

            for (int j = 0; j < length; j++)
            {
                b[j] = temp[j];
            }
            //for (int i = length; i < RSAsize / 8; i++)
            //{
            //    b[i] = 0;
            //}

            return b;
        }
        //public static byte[] TranslateToBytes()

        public static byte[] String2ArrReverse(string input)
        {
            byte[] b = new byte[RSAsize / 8];
            //b = new byte[272];
            BigInteger BigNum = new BigInteger(input, 10);
            byte[] temp = BigNum.getBytes();
            length = temp.Length;

            Array.Reverse(temp);

            for (int j = 0; j < length; j++)
            {
                b[j] = temp[j];
            }
            for (int i = length; i < RSAsize / 8; i++)
            {
                b[i] = 0;
            }

            return b;
        }
        public static byte[] String2ArrBig(string input)
        {
            BigInteger BigNum = new BigInteger(input, 10);
            return BigNum.getBytes();
        }
        public static byte[] Modulo(byte[] a, byte[] modulus)
        {

            BigInteger a_big = new BigInteger(a);
            BigInteger m_big = new BigInteger(modulus);
            a_big = a_big % m_big;
            return a_big.getBytes();
        }
        public static byte[] Overeni(byte[] a, byte[] b, byte[] modulus)
        {

            BigInteger a_big = new BigInteger(a);
            BigInteger b_big = new BigInteger(b);
            BigInteger m_big = new BigInteger(modulus);
            return ((a_big * b_big) % m_big).getBytes();

        }
        public static byte[] Overeni2(byte[] a, byte[] b)
        {

            BigInteger a_big = new BigInteger(a);
            BigInteger b_big = new BigInteger(b);
            //  BigInteger m_big = new BigInteger(modulus);
            return (a_big + b_big).getBytes();

        }

        public static byte[] Overeni3(byte[] a, byte[] b)
        {

            BigInteger a_big = new BigInteger(a);
            BigInteger b_big = new BigInteger(b);
            //  BigInteger m_big = new BigInteger(modulus);
            return (a_big - b_big).getBytes();

        }

        public static byte[] XOR(byte[] a, byte[] b)
        {
            BigInteger a_big = new BigInteger(a);
            BigInteger b_big = new BigInteger(b);
            //  BigInteger m_big = new BigInteger(modulus);
            return (a_big ^ b_big).getBytes();

        }
        
        public static bool Overeni3(byte[] g1, byte[] g2, byte[] c2, byte[] c22,byte[] z2, byte[] z22, byte[] e, byte[] n)
        {

            return false;
        }

        #endregion

        #region Debugovaci metody
        

        #region RSA test tunelu jen pro optimalizaci, nema jinak zde ve tříde uplatneni

        //private static RSACryptoServiceProvider RSAd = new RSACryptoServiceProvider(RSAsize);
        //public static RSAParameters RSAparam = new RSAParameters();

        ////Import parametrů RSA
        //public static void RSA_import(byte[] e, byte[] modulus)
        //{
        //    RSAparam = RSAd.ExportParameters(true);
        //    RSAparam.Exponent = e;
        //    RSAparam.Modulus = modulus;
        //    RSAd.ImportParameters(RSAparam);
        //}

        //public static byte[] Power(byte[] baze, byte[] exponent, byte[] modulus)
        //{
        //   // RSAparam = RSAd.ExportParameters(true);
        //    RSAparam.Exponent = exponent;
        //    RSAparam.Modulus = modulus;
        //    RSAd.ImportParameters(RSAparam);

        //    return RSAd.EncryptValue(baze);
        //}

        ////Inverze RSA, nepouzivane
        //public static byte[] RSA_Decrypt(byte[] input)
        //{
        //    byte[] foo = RSAd.DecryptValue(input);
        //    return foo;
        //}

        ////Export RSA parametru
        //public RSAParameters RSA_export()
        //{
        //    return RSAd.ExportParameters(true);
        //}

        ////Nasobeni
        //public byte[] Multiply(byte[] a_byte, byte[] b_byte, byte[] mod_byte, int iterace)
        //{
        //    Inicializace();
        //    byte[] aMULTb = new byte[RSAsize / 8];
        //    byte[] two = new byte[RSAsize / 8];
        //    two[RSAsize / 8 - 1] = 2;

        //    for (int i = 0; i < iterace; i++)
        //    {
        //        aMULTb = getService().ArrSubSimple(getService().ArrSubSimple(getService().Power(ArrAddSimple(a_byte, b_byte, mod_byte), two, mod_byte), getService().Power(a_byte, two, mod_byte), mod_byte), getService().Power(b_byte, two, mod_byte), mod_byte);
        //    }
        //    //UkonciSpojeni();
        //    //aMULTb = ArrSubSimple(aMULTb,mod_byte,mod_byte);


        //    //return ArrHalfSimple(aMULTb, mod_byte);
        //    return getService().Multiply(a_byte,b_byte,mod_byte,1);
        //}

        #endregion



        #endregion

        #region Kandidati na smazani


        //public static byte[] ArrAddEqual(byte[] a, byte[] b)
        //{

        //    int size = a.Length;

        //    // byte[] res = new byte[RSAsize / 8];
        //    byte[] res = new byte[size];

        //    int[] carry = new int[2];

        //    for (int i = size - 1; i >= 0; i--)
        //    {
        //        carry[(i + 1) % 2] = ((a[i] + b[i] + carry[i % 2]) > 255) ? 0x1 : 0x0;
        //        res[i] = (byte)((a[i] + b[i] + carry[i % 2]) % 256);
        //    }

        //    return res;
        //}



        //public static int[] String2ArrInt(string input)
        //{
        //    int[] b = new int[RSAsize / 8];

        //    for (int j = 0; j < 1; j++)
        //    {
        //        b[j] = Convert.ToInt32(input);

        //    }
        //    return b;
        //}




        ////jen muj test
        //public string VypoctiSoucet(string a, string b, string modulus, int iterace)
        //{
        //    //Inicializace komunikace s kartou
        //    //     Inicializace();

        //    //Inicializace parametru RSA
        //    byte[] a_byte = String2ArrReverse(a);
        //    a_length = length;
        //    Array.Reverse(a_byte);
        //    byte[] mod_byte = String2ArrReverse(modulus);
        //    m_length = length;
        //    Array.Reverse(mod_byte);
        //    byte[] b_byte = String2ArrReverse(b);
        //    b_length = length;
        //    Array.Reverse(b_byte);

        //    // a_byte = RedukceByteArr(a_byte);
        //    // b_byte = RedukceByteArr(b_byte);

        //    // byte[] a_vyr = VyrovnaniByteArr(a_byte, 128);
        //    //Vypocte soucet na karte
        //    byte[] res = ArrAddEqual(a_byte, b_byte);
        //    //  byte[] res = getService().ArrAddEqual(a_byte, b_byte);
        //    // byte[] res = ArrSubSimple(a_byte, b_byte,mod_byte);
        //    //   byte[] res = ArrHalfSimple(a_byte, mod_byte);

        //    res = Modulo(res, mod_byte);

        //    //Ziska parametry z karty
        //    //      RSAParameters RSAused = new RSAParameters();
        //    //      RSAused = getService().RSA_export();

        //    //Ukonceni spojeni s kartou
        //    //       UkonciSpojeni();

        //    // Vypocet kontrolni hodnoty pomoci bigint
        //    //pro součet
        //    byte[] res2 = Overeni2(a_byte, b_byte);

        //    //Vrati postupne kryptogra, pouzite parametry RSA a desifrovanou hodnotu. Pro prevod z pole bytu se pouziva fce Arr2Str
        //    return "a + b:\r\n" + Arr2String(res) + "\r\n" + "\r\n" + "a + b (overeni):\r\n" + Arr2String(res2) + "\r\n" + "\r\n" + "delky parametru: a= " + a_length * 8 + " bits,  b= " + b_length * 8 + " bits,  mod= " + m_length * 8 + " bits \r\n" + "\r\n";

        //}

        //public string VypoctiSoucin(string a, string b, string modulus, int iterace)
        //{
        //    //Inicializace komunikace s kartou
        //    Inicializace();

        //    //Inicializace parametru RSA
        //    byte[] a_byte = String2ArrReverse(a);
        //    a_length = length;
        //    Array.Reverse(a_byte);
        //    byte[] mod_byte = String2ArrReverse(modulus);
        //    m_length = length;
        //    Array.Reverse(mod_byte);
        //    byte[] b_byte = String2ArrReverse(b);
        //    b_length = length;
        //    Array.Reverse(b_byte);

        //    a_byte = RedukceByteArr(a_byte);
        //    b_byte = RedukceByteArr(b_byte);

        //    //Vypocte soucin na karte
        //    // byte[] res = getService().ArrMultiObecne(a_byte, b_byte);
        //    //   byte[] res = getService().ArrMultiObecneOpt(a_byte, b_byte);
        //    byte[] res = getService().ArrMultiObecneOpt2(a_byte, b_byte);
        //    //Vypocte soucin test
        //    // byte[] res = ArrMultiObecne(a_byte, b_byte);
        //    // byte[] res = ArrMultiSimple(a_byte, b_byte);

        //    res = Modulo(res, mod_byte);

        //    //Ziska parametry z karty
        //    //      RSAParameters RSAused = new RSAParameters();
        //    //      RSAused = getService().RSA_export();

        //    //Ukonceni spojeni s kartou
        //    UkonciSpojeni();

        //    // Vypocet kontrolni hodnoty pomoci bigint
        //    //pro součet

        //    //pro součin
        //    byte[] res2 = Overeni(a_byte, b_byte, mod_byte);

        //    //Vrati postupne kryptogra, pouzite parametry RSA a desifrovanou hodnotu. Pro prevod z pole bytu se pouziva fce Arr2Str
        //    return "a * b:\r\n" + Arr2String(res) + "\r\n" + "\r\n" + "a * b (overeni):\r\n" + Arr2String(res2) + "\r\n" + "\r\n" + "delky parametru: a= " + a_length * 8 + " bits,  b= " + b_length * 8 + " bits,  mod= " + m_length * 8 + " bits \r\n" + "\r\n";

        //}





        #endregion
    }



}

