19 Eylül 2008 Cuma

Ev Yapımı Şifreleme

Merhaba.
Bugün size Python ile ev yapımı şifreleme nasıl yapılır ondan bahsedeceğim. Ev yapımı şifrelemeden neyi kastettiğimi yazının devamında daha rahat anlayacaksınız.
(Not: Yazar girişte başlığı kullanarak merak uyandırmaya çalışmış ve okuyucuyu yazının devamını okuması için teşvik etmeye çalışmıştır).

Programı görmeden önce size bu programı nerede kullanabileceğinizden bahsedeceğim, programın bu bilgiyle incelendiğinde daha kolay anlaşılacağını düşünüyorum.

Senaryomuz şöyle;

Bir uygulama geliştirdiniz. Uygulamanız kullanıcı adı ve şifre girişi gerektirmekte ve sizde bu kullanıcı adını ve şifreyi kullanıcının bilgisayarında tutmak durumundasınız. Sadece bir kullanıcının kullanıcı adı ve şifresini tutmak içinde veritabanı kullanmak istemiyorsunuz. Bu durumda bu bilgileri bir dosyada tutmanız gerek. Buraya kadar her şey normal. Sorun bu bilgileri o dosyada nasıl tutacağınız. Bir dosya oluşturup içerisine pattadanak (böylemi yazılıyor bu?) yazacak değilsiniz. Bu kadarla da kalmıyorsunuz programınız kullanıcınızın izni dışında 3. şahıslar tarafından kopyalandığında da o 3. şahıs programını çaldığı kullanıcınızın bilgileri ile giriş yapamasın istiyorsunuz, yok artık!!! İşte bu yazıda böyle bir ihtiyaç durumunda kullanabileceğiniz bir şifreleme yönteminden, kendi verdiğim isimle "Ev Yapımı Şifreleme" den bahsedeceğim.

Çok konuştuk, kodu görelim. Önce kodun tamamını verip daha sonra parça parça açıklamasını vereceğim.

import operator
import sys,os

class Encrypt():
def xor(self, password,encrypt=True):
key=self.mix_mac()
if not encrypt:
key+='\x00'
p_sira = -1
encrypted = ""
for str_sira in range(len(key)):
p_sira += 1
if (p_sira >= len(password)): p_sira = 0
p = str(password[p_sira])
s = str(key[str_sira])
e = chr ( operator.xor(ord(s), ord(p)))
encrypted += e
if encrypt:
encrypted += str(len(password))
return encrypted

def decrypt(self,enc):
enc_len=int(enc[len(enc)-1])
return enc[:enc_len]

def mix_mac(self):
mac=self.getMacAddress()
KEY='pythontr'
mixed_mac=''
str_mac=str(mac)

for i in range(len(KEY)):
mixed_mac+=str_mac[i]+KEY[i]
mixed_mac+=str_mac[len(KEY):]
return mixed_mac

def getMacAddress(self):
if sys.platform == 'win32':
for line in os.popen("ipconfig /all"):
if line.lstrip().startswith('Physical Address'):
mac = line.split(':')[1].strip().replace('-',':')
break
else:
for line in os.popen("/sbin/ifconfig"):
if line.find('Ether') > -1:
mac = line.split()[4]
break
return mac


Eveet, şimdi gelelim açıklama kısmına. Önce programın tam olarak ne yaptığını anlatayım daha sonra açıklamalara geçeriz. Program kullanıcının mac adresini sizin verdiğiniz KEY ile (burada "pythontr") bit kaydırma işlemine tabi tutup bir değişken üretiyor. Daha sonra sizin verdiğiniz değişken ile (şifrelenecek değişken) kendi ürettiği değişkeni xor işlemine sokup size şifrelenmiş veriyi döndürüyor.

Gelelim metodlara:

getMacAddress():

os ve sys modüllerini kullanarak kullanıcının mac adresini öğreniyoruz.

sys.platform ile kullanıcının işletim sistemini öğreniyoruz, burada winfos ve linux için düzenlenmiştir.

os.popen ile komut istemine bir boru açıp mac adres bilgilerini veren komutu çalıştırıyoruz, devamında ise string işlemlerle çıktıdan mac adresini ayıklıyoruz.

mixMac():

Burada aldığımız mac adresi ile belirlediğimiz KEY değişkenini bit kaydırma işlemi ile karıştırıyoruz ve bu karıştırdığımız yeni string veriyi döndürüyoruz. Burada dikkat edilecek önemli nokta verdiğiniz KEY'in mac adresinden uzun olmaması gerektiği. Aksi halde "string index out of bound" hatası alırsınız.

decrypt():

Bu fonksiyon ise şifresini çözdüğümüz veriden ham şifreyi elde etmeye yarıyor. Programın kullanımında da göreceğiz, 8 karakterli bir şifre verdiğinizi varsayalım, çözdüğünüz şifre mac adresinin karakter sayısı+verdiğiniz KEY'in karakter sayısı kadar tekrarlı gelecek. Bu yüzden şifreleme yaparken şifreli verinin sonuna şifrenin karakter sayısını giriyoruz ve bu fonksiyonda o karakter sayısı kadar veriyi çekip tekrarları almamış oluyoruz. Korkmayın aşağıda örnekleyince daha kolay anlayacaksınız :)

xor():

Esas oğlan. Şifreleme işlemini yapan fonksiyon. Yaptığı iş çok karışık değil aslında. Programa gönderdiğiniz şifre ile programın oluşturduğu verinin her bir karakterinin ASCII kodunu alıp onları xor işlemine sokuyor. Burada "encrypt" parametresinden bahsetmekte fayda var. Şifreleme yapacağımız zaman "True" çözümleme yapacağımız zaman "False" değeri veriyoruz. Onu şu sebepten kullandık, şifreleme sırasında şifrelediğimiz verinin karakter sayısını verinin sonuna eklediğimizi söylemiştik. Çözümleme yaparken referansımız olan mac adresi ile xor işlemine soktuğumuzda verideki karakter sayısının işlenmediğini görürüz, çünkü mac adresinin karakter sayısı aynıdır ancak biz şifreli veriye sonradan bir karakter eklemişizdir, dolayısıyla mac adresinde o karakter ile xor işlemine girecek eleman kalmamıştır. Bu yüzden çözümleme yapacağımız zaman mac adresine şifremizin eleman sayısını da işleme sokmak için bir veri ekliyoruz. Peki nedir eklediğimiz veri "\x00" verisi, yani ascii 0'ın char karşılığı. Peki neden 0 ekledik, 0 ile herhangi bir sayıyı xor işlemine sokarsanız sonuç olarak sayının kendisini alırsınız. Anlayacağınız 0 xor işlemi için etkisiz eleman, dolayısıyla bize direk olarak şifremizin karakter sayısını döndürüyor. Olay bundan ibaret, 2 tane integer değerin xor sonucunu veriyor bize (her karakter için). Şifrelenmiş verimiz bu oluyor.

Şimdi gelelim programın örnek kullanımına. Python yorumlayıcısını açıyoruz (yanında kahve içmekte özgürsünüz) ve başlıyoruz.


In [1]: from Encrypt import Encrypt
In [2]: e=Encrypt()
In [3]: passwd='adige'
In [4]: sifreli=e.xor(passwd)
In [5]: sifreli

Out[1]: 'Q\x14SUW[!-]]%T\x10]WS^,#_Y S\x13_SVS"![\\-W\r[V[] %^Q#&\x0e^[U_$ S_![\nSUW[!-]]%!\x1d]WS^,#_Y Z\x15_SVS"![\\-5'

In [6]: sifresiz=e.xor(sifreli,False)
In [7]: sifresiz

Out[2]: 'adigeadigeadigeadigeadigeadigeadigeadigeadigeadigeadigeadigeadigeadigeadigeadigeadigeadi5'

In [8]: sifre=e.decrypt(sifresiz)
In [9]: sifre

Out[3]: 'adige'


Programın kullanımı bu şekilde. Kafanıza takılan bişey olursa sormaktan çekinmeyin.
Şimdilik benden bu kadar, bir sonraki Python macerasında görüşmek üzere.

Özgür kalın..

14 yorum:

  1. bir hatırlatma; türkçe işletim sistemi kullananlar için getMacAddress fonksiyonundan bir şey dönmiyecektir eğer 'Physical Address' yerine 'Fiziksel Adres' olarak değiştirilmezse.

    YanıtlaSil
  2. Evet, uyarınız için teşekkür ederim, buradan sizin aracılığınızla onu da belirtmiş olalım.

    YanıtlaSil
  3. Mac adresini almanın daha güzel bir yolu var mıdır acaba?

    YanıtlaSil
  4. Benim bildiğim en ağrısız yöntem bu. Linux ve winfos üzerinde işe yarıyor. Bunu kurcalarken baya bi bakındıydım bende ama başka bi yöntem bulamadım. Sen neden beğenmedin bunu?.

    YanıtlaSil
  5. Bende ilk baktığımda daha pythonic bir yol var mı diye düşünmedim değil.
    import os
    os.getmac() gibi birşeyler aradım. google'da da sordum hatta ama yokmuş. Senin dediğin gibi en işe yarar yol bu görünüyor.

    YanıtlaSil
  6. Yok beğenmemek değil. Mac adresini almak için Python içerisinde bir modül olmadığını görünce şaşırdım. Eğer yoksa eksiklik olarak düşünebiliriz sanırım bunu (Diğer dillerde varmıdır acaba?).

    YanıtlaSil
  7. siteniz çok güzel olmuş. elinize sağlık.
    mirat can'ın sorusuna güzel bir cevap buldum.

    Mac adresi almanın güzel yolu:

    from netbios import *
    # code ported from "HOWTO: Get the MAC Address for an Ethernet Adapter"
    # MS KB ID: Q118623
    ncb = NCB()
    ncb.Command = NCBENUM
    la_enum = LANA_ENUM()
    ncb.Buffer = la_enum
    rc = Netbios(ncb)
    if rc != 0: raise RuntimeError, "Unexpected result %d" % (rc,)
    for i in range(la_enum.length):
    ncb.Reset()
    ncb.Command = NCBRESET
    ncb.Lana_num = ord(la_enum.lana[i])
    rc = Netbios(ncb)
    if rc != 0: raise RuntimeError, "Unexpected result %d" % (rc,)
    ncb.Reset()
    ncb.Command = NCBASTAT
    ncb.Lana_num = ord(la_enum.lana[i])
    ncb.Callname = "* "
    adapter = ADAPTER_STATUS()
    ncb.Buffer = adapter
    Netbios(ncb)
    print "Adapter address:",
    for ch in adapter.adapter_address:
    print "%02x" % (ord(ch),) ,
    print


    ve sonucu: "Adapter address: 00 50 56 c0 00 08"
    winde denedim çalışıyor. linux'da da çalışıyor mu? test edebilir misiniz?

    ref: http://groups.google.com/group/comp.lang.python/msg/fd2e7437d72c1c21?pli=1

    YanıtlaSil
  8. Netbios modülü win bağımlı bir modül,

    Diğer işletim sistemlerinde kullanılmıyor malesef.

    Python'da neden kütüphanede buna yer vermemişler bende anlamış değilim, belki de biz bilmiyoruzdur, hatta belki google da :)

    YanıtlaSil
  9. Merhaba, yazmış olduğunuz bu kodları direkt olarak isminizi belirterek kendi programımda kullanabilir miyim? Kendi programım GPL ile lisanslı olacak.

    YanıtlaSil
  10. Merhaba, tabi ki kullanabilirsiniz. Programın github vs. linkini bizimle de paylaşırsanız pratikte kullanımı için güzel bir örnek olmuş olur.

    YanıtlaSil
  11. Bu yorum yazar tarafından silindi.

    YanıtlaSil
  12. Teşekkürler. Geliştirdiğim yazılımı buradan takip edebilirsiniz. Henüz programı yayımlamadım ama kodları buradan takip edebilirsiniz. Şimdilik düzgün çalışmıyor ama sorunlarıyla zaman buldukça ilgileniyorum.

    https://github.com/aslanon/whoyou

    YanıtlaSil
  13. Bu yorum yazar tarafından silindi.

    YanıtlaSil
  14. merhaba ben python u merak ettim python 3.4.3 sürümünü indirdim ama kodu nereye yazcam,kodu nasıl çalıştırıp bakcam?

    YanıtlaSil