DES şifreleme algoritmasındaki karakter desteği problemi

DES Algoritmasını yazmaya çalışıyorum. DES algoritması karakterleri son biti kontrol biti olacak şekilde önce şifrelenecek veriyi 8 bitlik şekle dönüştürür. Eğer ‘A’ harfi varsa bunu ikilik formatta ‘01000001’ şekline dönüştürür. Bu iş tamam ancak bir problem var. Ancak eğer harfimiz ‘Ö’ ise bunun ikilik formattaki hali ‘11000011 10010110’ dir. Atıyorum ben ‘Ö’ harfi geçen bir metni şifreledim ve şifresini çözmek istiyorum. En sonda binary formatını tekrardan karaktere dönüştürmek isteyeceğim zaman binary verisini 8 bit 8 bit mi 16 bit 16 bit mi ayıracağımı nereden anlayacağım?

Şu minvalde bir şeyler deneyebilirsiniz:

orijinal_metin = "aöb"
metin = orijinal_metin.encode()
metin = şifrele(metin)

metin = şifreyi_çöz(metin)
metin = metin.decode()
assert metin == orijinal_metin

Peki bu veriyi alan biri eğer orijinal metni bilmiyorsa (ki şifre çözme sürecinden sonra öğrenecek) ne yapacak? İlla ASCII ile mi yapmam gerekiyor. Veri ASCII karakter mi olmalı illa ki onu merak ediyorum.

Şu işlemi:


Neyi ASCII ile mi yapmanız gerekiyor? Şifreleme işlemi için 8 bitlik parçalar isteyen sizdiniz zaten.

Burada siz şifrelenmiş metin ile orijinal metnin aynı olup olmadığına bakıyorsunuz. Ama gerçek bir senaryoda örnek veriyorum veri ağ üzerinden başka bir cihaza gönderildiğinde veriyi alan kişi orijinal metni değil, sadece anahtarı ve şifrelenmiş metni bilecek. Bu bilgileri kullanarak veriyi şifre çözme algoritmasından geçirip orijinal metni bulacak. Ama bazı karakterler 8 bitle bazıları 16 bitle gösteriliyor. Şifre çözme işlemi sonucunda elde edilen ikilik verinin hangi bölümlerinin 8 hangilerinin 16 olduğunu nereden anlayabiliriz?

ASCII 8 bitlik karakter gösterimine dayanıyor. UTF-8 'e gelirsek bu veri 8, 16 veya daha fazlası olabiliyor.

16 bitlik halde kodlarsam da orijinal DES algoritmasını baştan aşağıya değiştirmem gerekecek. Algoritmaya sokmadan önce bir şekilde 8 bite sıkıştırmalıyım diye düşünüyorum. Ya da daha basit bir çözümü uygulamayı…

Evet, dikkat ederseniz UTF-8 sizin şu anda çözmeye çalıştığınız sorunu halihazırda çözmüş. Onun nasıl çalıştığını incelemek de isteyebilirsiniz.

Benim verdiğim kodda yine utf-8 encoding bu problemi tam olarak şu satırda sizin için çözüyor zaten:

Ayrıca bütün harfleri 16 bit ile temsil ederek de bu 8bit/16bit probleminden kurtulabilirsiniz, mesela:

orijinal_metin = "aöb"

def encode(string):
    def g():
        for i in map(ord, string):
            yield i // 255
            yield i % 255
    return bytes(g())

def decode(byts):
    return "".join(chr(byts[i] * 255 + byts[i + 1]) for i in range(0, len(byts), 2))

metin = encode(orijinal_metin)
metin = şifrele(metin)

metin = şifreyi_çöz(metin)
metin = decode(metin)
assert metin == orijinal_metin

16 biti 8 bite sıkıştırmaya çalışmak yerine niçin 16 biti 8 bitlik iki parça olarak işlemiyorsunuz?

2 Beğeni

Evet bu mantıklı bir yöntem. Ama algoritmayı yavaşlatacak. Normalden 2 kat daha yavaş çalışacak algoritma.

Anladığım kadarı ile ilk yazdığım kod sizin normal ile kastettiğiniz yöntemi kullanıyor zaten. “a” harfi için 8 bit kullanılırken “ö” harfi için 16 bit kullanılıyor.

Hocam kullanıyor da atıyorum ben size bir kağıt veriyorum. Kağıtta ikilik veriler var. Ben diyorum ki size bunların bazılarını 8-8 bazılarını 16-16 böl. Ve bunlara tablodan bak. Ama hangilerini 8 hangilerini 16 böleceğin belli değil. Nasıl anlayabilirsin ki?

Ayrıca:

Alternatif çözüm base64 kullanmak. Böylece veri boyutu sadece %33 artacak. Bu da şifreleme ve şifre çözme işleminin daha hızlı gerçekleşmesi demek.

data = "çöğasdfğdf"
cip = data.encode('utf-8')
print(cip.decode('utf-8'))

Bunu yapan DES degil, ASCII.

Ö harfinin ikilik formati diye bir sey yok. UTF-8’deki kodlanmasindan bahsediyorsun.

Standardi okumadim ama metinleri degil, byte dizilerini sifreleyebildigini tahmin ediyorum.

Metni byte dizisine nasil cevirdiysen tersini kullanman lazim.

Bu sorunun sifreleme ile alakasi yok. Ayni veri eline baska sekilde gecse ne degisecek?

Mesela UTF-16 :slight_smile:
orijinal_metin.encode('utf-16be')

Bu UTF-8’in calismasini mi temsil ediyor? UTF-8 boyle calismiyor cunku.

1 Beğeni

Evet, DES algotitması karakterlerle değil baytlarla çalışıyor. Bahsettiğim problem DES algoritmasını bağlayan bir problem değil. Önce veriyi 16’lık sistemde kodlamayı düşündüm ama bu ASCII kullanımına göre iki kat daha fazla verinin algoritmaya girmesi demek. Bu da algoritmanın 2 kat daha yavaş çalışması anlamına geliyor. Bu yöntemi zaten yukarıda @EkremDincel gösterdi. Aynı şekilde UTF-16 kullanmakta verinin ASCII’ye göre iki katına çıkması anlamına geliyor. Bunun için base64 kullanmaya karar verdim.

Standart ASCII tablosundak karakterlerden oluşan bir dize eğer base64 ile kodlanırsa, veri sadece %33 daha fazla yer kaplıyor. ASCII dışı karakterlerde ise iki katına çıkıyor. UTF-16 kullanıldığı vakit bütün karakterler normalden iki kat fazla yer kaplarken; base64 kullanıldığında ASCII karakterleri %33 fazla yer kaplarken, ASCII dışı karakterler UTF-8 tablosundaki bayt uzunluğu kadar veri kaplıyor.(Örneğin 2 bayt)

Kısacası base64 ile veriyi fazla şişirmeden ASCII formatına çevirebiliyoruz.

Base64 karakterlerle degil, byte’larla calisiyor. Butun verileri %33 buyutuyor.

Veri byte dizisiyse evet. Karakter dizesiyse once encode etmek gerek. Yukarida anlattigin kadariyla UTF-8 olarak encode ediyorsun once.

Aynen öyle:,

   import base64
   def text2base64(text_string):
        text_bytes = text_string.encode()
        base64_bytes = base64.b64encode(text_bytes)
        base64_string = base64_bytes.decode()
        return base64_string

    def base642text(base64_string):
        base64_bytes = base64_string.encode()
        text_bytes = base64.b64decode(base64_bytes)
        text_string = text_bytes.decode()
        return text_string