İlginizi Çekebilir
  1. Ana Sayfa
  2. C Sharp

C# Şifreli Mesajlaşma – Diffie Hellman + AES Şifreleme

C# Şifreli Mesajlaşma – Diffie Hellman + AES Şifreleme
+ - 0

Merhabalar, bu gün C# Şifreli Mesajlaşma – Diffie Hellman + AES Şifreleme konusuna bakacağız. Bu konuyu bir sitede görmüştüm. Dersi yazan arkadaş hiçbir şeyden bahsetmeden ve hiçbir şeyi açıklamadan direk kodları vermiş geçmiş. Birde programın nasıl çalıştığını gösteren bir video yüklemişti. (Bunu bende yapacağım. :) )

Böylesi dersleri hiç sevmiyorum. Bu sebeple bende bu dersi aldım kendimden bir şeyler ekleyerek daha güzel ve kullanışlı hale getirerek yeniden yaptım. Aşağıdaki videoda projenin nası çalıştığını görebilirsiniz.

Bu projeyi hazırlamadan önce bahsettiğim arkadaşın verdiği kodları kullanarak bir form hazırladım. Verilen kodlar tek form içinde iki kullanıcının mesajlaşması şeklindeydi. Kodların çalışma şeklini çözdükten sonra da bu kodları iki ayrı forma bölerek formlar arası mesajlaşma şeklinde çevirdim. Aşağıda kodlarını görebilirsiniz. Ayrıca projeyi github’a yükleyeceğim oradan da projeyi indirip kullanabilirsiniz.

Önizleme videosu…

C# Şifreli Mesajlaşma – Diffie Hellman + AES Şifreleme

Uygulamayı anlatmaya geçmeden önce Diffie Hellman ve AES’ten bahsetmek istiyorum.

Diffie Hellman Nedir?

Kriptografik anahtarların değişimi amacı ile 1976 yılında, Martin Hellman ve Whitfield Diffie tarafından yayınlanan bir tasarımdır. Güvenliksiz bir ağda iki tarafın ortak bir anahtar ile mesajların şifrelenerek güvenli haberleşmesini sağlar.

Biraz daha netleşmesi için bir örnek üzerinden anlatmaya çalışayım. Taraflar herkesin gördüğü 2 ve gizli olan 2 sayı seçiyor.  Tarafların gönderdiği anahtarlar üzerinde yapılan matematiksel işlemler sonucunda aynı sonuca ulaşmayı hedeflemektedir. İki uçta aynı sonuca ulaştıysa şifreli bağlantı sağlanmış anlamına gelir.

Bu konuyu daha ayrıntılı bir şekilde anlattığım yazıma Diffie-Hellman Nedir? Diffie-Hellman Anahtar Değişimi bağlantıya tıklayarak ulaşabilirsiniz..

 

AES Şifreleme Nedir?

AES, (Advanced Encryption Standard –  Gelişmiş Şifreleme Standardı) bir Kriptografi şifreleme anlamına gelir. Dijital verilerin şifrelenmesi amacı ile sunulmuş olan bir sistemdir. Amerika tarafından da kabul edilmiş olan AES, uluslararası boyutta da şifreleme standartı olarak kabul edilmiştir ve kullanılmaktadır.

En büyük örneği WhatsApp olarak verebiliriz. Popüler mesajlaşma uygulaması olan WhatsApp ‘ta AES şifreleme standardını kullanmaktadır.

AES algoritması ile şifrelenen bir verinin çözümlenmesi teknik olarak imkansızdır diyebiliriz.  128 bit şifreleme ile şifrelendiğinde 2128 adet farklı anahtarı vardır. Bu sebeple bu şifrelenmiş verinin çözümlenmesi için çok büyük zaman ve maliyet gerekmektedir. Mevcut teknoloji düşünüldüğünde 128 bitlik şifrenin çözülebilmesi için 100 yıl kadar bir zaman gerekmektedir.

Bu konuyu daha ayrıntılı bir şekilde anlattığım yazıma AES Şifreleme Nedir? AES Güvenliği bağlantıya tıklayarak ulaşabilirsiniz..

Şimdi uygulamamıza geçelim.

 

C# Şifreli Mesajlaşma

Yukarıdaki videoda çalışma şeklini ve form tasarımlarını görüyorsunuz. Şimdi size kodları elimden geldiğince açıklayarak vereceğim. Tek Formda Göster formu bu konuyu bulduğum dersteki halidir. O kısmı hiç anlatmayacağım. Ben bu formun içindeki bilgileri 3 parçaya böldüm ve videodaki hale getirdim. Bu derste de o 3 formu anlatacağım.

ECDiffieHellmanCng_Class.cs

Öncelikle ECDiffieHellmanCng_Class adında bir class tanımlaması yapıyoruz ve anahtarları oluşturacak kodlarımızı bu class dosyamıza alıyoruz. Tüm class dosyasını olduğu gibi veriyorum.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace AES_Cryptic_Chat
{
    public class ECDiffieHellmanCng_Class
    {

        public static byte[] kullanici_1_Pulic_Key, kullanici_2_Pulic_Key;
        public static byte[] ortak_Anahtar;
        public static byte[] baslatma_Vektoru_IV;


        public static string txt_Kul_1_Public_Key = "";
        public static string txt_Kul_2_Public_Key = "";
        public static string txt_Ortak_Anahtar = "";

        public static void KeyUret()
        {
            
            using (ECDiffieHellmanCng ecd1 = new ECDiffieHellmanCng())
            {
                ecd1.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
                ecd1.HashAlgorithm = CngAlgorithm.Sha256;
                kullanici_1_Pulic_Key = ecd1.PublicKey.ToByteArray();
                txt_Kul_1_Public_Key = Convert.ToBase64String(kullanici_1_Pulic_Key);

                using (ECDiffieHellmanCng ecd2 = new ECDiffieHellmanCng())
                {
                    ecd2.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
                    ecd2.HashAlgorithm = CngAlgorithm.Sha256;

                    kullanici_2_Pulic_Key = ecd2.PublicKey.ToByteArray();
                    txt_Kul_2_Public_Key = Convert.ToBase64String(kullanici_2_Pulic_Key);

                    ortak_Anahtar = ecd2.DeriveKeyMaterial(CngKey.Import(kullanici_1_Pulic_Key, CngKeyBlobFormat.EccPublicBlob));
                    txt_Ortak_Anahtar = Convert.ToBase64String(ortak_Anahtar);

                }
            }
        }
    }
}

Bu kodlarda anlatabileceğim bir şey yok maalesef.

Chat_Class.cs

Ardından, formlar arasındaki iletişimi sağlayabilmek için bir class tanımlaması daha yapıyoruz. Bu class dosyasında anlatacak bir şey yok. Sadece iki adet değişken bulunuyor. Bu değişkenleri yukarıdaki class içerisine de ekleyebilirsiniz. Ben ayrı bir class olarak tanımlamak istedim.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AES_Cryptic_Chat
{
    public class Chat_Class
    {

        public static byte[] Kullanici_1_Mesaj, Kullanici_2_Mesaj;

    }
}

 

Anaform.cs

Aşağıda ana formdaki kodları görebilirsiniz.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AES_Cryptic_Chat
{
    public partial class AnaForm : Form
    {
        public AnaForm()
        {
            InitializeComponent();
        }
        private void AnaForm_Load(object sender, EventArgs e)
        {
            // Şifreli mesajlaşmayı sağlayan keyleri üretecek olan kodlarımızı class içerisine aldık.
            // keyleri classta ürettikten sonta public değişkenler ile ana forma getirdik.
            ECDiffieHellmanCng_Class.KeyUret();
            txt_Baslatma_Vektoru_IV.Text = ECDiffieHellmanCng_Class.txt_Ortak_Anahtar;
            txt_Kul_1_Public_Key.Text = ECDiffieHellmanCng_Class.txt_Kul_1_Public_Key;
            txt_Kul_2_Public_Key.Text = ECDiffieHellmanCng_Class.txt_Kul_2_Public_Key;

        }
        private void btn_kul1_Click(object sender, EventArgs e)
        {
            Kullanici_1_Ekran fr = new Kullanici_1_Ekran();
            fr.Show();
        }

        private void btn_kul2_Click(object sender, EventArgs e)
        {
            Kullanici_2_Ekran fr = new Kullanici_2_Ekran();
            fr.Show();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            TekFormdaGoster fr = new TekFormdaGoster();
            fr.ShowDialog();
        }
    }
}

Anahtarları oluşturacak kodlarımızı class dosyasına çekmiştik. Anaform ‘un load eventinde bu class’ı çalıştırıyoruz ve diğer formlarda kullanmamız gereken anahtarları üretiyoruz.

NOT: Burada Anaform’daki nesneleri kullanmadan değişkenler üzerinden de kullanabilirdik. Sadece üretilen anahtarları görmek istediğimiz için textboxlara yazıyoruz. Zaten diğer formlarda class dosyasındaki değişkenleri kullanıyoruz.

 

Kullanici_1_Ekran.cs

Kullanici_1_Ekran ve Kullanici_2_Ekran teknik olarak aynı. Kullanici_1_Ekran’de Kullanici_2_Ekran’dan gelen mesajları gösterirken, Kullanici_2_Ekran’da Kullanici_1_Ekran’den gelen mesajları tutan değişkenler kullanılıyor. Ancak ben iki formun kodlarını da vereceğim.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AES_Cryptic_Chat
{
    public partial class Kullanici_1_Ekran : Form
    {
        public Kullanici_1_Ekran()
        {
            InitializeComponent();
        }

        private void Kullanici_1_Ekran_Load(object sender, EventArgs e)
        {
            // Gelen ve giden mesajları timer ile kontrol edip alacağız.
            timer1.Interval = 100;
            timer1.Enabled = true;
            timer1.Start();
        }

        private void btn_Gonder_Kul_1_Click(object sender, EventArgs e)
        {
            // Gönderme sadece buton ile olacak ama geleni alma kısmını timer yapacak.
            // Timer olmaz ise sadece mesaj gönderdiğimizde gelenden haberimiz olur.
            Gonder();
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            // Timer ile geleni kontrol ediyoruz.
            Al();
        }

        void Gonder()
        {
            string messageToSend = txt_gonderilecek.Text;
            using (Aes aes = new AesCryptoServiceProvider())
            {
                // Classımız da üretilen keyler ile işlemlerimizi yapıyoruz.
                aes.Key = ECDiffieHellmanCng_Class.ortak_Anahtar;
                if (ECDiffieHellmanCng_Class.baslatma_Vektoru_IV == null || ECDiffieHellmanCng_Class.baslatma_Vektoru_IV.Length <= 0)
                    ECDiffieHellmanCng_Class.baslatma_Vektoru_IV = aes.IV;
                else
                    aes.IV = ECDiffieHellmanCng_Class.baslatma_Vektoru_IV;
                ECDiffieHellmanCng_Class.txt_Ortak_Anahtar = Convert.ToBase64String(ECDiffieHellmanCng_Class.baslatma_Vektoru_IV);
                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        byte[] plainTextMessage = Encoding.UTF8.GetBytes(messageToSend);
                        cs.Write(plainTextMessage, 0, plainTextMessage.Length);
                        cs.Close();
                        // Sadece göndermek istediğimiz mesajı gönderiyoruz. 
                        // Ekrana gelecek olan bilgiler kullanıcı 2'den gelecek olan bilgilerdir.
                        Chat_Class.Kullanici_1_Mesaj = ms.ToArray();
                    }
                }
            }
        }

        void Al()
        {
            try
            {
                using (Aes aes = new AesCryptoServiceProvider())
                {
                    aes.Key = ECDiffieHellmanCng_Class.ortak_Anahtar;
                    aes.IV = ECDiffieHellmanCng_Class.baslatma_Vektoru_IV;
                    using (MemoryStream ms = new MemoryStream())
                    {
                        using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
                        {
                            // Biz kullanıcı 1'iz 
                            // Kullanıcı 2'den gelen bilgileri ekranımızda gösteriyoruz.
                            // Bu işlemi class kullanarak yaptığımızdan dolayı timer bizim için çok önemlidir.
                            cs.Write(Chat_Class.Kullanici_2_Mesaj, 0, Chat_Class.Kullanici_2_Mesaj.Length);
                            cs.Close();
                            txt_gelen_normal.Text = Encoding.UTF8.GetString(ms.ToArray());
                            txt_gelen_sifreli.Text = Convert.ToBase64String(Chat_Class.Kullanici_2_Mesaj);
                        }
                    }
                }
            }
            // İlk açılışta bu özel durumlar çıktığından dolayı bunları eklemek zorundayız. 
            // Zaten kodların çalışmasında bir sorun yok.
            catch (ArgumentNullException)
            {
            }
            catch (NullReferenceException)
            {
            }

        }


    }
}

Burada mesajı gönderen ve mesajları alma kodlarını metodlar içerisine aldık. Gönderme işlemi buton ile kullanılırken, mesajları alan metodu timer nesnesi ile kullanılacak. Yani anlık olarak mesaj gelip gelmediği kontrol edilecek ama sadece butona tıkladığımızda mesaj gönderilecek.

Kullanıcı 1’den giden mesaj hem şifreli hemde çözülmüş olarak kullanıcı 2 ekranında gösterilecek. Kullanıcı 2’den giden mesajda hem şifreli hemde çözülmüş olarak kullanıcı 1 ekranında gösterilecek.

Ben burada anlık olarak kontrol edilmesini istediğim için timer’in Interval özelliğini 100 milisaniye olarak ayarladım. Timer nesnesinin Tick eventinde gelen mesajlar kontrol ediliyor. Gönder butonunun Click eventinde ise kodlar gönderiliyor. Diğer açıklamalar zaten kodlar üzerinde yer almaktadır.

 

Kullanici_2_Ekran.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AES_Cryptic_Chat
{
    public partial class Kullanici_2_Ekran : Form
    {
        public Kullanici_2_Ekran()
        {
            InitializeComponent();
        }

        private void Kullanici_1_Ekran_Load(object sender, EventArgs e)
        {
            // Gelen ve giden mesajları timer ile kontrol edip alacağız.
            timer1.Interval = 100;
            timer1.Enabled = true;
            timer1.Start();
        }

        private void btn_Gonder_Kul_1_Click(object sender, EventArgs e)
        {
            // Gönderme sadece buton ile olacak ama geleni alma kısmını timer yapacak.
            // Timer olmaz ise sadece mesaj gönderdiğimizde gelenden haberimiz olur.
            Gonder();
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            // Timer ile geleni kontrol ediyoruz.
            Al();
        }

        void Gonder()
        {
            string messageToSend = txt_gonderilecek.Text;
            using (Aes aes = new AesCryptoServiceProvider())
            {
                // Classımız da üretilen keyler ile işlemlerimizi yapıyoruz.
                aes.Key = ECDiffieHellmanCng_Class.ortak_Anahtar;
                if (ECDiffieHellmanCng_Class.baslatma_Vektoru_IV == null || ECDiffieHellmanCng_Class.baslatma_Vektoru_IV.Length <= 0)
                    ECDiffieHellmanCng_Class.baslatma_Vektoru_IV = aes.IV;
                else
                    aes.IV = ECDiffieHellmanCng_Class.baslatma_Vektoru_IV;
                ECDiffieHellmanCng_Class.txt_Ortak_Anahtar = Convert.ToBase64String(ECDiffieHellmanCng_Class.baslatma_Vektoru_IV);
                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        byte[] plainTextMessage = Encoding.UTF8.GetBytes(messageToSend);
                        cs.Write(plainTextMessage, 0, plainTextMessage.Length);
                        cs.Close();
                        // Sadece göndermek istediğimiz mesajı gönderiyoruz. 
                        // Ekrana gelecek olan bilgiler kullanıcı 2'den gelecek olan bilgilerdir.
                        Chat_Class.Kullanici_2_Mesaj = ms.ToArray();

                    }
                }
            }
        }

        void Al()
        {
            try
            {
                using (Aes aes = new AesCryptoServiceProvider())
                {
                    aes.Key = ECDiffieHellmanCng_Class.ortak_Anahtar;
                    aes.IV = ECDiffieHellmanCng_Class.baslatma_Vektoru_IV;
                    using (MemoryStream ms = new MemoryStream())
                    {
                        using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
                        {
                            // Biz kullanıcı 2'yiz 
                            // Kullanıcı 1'den gelen bilgileri ekranımızda gösteriyoruz.
                            // Bu işlemi class kullanarak yaptığımızdan dolayı timer bizim için çok önemlidir.
                            cs.Write(Chat_Class.Kullanici_1_Mesaj, 0, Chat_Class.Kullanici_1_Mesaj.Length);
                            cs.Close();
                            txt_gelen_normal.Text = Encoding.UTF8.GetString(ms.ToArray());
                            txt_gelen_sifreli.Text = Convert.ToBase64String(Chat_Class.Kullanici_1_Mesaj);
                        }
                    }
                }
            }
            // İlk açılışta bu özel durumlar çıktığından dolayı bunları eklemek zorundayız. 
            // Zaten kodların çalışmasında bir sorun yok.
            catch (ArgumentNullException)
            {
            }
            catch (NullReferenceException)
            {
            }
        }


    }
}

Uygulama gördüğünüz gibidir arkadaşlar. Giriş kısmında söylediğim gibi bu uygulamayı github’a yükledim. Oradan indirip dilediğiniz gibi kullanabilir hatta daha da geliştirebilirsiniz. Örnek olarak ağ üzerinden veri gönderme yolu ile ya da bir sql server aracılığı ile güvenli bir şekilde mesajlaşma uygulamaları geliştirebilirsiniz.


C# Şifreli Mesajlaşma – Diffie Hellman + AES Şifreleme dersimiz de bu kadardı arkadaşlar. Bu yazım için farklı bir kapak fotosu kullandım. Nasıl olmuş sizce? :)

C Sharp Eğitim Seti eğitimi sayfasına gitmek için tıklayınız.

C# Derslerime özel olarak hazırladığım Github Projeme buradan ulaşabilirsiniz… Bu projeye buradan ulaşabilirsiniz.

Sağlıcakla ve takipte kalın. ?

Bu yazıya tepkiniz ne oldu?

Yazar Hakkında

Lise Ağ Sistemleri ve Yönetimi bölümü, üniversite Bilgisayar Programcılığı bölümü Ön Lisans, Yönetim Bilişim Sistemleri Lisans öğrenimi aldım. Askerlik görevimi tamamladım. Uzmanlık alanım; C# ve SQL Programlama dilleri ile müşteri odaklı, kullanıcı dostu ERP ve CRM gibi sistemleri geliştirmektir. Ayrıca şuanda PHP ve MYSQL alanında projeler geliştirmekteyim. C++, Phyton, Xamarin, MVC gibi konuları öğrenmek ve kendimi geliştirme çabası içerisindeyim. Discord için: https://discord.gg/FBxZeHu9

Değerli yorumlarınızı bekliyorum. :)