Makale Özeti

Bu makalemde sizlerle birlikte Modern Simetrik şifreliyicilerden en çok kullanılan Data Encryption Standard (DES) türevi olan Stream Cipher'lardan Simplified DES i inceleyeceğiz ve algoritmasını yazacağız.

Makale

         İlk kısımda geldiğimiz noktadan sonra şimdi ise EncryptFunction isimli metodu inceleyelim. IP permutasyon fonksiyonndan çıkan 8 bit bu fonksiyona girer ve burada sağdaki 4 ve soldaki 4 bit ayrılırla, Sağdaki 4 Bit E/P permutasyon fonksiyonu ile 8 bit'e çevrilir ve Key ile XOR fonksiyonuna girerler, Bu fonksiyondan çıkan 8 bit S-Box'lar sayesinde 4 bit e indirgenir ve İlk başta aldığımız Soldaki 4 bit ile bir daha XOR fonksiyonuna girer ve en son olarak P4 permutasyon fonksiyonuna girdikten sonra bu fonksiyondan çıkacak 8 bitlik değerin soldaki 4 bitini oluşturur sağdaki 4 bit ise başlangıçtaki ile aynıdır.

         Bu metodumuzu kodu ile birlikte biraz daha detaylı inceleyelim.

 
        private string EncryptFunction(string binaryVal, string key)
        {
            string leftPart = binaryVal.Substring(0, 4);
            string rightPart = binaryVal.Substring(4, 4);
            string afterEp = PermutationFunctions.PermutateEP(rightPart);
            string afterxOr = "";
            for (int j = 0; j < 8; j++)
            {
                afterxOr += EncrytionFunctions.exclusiveOr(afterEp.Substring(j, 1), key.Substring(j, 1));
            }
            string afterSBoxes = "";
            int row = EncrytionFunctions.ConvertToDecimal(afterxOr.Substring(0, 1) + afterxOr.Substring(3, 1));
            int column = EncrytionFunctions.ConvertToDecimal(afterxOr.Substring(1, 1) + afterxOr.Substring(2, 1));
            afterSBoxes += EncrytionFunctions.ConvertToBinary(EncrytionFunctions.S0(row, column),2);
 
            row = EncrytionFunctions.ConvertToDecimal(afterxOr.Substring(4, 1) + afterxOr.Substring(7, 1));
            column = EncrytionFunctions.ConvertToDecimal(afterxOr.Substring(5, 1) + afterxOr.Substring(6, 1));
            afterSBoxes += EncrytionFunctions.ConvertToBinary(EncrytionFunctions.S1(row, column),2);
            string afterP4 = PermutationFunctions.Permutate4(afterSBoxes);
            string afterXOr2 = "";
            for (int j = 0; j < 4; j++)
            {
                afterXOr2 += EncrytionFunctions.exclusiveOr(afterP4.Substring(j, 1), leftPart.Substring(j, 1));
            }
            string encrypted = afterXOr2 + rightPart;
            return encrypted;
        }
          Bu metodumuz bizden 8 bit uzunluğundaki plaintext i ve key i alıyor. Daha sonrasında gelen 8 bitlik bu değerin soldaki 4 bit i leftPart sağdaki 4 bit i ise rightPart isimli değişkenlere atanıyor. Daha sonra rightPart değişkeni E/P permutasyon fonksiyonuna sokuluyor ve çıkan değer afterEp değişkenine atanıyor ve geriye 8 bit lik bir değer dönüyor. E/P fonksiyonunun yapısını inceleyecek olursak,

E/P
4 1 2 3 2 3 4 1
         Şimdi ise kodunu inceleyelim
 
        public static string PermutateEP(string str)
        {
            int[] permutationEPRules = new int[8];
            permutationEPRules[0] = 3;
            permutationEPRules[1] = 0;
            permutationEPRules[2] = 1;
            permutationEPRules[3] = 2;
            permutationEPRules[4] = 1;
            permutationEPRules[5] = 2;
            permutationEPRules[6] = 3;
            permutationEPRules[7] = 0;
            string retVal = "";
            for (int i = 0; i < permutationEPRules.Length; i++)
            {
                retVal = retVal + str.Substring(permutationEPRules[i], 1);
            }
            return retVal;
        }
          Bu fonksiyondan çıkan 8 bit lik değer ile key de bulunan 8 bit lik değer tek tek XOR fonksiyonuna sokularak sonuçta ortaya çıkan 8 bitlik değer afterxOr değişkenine atanıyor, xOr fonksiyonunu inceleyecek olursak,
 
        public static string exclusiveOr(string a, string b)
        {
           
            if (a != b)
            {
                return "1";
            }
            else
            {
                return "0";
            }
        }
          xOr fonksiyonuna giren değerlerin aynı olması durumunda 0 farklı olması durumunda ise 1 değerini döndürmektedir. Kodu oldukça basittir, Bu işlemden sonra Bu algoritmanın temelini oluşturan sBox lar üzerinde işlem yapacağız, Sbox lar ın yapısını inceleyelim ve daha sonra çalışma mantıklarını irdeleyelim.

S0 S1
0 1 2 3
0 1 0 3 2
1 3 2 1 0
2 0 2 1 3
3 3 1 3 2
0 1 2 3
0 0 1 2 3
1 2 0 1 3
2 3 0 1 0
3 2 1 0 3

          SBOX'lar da kolon ve sıra seçilirken 2 bit değerlerin ondalık sisteme çevrilmiş karşılıkları olarak numaralar kullanılı örneğin elimizde 11 şeklinde binary bir değer varsa bu ondalık sistemde 3 e karşılık geldiğinden sıra veya sütünda 3 ü seçeriz diğer değer içinde aynı şekilde işlem yaparız ve kesiştikleri yerdeki rakamı buluruz, bulduğumuz bu rakamı tekrar 2 bit şekilinde binary bir değere çevririz.

         S0 için sıra'da seçeceğimiz değer xOr fonksiyonundan çıkan 8 bit değerdeki 1. ve 4. değerlerin yan yana yazılmasından orata çıkan değerdir, sütunda seçeceğimiz değer ise 2. ve 3. değerlerin yan yana yazılmasıyla ortaya çıkar.S1 için ise sırayı 5. ve 8. değerler oluşturuken sütunu 6. ve 7. değerler oluşturur. Ve geri dönen değerler tekrardan binary şeklie çevrilir Böylece sBox lar 4 bit değer alıp bize 2 bit değer döndürmektedir. Yani E/P fonksiyonunda 8 bite çevirdiğimiz bit sayısını tekrar 4 e indirgeriz.
 
        public static int S0(int rowNumber, int columnNumber)
        {
            if (rowNumber == 0)
            {
                if (columnNumber == 0){ return 1; }
                else if (columnNumber == 1){ return 0; }
                else if (columnNumber == 2){ return 3; }
                else if (columnNumber == 3){ return 2; }
                else{ throw new Exception("Invalid S0 Value"); }
            }
            else if (rowNumber == 1)
            {
                if (columnNumber == 0){ return 3; }
                else if (columnNumber == 1){ return 2; }
                else if (columnNumber == 2){ return 1; }
                else if (columnNumber == 3){ return 0; }
                else{ throw new Exception("Invalid S0 Value"); }
            }
            else if (rowNumber == 2)
            {
                if (columnNumber == 0){ return 0; }
                else if (columnNumber == 1){ return 2; }
                else if (columnNumber == 2){ return 1; }
                else if (columnNumber == 3){ return 3; }
                else{ throw new Exception("Invalid S0 Value"); }
            }
            else if (rowNumber == 3)
            {
                if (columnNumber == 0){ return 3; }
                else if (columnNumber == 1){ return 1; }
                else if (columnNumber == 2){ return 3; }
                else if (columnNumber == 3){ return 2; }
                else{ throw new Exception("Invalid S0 Value"); }
            }
            else
            { throw new Exception("Invalid S0 Value"); }
        }
        public static int S1(int rowNumber, int columnNumber)
        {
            if (rowNumber == 0)
            {
                if (columnNumber == 0){ return 1; }
                else if (columnNumber == 1){ return 1; }
                else if (columnNumber == 2){ return 2; }
                else if (columnNumber == 3){ return 3; }
                else{ throw new Exception("Invalid S1 Value"); }
            }
            else if (rowNumber == 1)
            {
                if (columnNumber == 0){ return 2; }
                else if (columnNumber == 1){ return 0; }
                else if (columnNumber == 2){ return 1; }
                else if (columnNumber == 3){ return 3; }
                else{ throw new Exception("Invalid S1 Value"); }
            }
            else if (rowNumber == 2)
            {
                if (columnNumber == 0){ return 3; }
                else if (columnNumber == 1){ return 0; }
                else if (columnNumber == 2){ return 1; }
                else if (columnNumber == 3){ return 0; }
                else{ throw new Exception("Invalid S1 Value"); }
            }
            else if (rowNumber == 3)
            {
                if (columnNumber == 0){ return 2; }
                else if (columnNumber == 1){ return 1; }
                else if (columnNumber == 2){ return 0; }
                else if (columnNumber == 3){ return 3; }
                else{ throw new Exception("Invalid S1 Value"); }
            }
            else
            { throw new Exception("Invalid S1 Value"); }
        }
          S-Box ların kodumuzdaki fonksiyonları bu şekildedir. SBox'lardan çıkan 2 bit lik değerler yan yana yazılır ve elimize 4 bit değer oluşur oluşan bu 4 bitlik değeri P4 fonksiyonundan geçirirz ve daha sonrasında ilk başta bulduğumuz soldaki 4 bit ile xOr fonksiyonuna sokarız.

P4
2 4 3 1
 
        public static string Permutate4(string str)
        {
            int[] permutation4Rules = new int[8];
            permutation4Rules[0] = 1;
            permutation4Rules[1] = 3;
            permutation4Rules[2] = 2;
            permutation4Rules[3] = 0;
            string retVal = "";
            for (int i = 0; i < 4; i++)
            {
                retVal = retVal + str.Substring(permutation4Rules[i], 1);
            }
            return retVal;
        }
          P4 permutasyon fonksiyonuda yukarıdaki şekilde yazılabilir. Bunun yanı sıra ilk adımın sonunda yer alan switch fonksiyonunu ise aşağıdaki gibi yazmak mümkündür, Switch fonksiyonu daha öncede bahsettiğimiz gibi sağdaki ve soldaki 4 bit in yerini değiştirmekte ve dolayısıyla ilk adım sonunda değişmemiş olan sağdaki 4 biti fonksiyona sokmakta faydalıdır.
 
        public static string Switch(string text)
        {
            return text.Substring(4, 4) + text.Substring(0, 4);
        }
          Des algoritmasında ikinci adımdaki fonksiyon ilk adımdaki ile aynıdır, ancak tek fark bu sefer 2. Key'in kullanılmasıdır. 2. adımdanda çıkan değerler IP-1 fonksiyonundan geçirilerek nihai sonuç elde edilir.

         Şimdi ise Diğer bir classımız olan CipherText i inceleyelim. CipherText yapı olarak PlainText ile aynı yapıdadır. Ancak Encrypt Metodu yerine Decrypt metodu vardır. Des Algoritmasında Decrypt işlemi yapılması için gerekli olan tek şey Key1 ve Key2 nin yerlerini değiştirmektir.

using System;
using System.Collections.Generic;
using System.Text;
 
namespace DesAlgorithm
{
    public class CipherText
    {
        public CipherText()
        {
        }
        public CipherText(string text)
        {
            _Text = text;
        }
        private string _Text;
        public string Text
        {
            get { return _Text; }
            set
            {
                _Text = value;
               
            }
        }
        public string BinaryText
        {
            get
            {
                string _BinaryText = "";
                for (int i = 0; i < _Text.Length; i++)
                {
                    _BinaryText += EncrytionFunctions.ConvertToBinary((int)_Text.ToCharArray()[i], 8);
                }
                return _BinaryText;
            }
        }
        private string DecryptFunction(string binaryVal, string key)
        {
            string leftPart = binaryVal.Substring(0, 4);
            string rightPart = binaryVal.Substring(4, 4);
            string afterEp = PermutationFunctions.PermutateEP(rightPart);
            string afterxOr = "";
            for (int j = 0; j < 8; j++)
            {
                afterxOr += EncrytionFunctions.exclusiveOr(afterEp.Substring(j, 1), key.Substring(j, 1));
            }
            string afterSBoxes = "";
            int row = EncrytionFunctions.ConvertToDecimal(afterxOr.Substring(0, 1) + afterxOr.Substring(3, 1));
            int column = EncrytionFunctions.ConvertToDecimal(afterxOr.Substring(1, 1) + afterxOr.Substring(2, 1));
            afterSBoxes += EncrytionFunctions.ConvertToBinary(EncrytionFunctions.S0(row, column), 2);
 
            row = EncrytionFunctions.ConvertToDecimal(afterxOr.Substring(4, 1) + afterxOr.Substring(7, 1));
            column = EncrytionFunctions.ConvertToDecimal(afterxOr.Substring(5, 1) + afterxOr.Substring(6, 1));
            afterSBoxes += EncrytionFunctions.ConvertToBinary(EncrytionFunctions.S1(row, column), 2);
            string afterP4 = PermutationFunctions.Permutate4(afterSBoxes);
            string afterXOr2 = "";
            for (int j = 0; j < 4; j++)
            {
                afterXOr2 += EncrytionFunctions.exclusiveOr(afterP4.Substring(j, 1), leftPart.Substring(j, 1));
            }
            string encrypted = afterXOr2 + rightPart;
            return encrypted;
        }
        public CipherText Decrypt(DesKey key)
        {
            string binaryVal = "";
            CipherText cText = new CipherText();
 
            for (int i = 0; i < _Text.Length; i++)
            {
                binaryVal = EncrytionFunctions.ConvertToBinary((int)_Text.ToCharArray()[i], 8);
                binaryVal = PermutationFunctions.PermutateIP(binaryVal);
                binaryVal = DecryptFunction(EncrytionFunctions.Switch(DecryptFunction(binaryVal, key.BinaryKey2)), key.BinaryKey1);
                binaryVal = PermutationFunctions.PermutateInverseIP(binaryVal);
                cText.Text += ((char)EncrytionFunctions.ConvertToDecimal(binaryVal)).ToString();
            }
            return cText;
        }
    }
}


          Şimdi ise sırada bu metodların uygulanabilirliğini inceleyeceğimiz örnek bir uygulama yazmaya geldi. Uyguamanın User Interface kısmı aşağıdaki gibi olacaktır. ancak kod tarafında yazdığımız başarılı metodların sonucu pek bir kod yazmayacağız.



         Encrypt buttonu tıklandığınd aypmamız gereken iş key alanına yazılmış key den bir key nesnesi oluşturmak ve bir plaintext nesnesini plaintext alanına girilmiş veriden oluşturup bu nesnenin Encrypt fonksiyonunu key nesnesini parametre olarak vereek çağırmaktır. Decrypt butonu tıklandığı zaman ise yine bir key nesnesi oluşturmak ve şifrelenmiş metinden bir ciphertext nesnesi oluşturarak bu nesnenin Decrypt metoduna key nesnesini parametre olarak vermektir. isterseniz kodları inceleyelim

        private void btnEncrypt_Click(object sender, EventArgs e)
        {
            DesKey key = new DesKey(txtKey.Text);
            PlainText p = new PlainText(txtPlainText.Text);
            txtCipherText.Text = p.Encrypt(key).Text;
            txtKey1.Text = key.BinaryKey1;
            txtKey2.Text = key.BinaryKey2;
        }
 
        private void btnDecrypt_Click(object sender, EventArgs e)
        {
            DesKey key = new DesKey(txtDKey.Text);
            CipherText c = new CipherText(txtDCiphertext.Text);
            txtDPlainText.Text = c.Decrypt(key).Text;
            txtDKey1.Text = key.BinaryKey2;
            txtDKey2.Text = key.BinaryKey1;
        }


         Böylece her uygulamamızda kullanabileceğimiz des algoritmasını implement eden nesnelerimizi ve fonksiyonlarımızı yazmış olduk. Artık verilerimizi güvenle saklayabiliriz.

oztamer@hotmail.com
tamer.oz@yazgelistir.com
oztamer@hotmail.com

 

Ornek Kodlar