in Ar-Ge, Kriptoloji ve Bilgi Güvenliği

Openssl C kütüphanesi ile AES 256 CBC ile dosya şifreleme

Tamam sakin olun, başlıktaki terimlerin hepsini açıklayacağım ve gerçekten de bu yazının sonunda siz de openssl kütüphanesi kullanarak, AES (Rijndael) algoritması ile 256 bit uzunluğunda anahtar kullanarak, CBC (Cipher Block Chaining) modu kullanarak şifreleme yapabileceksiniz. Ayrıca diğer yazılarımda dosya bütünlüğünü HMAC ile kontrol etmekten ve ağ iletiminde sorun yaşamamak için şifrelediğiniz dosyaları Base64 ile kodlamaktan bahsedeceğim.

Şifreleme yapacak kodun mantığından bahsedeyim. Bu tasarım üzerinden OpenSSL kütüphanesinden bahsederek geçeceğim.

Şifreleme:
Dosyayı oku.
Dosya içeriğini şifrele.
Şifreli metnin MAC anahtarı ile SHA-1 algoritması HMAC değerini hesapla.
Şifreli metni ve HMAC değerini Base64 şemasına göre kodla.
HMAC değeri + şifreli metni şifrelenmiş dosyaya yazdır.

Deşifre etme:
Dosyayı oku.
Dosyanın başındaki sabit boyutlu HMAC değerini ve şifreli metni ayır.
Base64 kodlanmış şifreli metni binary hale getir.
Şifreli metnin HMAC değerini hesapla ve Base64 ile kodla.
Önceki basamakta hesaplanan HMAC değeri ile dosyadan okunan HMAC değerini karşılaştır.
Binary haldeki şifreli metni deşifre et.
Deşifre edilmiş metni dosyaya yazdır.

Openssl kütüphanesini kullanmak için öncelikle aşağıdaki satırla gerekli header dosyasını kodumuza dahil ediyoruz.

#include <openssl/evp.h>

Şifreleme ya da deşifreleme işlemine başlamadan önce, tüm durum bilgilerini tutan “cipher context” adlı (bunu Türkçe’ye çeviremiyorum) bir tür tanımlamamız gerekiyor. Bu yapı şifreleme ve deşifreleme işlemlerine ilişkin tüm bilgiyi içinde tutacak (şifreleme modu (mode of operation) CBC, ECB vs., padding bilgisi vs.). Daha sonra bu yapıyı EVP_CIPHER_INIT(&ctx) ile başlangıç durumuna getiriyoruz ve bir alt satırda da gerekli parametrelerle içini dolduruyoruz. Bu yapı şifreleme, deşifreleme ya da ikisi için birden kullanılacak şekilde başlatılabiliniyor. Ancak senkronizayon problemleri yaşanabileceği için tavsiye edilen ya şifreleme ya da deşifreleme için başlatmak. Aşağıdaki kodda  EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, key, iv); satırı ile bu yapıyı AES 256 bit CBC yapacak şekilde, anahtar olarak key, başlangıç vektörü olarak  iv vererek başlangıç durumuna getiriyoruz.

//şifreleme objesi oluşturma, initialize etme, algoritma anahtar belirleme
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, key, iv);

ctx yapısını oluşturup içini, gerekli verilerle doldurduktan sonra şifrelenmiş metnimizi oluşturmaya başlayabiliriz. Öncelikle şifrelenmiş veriyi tutacak olan karakter dizisine gerekli yeri ayırıyoruz. Padding ile dosya uzunluğu tam blok uzunluğuna tamamlanacağı için şifrelenmiş veri için 1 blok fazladan yer ayırıyoruz. Aşağıdaki kodda ilk if ifadesi , intext değişkeninden okuduğu algoritmanın blok uzunluğunun tam katı kadar veriyi şifreliyor. Şifrelenmiş veriyi outbuf değişkenine, uzunluğunu da outlen değişkenine yazıyor. İkinci if ifadesi kalan veriyi tam blok uzunluğuna tamamlıyor (belirlenmiş padding yöntemi ile)ve şifreliyor. Şifrelenmiş veriyi outbuf değişkenine ekliyor. Eklenen verinin uzunluğu tmplen değişkenine kaydediliyor.

//şifrelenmiş metnin saklanacağı char array
//padding olacağı için 1 blok fazladan yer alıyoruz
outbuf = (char *)malloc(inlen + EVP_MAX_BLOCK_LENGTH);

//outbuf şifrelenmiş metin, outlen şifrelenmiş metnin uzunluğu,
//intext şifrelenecek metin, inlen şifrelenecek metnin uzunluğu
if(!EVP_EncryptUpdate(&ctx, outbuf, &outlen, intext, inlen))
{
/* Error */
return 0;
}
/* Buffer passed to EVP_EncryptFinal() must be after data just
* encrypted to avoid overwriting it.
*/
//blok katının dışındaki kısım padding eklenerek blok uzunluğuna tamamlanıp şifreleniyor.
if(!EVP_EncryptFinal_ex(&ctx, outbuf + outlen, &tmplen))
{
/* Error */
return 0;
}

Şifrelenmiş verinin tam uzunluğu outlen + tmplen olarak bulunuyor ve outlen değişkenine aktarılıyor.

//outlen in son uzunluğu bulunuyor
outlen += tmplen;
EVP_CIPHER_CTX_cleanup(&ctx); //obje temizleniyor
/* Need binary mode for fopen because encrypted data is
* binary data. Also cannot use strlen() on it because
* it wont be null terminated and may contain embedded
* nulls.
*/

Bu yazımda birebir şifreleme yapan bir yazılım vermek yerine okuyucuyu da araştırmaya teşvik eden bir bakış açısı tercih ettim. Network Security with OpenSSL adlı kitaptan ve örneklerinden faydalandım. Yazılarımın devamında, bu yazımın başında belirttiğim HMAC ve Base64 kodlama ile ilgili bilgilere de ulaşabileceksiniz.

Write a Comment

Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  1. Teşekkürler olayı çözdüm sayende 😉