Xamarin Forms AES 256 Bit Şifreleme Kullanımı

Merhabalar,

Güzel bir bayram sabahı vakit bulabilmişken hemen bilgisayar başına oturup, aklımdaki konuyu yazmak istedim 🙂

Gelen maillerden anladığım kadarıyla Xamarin.Forms ile geliştirdiğimiz mobil uygulamalarımızda şifreleme ve şifre çözme işlemleri biraz havada kalmış. Amacım bu yazı ile bu soru işaretlerini ortadan kaldırmak.

Aslında yapacağımız işlem XF tarafında desteklenmeyen kütüphaneleri, DependencyService yardımıyla Traditional tarafta halledip, geriye bir object döndürmek 🙂

Şifreleme algoritması olarak AES 256 bit kullanacağım. Bu şifreleme algoritması konusundaki orjinal kaynağa linkten ulaşabilirsiniz.

Buradaki amacımız bu şifreleme yöntemlerinin XF tarafında nasıl kullanıldığını anlamak olduğu için AES algoritmasına ve çalışma mantığına pek değinmeyeceğim. Zaten kaynak linkinde yazan arkadaş konuyu gayet iyi anlatmış. Öğrenmek isteyenler kaynaktan detaylı bir şekilde okuyup, öğrenebilir.

Bu arada atlamadan geçmeyelim. XF PCL projelerinizde kullanabileceğiniz PCLCrypto plugini de var 🙂

Senaryomuz şu şekilde olsun. Kredi kartı bilgilerini XF ile geliştirdiğim mobil uygulamadan alıp, web servis yardımıyla son kullanıcının ödeme yapmasını sağlamak olsun.

Basit bir şekilde CreditCard sınıfı oluşturdum.

    public class CreditCard
    {
        public string Number { get; set; }
        public string Name { get; set; }
        public string Surname { get; set; }
        public string Month { get; set; }
        public string Year { get; set; }
        public string Cvv { get; set; }
        public string InstallmentNumber { get; set; }
    }
    

Amaç bu sınıfını kullanarak traditional tarafta gerekli yerleri AES algoritması ile şifrelemek ve tekrar PCL tarafta kullanmak.
Bu işlemi yapabilmek için yardımcı bir interface yaratmamız gerekiyor.

public interface ICreditCardCryptor
{
  CreditCard AESEncryption(CreditCard card);
}

Şifresiz CreditCard sınıfını alıp, şifreledikten sonra tekrar CreditCard sınıfını dönecek olan interface’i oluşturmuş olduk.

Ufak bir ekran tasarımı yapalım 🙂

Android tarafı için başlayalım..

Crypto için bir şifreye ihtiyacımız var bunu hem iOS hem de Android tarafında kullanacağım için, App.cs altında public static string password = “XFAES”; static bir değişken tanımladım.

    class CreditCartDependency : ICreditCardCryptor
    {
        public CreditCard AESEncryption(CreditCard card)
        {
            return new CreditCard
            {
                Name = EncryptText(card.Name, App.password),
                Surname = EncryptText(card.Surname, App.password),
                Cvv = EncryptText(card.Cvv, App.password),
                InstallmentNumber = EncryptText(card.InstallmentNumber, App.password),
                Month = EncryptText(card.Month, App.password),
                Number = EncryptText(card.Number, App.password),
                Year = EncryptText(card.Year, App.password)
            };
        }
        public string EncryptText(string input, string password)
        {
            byte[] bytesToBeEncrypted = Encoding.UTF8.GetBytes(input);
            byte[] passwordBytes = Encoding.UTF8.GetBytes(password);

            passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

            byte[] bytesEncrypted = AES_Encrypt(bytesToBeEncrypted, passwordBytes);

            string result = Convert.ToBase64String(bytesEncrypted);

            return result;
        }
        public byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
        {
            byte[] encryptedBytes = null;

            byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

            using (MemoryStream ms = new MemoryStream())
            {
                using (RijndaelManaged AES = new RijndaelManaged())
                {
                    AES.KeySize = 256;
                    AES.BlockSize = 128;

                    var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
                    AES.Key = key.GetBytes(AES.KeySize / 8);
                    AES.IV = key.GetBytes(AES.BlockSize / 8);

                    AES.Mode = CipherMode.CBC;

                    using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
                        cs.Close();
                    }
                    encryptedBytes = ms.ToArray();
                }
            }

            return encryptedBytes;
        }
    }

Kredi kartı bilgilerini web servise göndermeden hemen önce Traditional tarafta System.Security.Cryptography dll’i yardımıyla şifreliyoruz.

iOS tarafına geçelim..

    class CreditCartDependency : ICreditCardCryptor
    {
        public CreditCard AESEncryption(CreditCard card)
        {
            return new CreditCard
            {
                Name = EncryptText(card.Name, App.password),
                Surname = EncryptText(card.Surname, App.password),
                Cvv = EncryptText(card.Cvv, App.password),
                InstallmentNumber = EncryptText(card.InstallmentNumber, App.password),
                Month = EncryptText(card.Month, App.password),
                Number = EncryptText(card.Number, App.password),
                Year = EncryptText(card.Year, App.password)
            };
        }
        public string EncryptText(string input, string password)
        {
            byte[] bytesToBeEncrypted = Encoding.UTF8.GetBytes(input);
            byte[] passwordBytes = Encoding.UTF8.GetBytes(password);

            passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

            byte[] bytesEncrypted = AES_Encrypt(bytesToBeEncrypted, passwordBytes);

            string result = Convert.ToBase64String(bytesEncrypted);

            return result;
        }
        public byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
        {
            byte[] encryptedBytes = null;

            byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

            using (MemoryStream ms = new MemoryStream())
            {
                using (RijndaelManaged AES = new RijndaelManaged())
                {
                    AES.KeySize = 256;
                    AES.BlockSize = 128;

                    var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
                    AES.Key = key.GetBytes(AES.KeySize / 8);
                    AES.IV = key.GetBytes(AES.BlockSize / 8);

                    AES.Mode = CipherMode.CBC;

                    using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
                        cs.Close();
                    }
                    encryptedBytes = ms.ToArray();
                }
            }

            return encryptedBytes;
        }
    }

Aslında Crypto classını tek bir sefer yazıp “add existing item” yardımıyla hem iOS hem de Android tarafta kullanabilirdik. Fakat olayı daha yalın bir şekilde aktarabilmek için o yöntemi uygulamadım.

Gelelim kullanımına..

 private void Button_Clicked(object sender, EventArgs e)
 {
 var Crypto = DependencyService.Get<ICreditCardCryptor>()
 .AESCrypto(new CreditCard
    {
       Cvv = txtCvv.Text,
       Name = txtName.Text,
       Surname = txtSurname.Text,
       Number = txtNumber.Text,
       InstallmentNumber = pckrInstallment.SelectedItem
       .ToString(),
       Month = pckrMonth.SelectedItem.ToString(),
       Year = pckrYear.SelectedItem.ToString()
    });
 }


Test ettiğimizde şifreleme işlemlerimizin hem iOS hem de Android için sorunsuz çalıştığını göreceğiz.
Tabi bu işlemin bir de şifre çözme tarafı var.
Interface tarafına ufak bir update geçiyoruz..

 public interface ICreditCardCryptor
 {
    CreditCard AESEncryption(CreditCard card);
    CreditCard AESDecryption(CreditCard card);
 }

Daha sonra Traditional tarafta gerekli geliştirmereli yapmalıyız.
iOS ve Android için..

        public CreditCard AESDecryption(CreditCard card)
        {
            return new CreditCard
            {
                Name = DecryptText(card.Name, App.password),
                Surname = DecryptText(card.Surname, App.password),
                Cvv = DecryptText(card.Cvv, App.password),
                InstallmentNumber = DecryptText(card.InstallmentNumber, App.password),
                Month = DecryptText(card.Month, App.password),
                Number = DecryptText(card.Number, App.password),
                Year = DecryptText(card.Year, App.password)
            };
        }
        public byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
        {
            byte[] decryptedBytes = null;

            byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

            using (MemoryStream ms = new MemoryStream())
            {
                using (RijndaelManaged AES = new RijndaelManaged())
                {
                    AES.KeySize = 256;
                    AES.BlockSize = 128;

                    var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
                    AES.Key = key.GetBytes(AES.KeySize / 8);
                    AES.IV = key.GetBytes(AES.BlockSize / 8);

                    AES.Mode = CipherMode.CBC;

                    using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
                        cs.Close();
                    }
                    decryptedBytes = ms.ToArray();
                }
            }

            return decryptedBytes;
        }
        public string DecryptText(string input, string password)
        {
            byte[] bytesToBeDecrypted = Convert.FromBase64String(input);
            byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
            passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

            byte[] bytesDecrypted = AES_Decrypt(bytesToBeDecrypted, passwordBytes);

            string result = Encoding.UTF8.GetString(bytesDecrypted);

            return result;
        }


Decrypt işlemlerimizin de başarılı bir şekilde gerçekleştiğini görüyoruz.

Kaynak kodları github üzerinden indirebilirsiniz.

Yiğit

Xamarin Developer, Consultant & Architect. Community Leader and Director of Xamarin Türkiye

2 Comments

You can post comments in this post.


  • Hocam öncelikle teşekkür ediyorum eğitimleriniz için.

    Benim açımdan önemli bir konuda beni aydınlatabilirseniz çok minnettar olacağım;
    Bu eğitim içeriğinde kredi kartı bilgilerini sunucuya şifreli şekilde iletmeyi anlatmışsınız, mobil uygulama üzerinden ödeme alma işlemi sadece bu yöntemle(bilgileri kendi sunucumuza iletip, sunucuyu bankayla konuşturma) mi halledilir acaba, uygulamayı direk bankanın servisi ile entegre etme yöntemi de kullanılır mı?

    Tekrardan teşekkürler…

    İbrahim KILIÇ 5 sene ago Reply


    • Selam,

      Bu tarz mobil uzerinden odeme alma konularinda 3th party sirketlerde var. (iyzico gibi) bunlari direkt kullanabilirsin. Bankanin servislerini de kullanabilirsin (eger rest ise). Fakat benim onerim transaction ve logic yonetimini servis katmaninda yapman. Cunku mobil kisma sadece UI olarak bakmak daha mantikli geliyor bana 🙂

      Yiğit 5 sene ago Reply


Post A Reply