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

          Merhabalar,

          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. S-DES Algoritmasında Key(Anahtar) 10 bit'den oluşur bunun yanısıra şifrelenecek temiz metin(Plain Text) 8 bit den oluşur ve şifreleme işlemi sonucu ortaya çıkan şifrelenmiş metin(Cipher Text) de 8 bit den oluşur. İlk önce S-DES Algoritmasının genel bir yapısını inceleyelim. Bunun için aşağıda bulunan şema bize yardımcı olacaktır.



          Burda görüldüğü gibi 10 Bit Bir anahtar giriyor ve bu anahtardan 2 tane anahtar üretiliyor ve algoritmanın çeşitli adımlarında bu anahtarlar kullanılıyor. İsterseniz ilk önce 10 bit bir değer alarak key'lerimizi oluşturalım. Ancak bu örnekleri yaparkan mümkün olduğunda object oriented bir yaklaşım izleyip mevcut yazılmış des algoritmalarından farklı birşey ortaya çıkarmaya çalışacağız. Bundan anlaşılacağı gibi Key bizim için bir nesne olacaktır. Diğer bir dikkat etmemiz gereken nokta ise Permutasyon(Permutation) fonksiyonlarını,Öteleme(Shift) fonksiyonlarını ve Encryption(Şifreleme) fonksiyonlarını ayrı classlar içine heryerden kulanılabilecek genel metodlar olarak tanımlayacağız. İlk önce projemizin Class yapısını diyagram üzerinde inceleyelim ve kodumuzu algoritmayı adım adım inceleyerek yazmaya başlayalım.



          S-DES Key'ini oluşturmak için DesKey Class'ımızı yazmaya başlıyoruz. Bu Class'ımızı yazarken önümüze çıkan parmutation ve shift metodlarını ayrıca Gerekli Class yapıları içine tanımlayacağız.
 
using System;
using System.Collections.Generic;
using System.Text;
 
namespace DesAlgorithm
{
    public class DesKey
    {
        public DesKey(string key)
        {
            _Key = key;
        }
        private string _Key;
        public string Key
        {
            get { return _Key; }
            set { _Key = value; }
        }
          Bu kısımda class'ımızı tanımlıyoruz ve Nesnemizin Constructor'unda key'i string olarak alan ve bunu aynı isimdeki property'e atan bir metod mevcut ayrıca string tipinden key'i saklayabilmek ve okuyabilmek için değişken ve bunu encapsule eden property'mizde mevcuttur. Şimdi isterseniz S-DES algoritmasında Key'in oluşturulması algoritmasını şemada daha detaylı inceleyelim ve gerekli metodları yazarak devam edelim.



        private string GenerateKeyStandart()
        {
            string binvalue = "";
            if (_Key.Length==10)
            {
                for (int i = 0; i < 10; i++)
                {
                    if (!(_Key.Substring(i, 1) == "1" || _Key.Substring(i, 1) == "0"))
                    {
                        throw new Exception("Bit Value Key Characters Must Be 1 And 0");
                    }
                }
                binvalue = _Key;
            }
            else
            {
                int intgr = int.Parse(_Key);
                binvalue = EncrytionFunctions.ConvertToBinary(intgr, 10);             
            }
            return binvalue;
        }
          Bu Key1'i ve Key2 yi oluşturuken kullanacağımız standart bir metod olduğu için ortak yapıyı böyle bir metodda tutmak kodumuzun daha yönetilebilir olmasını sağlayacaktır. Bu kodun yaptığı iş atanmış olan string key'in uzunluğu 10 sa ve sadece 1 ve 0 karakterlerinden oluşuyorsa bunu olduğu gibi geri döndürmek ancak bir integer değer atanmışsa bu integer değeri 10 bit' binary değere çevirerek geri döndürmektir. Bunun için EncryptionFunctions class'ında bulunan ConvertToBinary metodunu kullanmaktayız. Bu metodu inceleyecek olursak,
 
        public static string ConvertToBinary(int intgr,int length)
        {
            int tempValue = 0;
            string binValue = "";
            while (intgr != 0)
            {
                tempValue = intgr % 2;
                binValue = tempValue.ToString() + binValue;
                intgr = intgr / 2;
            }
            if (binValue.Length > length)
            {
                throw new Exception("Key Size Is Bigger Then " + length.ToString() + " Bits");
            }
            else
            {
                int additionalzeros = length - binValue.Length;
                if (additionalzeros > 0)
                {
                    for (int i = 0; i < additionalzeros; i++)
                    {
                        binValue = "0" + binValue;
                    }
                }
            }
            return binValue;
        }
          Bu metod bizdenbir integer değer ve sonucun kaç haneden oluşacak şekilde sunulacağını belirte bir integer parametre almakta ve verilen sayıyı sürekli 2 ye bölerek elimizde 1 ve 0 dan oluşan bir binary sayı kalmakta ve daha sonra gerekli ise bu sayının başına 0'ları ekleyerek uygun hane sayısına erişmektedir. Şimdi ise kodumuza Key1 ve Key2 nin oluşturulmasını inceleyerek devam edelim.
 
        public string BinaryKey1
        {
            get
            {
                string binvalue = GenerateKeyStandart();
                binvalue = PermutationFunctions.Pemutate10(binvalue);
                string leftPart = binvalue.Substring(0, 5);
                string rightPart = binvalue.Substring(5, 5);
                binvalue = ShiftFunctions.LeftShift(leftPart,1) + ShiftFunctions.LeftShift(rightPart,1);
                return PermutationFunctions.Permutate8(binvalue);
            }
        }
        public string BinaryKey2
        {
            get
            {
                string binvalue = GenerateKeyStandart();
                binvalue = PermutationFunctions.Pemutate10(binvalue);
                string leftPart = binvalue.Substring(0, 5);
                string rightPart = binvalue.Substring(5, 5);
                binvalue = ShiftFunctions.LeftShift(leftPart,2) + ShiftFunctions.LeftShift(rightPart,2);
                return PermutationFunctions.Permutate8(binvalue);
             }
        }
    }
}
          Key oluşturma aşamasındaki kod yukarıdaki gibidir genel algoritma açıklandıktan sonra fonksiyonlar yazılacaktır. Key1 oluşturulurken ilk önce _Key değişkeninde bulunan değer biraz önce yazdığımız GenerateKeyStandart() metodundan geçirilerek bir string değerine atanıyor, Bu string de tutulan 10 bit değer P10 permutasyon fonksiyonundan geçiriliyor ve daha sonrasında ilk ve son 5 bit olmak üzere ikiye bölünütor. İlk bölümü ve ikinci 1 karakter sola öteledikten sonra oluşan değerleri birleştiriyor ve P8 permutasyon fonksiyonuna sokuyoruz. Buda bize 8 bit bir değer döndürüyor. Key2 oluşturulurken tek farklılık 1 adım sola öteleme yapılan kısımda yapılan ötelemenin 2 adım yapılmasıdır, Bit yerleri değiştiği için elimize ikinci anahtar için P8 fonksiyonundan farklı bir binary değer geçmektedir. Şimdi bu işlemler sırasında kullanılan metodları inceleyelim ilk önce P10 fonksiyonu ile başlayabiliriz.

P10
3 5 2 7 4 10 1 9 8 6


         Bu metod bize karakterlerin yerlerinin nasıl değiştirileceğini belirtmektedir örneğin P10 fonksiyonuna giren 10 bit değer çıkarken girişte 3. sırada yer alan değer çıkışta 1. sırada, girişte 5. sırada yer aşan değer çıkışta 2. sırada yer alacaktır.

         P8 fonksiyonu ise P10 ile aynı mantıktadır ancak sıralama farklıdır.

P8
6 3 7 4 8 5 10 9


Left Shift fonksiyonu ise verilen değeri verilen karakter kadar sola ötelemektedir. Şimdi isterseniz bu 3 metodun nasıl yazıldığını inceleyelim.

        public static string Pemutate10(string str)
        {
            int[] permutation10Rules = new int[10];
            permutation10Rules[0] = 2 ;
            permutation10Rules[1] = 4;
            permutation10Rules[2] = 1 ;
            permutation10Rules[3] = 6;
            permutation10Rules[4] = 3 ;
            permutation10Rules[5] = 9;
            permutation10Rules[6] = 0 ;
            permutation10Rules[7] = 8;
            permutation10Rules[8] = 7 ;
            permutation10Rules[9] = 5;
            string retVal = "";
            for (int i = 0; i < 10; i++)
            {
                retVal = retVal + str.Substring(permutation10Rules[i], 1);
            }
            return retVal;
        }
        public static string Permutate8(string str)
        {
            int[] permutation8Rules = new int[8];
            permutation8Rules[0] = 5;
            permutation8Rules[1] = 2;
            permutation8Rules[2] = 6;
            permutation8Rules[3] = 3;
            permutation8Rules[4] = 7;
            permutation8Rules[5] = 4;
            permutation8Rules[6] = 9;
            permutation8Rules[7] = 8;
            string retVal = "";
            for (int i = 0; i < 8; i++)
            {
                retVal = retVal + str.Substring(permutation8Rules[i], 1);
            }
            return retVal;
        }
        public static string LeftShift(string str,int shiftDegree)
        {
            string retval = "";
            retval = str.Substring(shiftDegree, str.Length - shiftDegree) + str.Substring(0, shiftDegree);
            return retval;
        }
        public static string RightShift(string str, int shiftDegree)
        {
            string retval = "";
            retval = str.Substring(0, shiftDegree) + str.Substring(shiftDegree, str.Length - shiftDegree);
            return retval;
        }
         Bu metodlarında incelenmesinden sonra key üretilmesi işlemini tamamlamış oluyoruz. Şimdi sırada şifreleme algoritmasının incelenmesi var. İlk önce şema üzerinde bir inceleme yapalım ve daha sonrasında kodumuzu yazarken algoritmayı çözelim



          Bu kısımda sözü geçen fonksiyon fK(L,R) = L XOR F(R,Ki),           R şeklinde ifade edilmektedir burada bulunan;
          L:Solda Bulunan 4 bit
          R:Sağda Bulunan 4 bit
          K:Key
          F:Şifrelemenin yapıldığı temel fonksiyon'u temsil etmektedir.         

PlainText ismini verdiğmiz ve içinde Encrypt metodu bulunan class'ımızı yazmaya başlayalım.
 
using System;
using System.Collections.Generic;
using System.Text;
 
namespace DesAlgorithm
{
    public class PlainText
    {
        public PlainText()
        {
        }
        public PlainText(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;
            }
        }
          PlainText clas'ımızın şifrelenecek metni parametre olarak alan bir Constructor'u bulunmaktadır bunun yanı sıra _Text adında string tipinden bir değişken ve bu değişkene değer atamakta veya okumakta kullanılan Text isminde bir peoprty barındırır. Bunun yanı sıra Read Only olan bir diğer property ise BinaryText'dir ve bu property Text propertysine atadığımız metni daha önce açıkladığımız ConvertToBinary fonksiyonunu kullanarak binary şekilde ifade edilebilir biçme çevirir.

         Şimdi isterseniz bu class'ın Encrypt metodunu inceleyelim.
        public CipherText Encrypt(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= EncryptFunction(EncrytionFunctions.Switch( EncryptFunction(binaryVal, key.BinaryKey1)),key.BinaryKey2);
                binaryVal = PermutationFunctions.PermutateInverseIP(binaryVal);
                cText.Text += ((char)EncrytionFunctions.ConvertToDecimal(binaryVal)).ToString();
            }
            return cText;
        }
          Bu metodumuz bize şifrelenmiş metni ifade eden CipherText nesnesini föndüreceğinden metodun ilk satırlarında bu nesneden oluşturuyoruz, Daha sonra gelen metninde bulunan her karakteri Binary yapıya çeviriyor, IP Permutasyon fonksiyonundan geçiriyor, Elde ettiğimiz yeni binary 8 bit değeri Key1 ile birlikte F ile ifade ettiğimiz EncryptFunction'a parametre olarak veriyoruz, Bu fonksiyondan çıkan değerimizi Switch e sokarak sağdaki ve soldaki 4 bit'lerin yerlerini değiştirerek bu sefer şifrelemenin sol taraf iin yapılmasını sağlıyoruz ve aynı fonksiyona bu sefer Key2 parametresi ile yolluyoruz., Burdan bize dönene 8 bit değeri IP-1(Inverse) Fonksiyonuna sokuyoruz ve elimize geçen binary değeri decimal değere ve ordanda char tipine çevirip yaratmış olduğumuz CipherText nesnesinin Text propertysinin append ediyoruz.
        
         Şimdi öncelikle IP,IP-1 ve ConvertTodecimal metodlarını yazalım ve arkasından EncryptFunction metodunu detaylı olarak inceleyelim.

IP
2 6 3 1 4 8 5 7

IP-1
4 1 3 5 7 2 8 6
Permutasyon fonksiyonlarının çalışma mantığı daha önceden açıklandığı için bu 2 metodu ayrıca açıklamaya gerek yok, Ancak kodlarını yazalım.

        public static string PermutateIP(string str)
        {
            int[] permutationIpRules = new int[8];
            permutationIpRules[0] = 1;
            permutationIpRules[1] = 5;
            permutationIpRules[2] = 2;
            permutationIpRules[3] = 0;
            permutationIpRules[4] = 3;
            permutationIpRules[5] = 7;
            permutationIpRules[6] = 4;
            permutationIpRules[7] = 6;
            string retVal = "";
            for (int i = 0; i < 8; i++)
            {
            permutationIpRules[7] = 6;
            retVal = retVal + str.Substring(permutationIpRules[i], 1);
            }
            return retVal;
        }
        public static string PermutateInverseIP(string str)
        {
            int[] permutationInverseIpRules = new int[8];
            permutationInverseIpRules[0] = 3;
            permutationInverseIpRules[1] = 0;
            permutationInverseIpRules[2] = 2;
            permutationInverseIpRules[3] = 4;
            permutationInverseIpRules[4] = 6;
            permutationInverseIpRules[5] = 1;
            permutationInverseIpRules[6] = 7;
            permutationInverseIpRules[7] = 5;
            string retVal = "";
            for (int i = 0; i < 8; i++)
            {
                retVal = retVal + str.Substring(permutationInverseIpRules[i], 1);
            }
            return retVal;
        }
        public static int ConvertToDecimal(string str)
        {
            int intgr = 0;
            for (int i = 0; i < str.Length; i++)
            {
                double result = double.Parse(str.Substring(str.Length - 1 - i, 1)) * Math.Pow(2, i);
                intgr += (int)result;
            }
            return intgr;
        }
          Yukarıda bulunan permutasyon metodlarının nasıl yazıldığını açıklamaya gerek yoktur ancak ConvertToDecimal metodunu aaçıklayacak olursak burada 8 bit değerler sıra ile 2 nin üsleri ile çarpılarak 10 luk sisteme çevriliyor ve sonuçta elimizde bir integer değer bulunuyor.

EncryptFunction isimli metodumuzun yazılmasını ve daha ilerisindeki konuları makalenin 2. kısmında inceleyeceğiz.

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