Tartışma

Python ile SHA256 Hesaplama

Başlatan QuantumBerk · 09 Tem 2026 12:16 · 18 Görüntülenme · 0 Yanıtlar
Konuyu Açan #0
SHA256, günümüz dijital dünyasında veri bütünlüğünü ve güvenliğini sağlamanın temel taşlarından biri, değil mi? Özellikle kriptografik işlemler, dosya doğrulama ya da basit bir veri parmak izi oluşturma ihtiyacı duyduğumuzda aklımıza gelen ilk algoritmalar arasında yer alıyor. Peki, bu güçlü algoritmayı Python gibi kullanımı kolay ve çok yönlü bir dil ile nasıl etkin bir şekilde kullanabiliriz? İşte bugün tam da bu konuya derinlemesine dalacağız.

Python'ın standart kütüphanesi, kriptografik hash fonksiyonlarını kullanmak için bize hashlib modülünü sunuyor. Bu modül sayesinde SHA256'dan MD5'e, SHA512'ye kadar birçok farklı hash algoritmasına erişebiliyoruz. İşin güzel yanı, kullanımı oldukça basit ve sezgisel... Ama tabii ki bazı püf noktaları var, özellikle stringlerle çalışırken dikkat etmemiz gereken bir detay.

Bir metin dizisini (string) SHA256 ile hash'lemek, en sık karşılaştığımız senaryolardan biri. Burada en önemli nokta, hash fonksiyonlarının byte dizileri üzerinde çalışmasıdır. Python'daki string'ler ise Unicode karakter dizileridir. Bu yüzden, herhangi bir string'i hash'lemeden önce onu belirli bir kodlama (encoding) ile byte dizisine dönüştürmemiz gerekiyor. Genellikle UTF-8 tercih edilir, çünkü uluslararası karakter setlerini de destekler ve yaygın bir standarttır.

CODE
1234567891011121314151617181920
import hashlib

[b]Hash'lenecek metin[/b]
metin = "Bu bir test metnidir ve SHA256 ile hash'lenecektir."

[b]Metni UTF-8 ile byte dizisine dönüştürüyoruz[/b]
metin_bytes = metin.encode('utf-8')

[b]SHA256 hash nesnesini oluşturuyoruz[/b]
hasher = hashlib.sha256()

[b]Byte dizisini hash nesnesine güncelliyoruz[/b]
hasher.update(metin_bytes)

[b]Hash değerini hexadecimal (onaltılık) formatta alıyoruz[/b]
hash_degeri = hasher.hexdigest()

print(f"Orijinal Metin: {metin}")
print(f"SHA256 Hash Değeri: {hash_degeri}")


Gördüğünüz gibi, .encode('utf-8') adımı burada kritik. Eğer bu adımı atlarsak, Python bize bir TypeError fırlatacak, çünkü hashlib.sha256().update() metodu sadece byte dizilerini kabul eder. Sonrasında .hexdigest() metodunu kullanarak okunabilir, onaltılık formatta hash değerini elde ediyoruz. Bir de .digest() metodu var, o da hash değerini doğrudan byte dizisi olarak döndürür; genellikle daha ileri kriptografik işlemler için kullanılır.

Peki ya büyük dosyaları hash'lemek istersek? Diyelim ki indirdiğiniz bir yazılımın kurulum dosyasının bütünlüğünü kontrol etmek istiyorsunuz, dosya boyutu birkaç gigabayt olabiliyor. Bu durumda tüm dosyayı belleğe tek seferde yükleyip hash'lemeye çalışmak pek verimli olmaz, hatta bellek yetersizliği sorunlarına yol açabilir. İşte burada dosyayı parça parça okuyup hash nesnesini güncellemeyi öğrenmek çok işimize yarar.

CODE
12345678910111213141516171819202122232425262728293031323334353637
import hashlib

def dosya_sha256_hesapla(dosya_yolu, blok_boyutu=65536): # 64 KB blok boyutu
    hasher = hashlib.sha256()
    try:
        with open(dosya_yolu, 'rb') as f: # Dosyayı ikili (binary) modda okuyoruz
            while True:
                buffer = f.read(blok_boyutu)
                if not buffer:
                    break
                hasher.update(buffer)
        return hasher.hexdigest()
    except FileNotFoundError:
        return "Dosya bulunamadı."
    except Exception as e:
        return f"Bir hata oluştu: {e}"

[b]Örnek kullanım: mevcut bir dosyanın hash'ini hesaplayalım[/b]
[b]Kendi sisteminizde var olan küçük bir dosya ile deneyebilirsiniz.[/b]
[b]Örneğin, "test_dosyasi.txt" adında bir dosya oluşturup içine bir şeyler yazın.[/b]
[b]Örnek olarak bir dosya oluşturalım:[/b]
with open("test_dosyasi.txt", "w") as f:
    f.write("Bu, hash'lenecek bir test dosyasıdır.\n")
    f.write("İçeriği değiştikçe hash değeri de değişecektir.\n")

dosya_yolu = "test_dosyasi.txt"
dosya_hash = dosya_sha256_hesapla(dosya_yolu)

print(f"\n'{dosya_yolu}' dosyasının SHA256 Hash Değeri: {dosya_hash}")

[b]Dosyanın içeriğini değiştirip tekrar hash'leyelim[/b]
with open("test_dosyasi.txt", "a") as f:
    f.write("Yeni bir satır eklendi.")

dosya_hash_yeni = dosya_sha256_hesapla(dosya_yolu)
print(f"Değiştirilmiş '{dosya_yolu}' dosyasının SHA256 Hash Değeri: {dosya_hash_yeni}")


Bu örnekte, dosyayı 'rb' (read binary) modunda açtığımıza ve belirli bir blok_boyutu kadar okuyarak hasher.update(buffer) ile hash nesnesini sürekli güncellediğimize dikkat edin. Bu yöntem, dosya boyutu ne olursa olsun belleği yormadan hash hesaplamamızı sağlar. Dosya bütünlüğünü kontrol etmek için gerçekten paha biçilmez bir yöntemdir bu. Bir dosyanın indikten sonra değişip değişmediğini, bozulup bozulmadığını anlamanın en pratik yollarından biri.

Peki ya güvenlik, özellikle şifreler söz konusu olduğunda SHA256 tek başına yeterli mi? Ne yazık ki hayır, tek başına yeterli değil. Şifreler için sadece SHA256 kullanmak, gökkuşağı tabloları (rainbow tables) ve kaba kuvvet saldırılarına karşı savunmasız kalmanıza neden olabilir. İşte bu noktada 'salt' kavramı devreye giriyor. Salt, hash'lenecek veriye (örneğin bir şifreye) eklenen rastgele bir dizedir. Bu sayede aynı şifreye sahip iki kullanıcının hash değeri farklı olur, bu da saldırganların işini zorlaştırır.

CODE
1234567891011121314151617181920212223242526272829303132333435363738394041
import hashlib
import os

def salted_sha256(sifre, salt=None):
    if salt is None:
        # Her yeni şifre için benzersiz, rastgele bir salt oluştur
        salt = os.urandom(16) # 16 byte'lık rastgele salt
    
    # Salt'ı ve şifreyi birleştirip hash'liyoruz
    # Şifreyi byte'a çevirmeyi unutmayın!
    hasher = hashlib.sha256()
    hasher.update(salt + sifre.encode('utf-8'))
    
    # Salt'ı ve hash'i depolayabiliriz
    return salt.hex(), hasher.hexdigest()

[b]Kullanıcı şifresi[/b]
kullanici_sifresi = "benimGizliSifrem123"

[b]İlk kez bir şifreyi hash'liyoruz, salt otomatik oluşacak[/b]
ilk_salt_hex, ilk_hash = salted_sha256(kullanici_sifresi)
print(f"\nİlk Hash: Salt = {ilk_salt_hex}, Hash = {ilk_hash}")

[b]Aynı şifreyi tekrar hash'leyelim, farklı bir salt oluştuğu için hash de farklı olacak[/b]
ikinci_salt_hex, ikinci_hash = salted_sha256(kullanici_sifresi)
print(f"İkinci Hash: Salt = {ikinci_salt_hex}, Hash = {ikinci_hash}")

[b]Şimdi, önceden oluşturulmuş bir salt ile şifreyi doğrulayalım[/b]
[b]Doğrulama anında, kaydedilen salt'ı kullanarak şifreyi tekrar hash'lememiz gerekir.[/b]
kaydedilen_salt_bytes = bytes.fromhex(ilk_salt_hex)
dogrulama_hash = salted_sha256(kullanici_sifresi, salt=kaydedilen_salt_bytes)[1]

print(f"Doğrulama Hash: {dogrulama_hash}")
print(f"Doğrulama başarılı mı? {dogrulama_hash == ilk_hash}")

[b]Yanlış şifre ile deneme[/b]
yanlis_sifre = "yanlisSifre"
yanlis_hash = salted_sha256(yanlis_sifre, salt=kaydedilen_salt_bytes)[1]
print(f"Yanlış Şifre Hash: {yanlis_hash}")
print(f"Yanlış şifre ile doğrulama başarılı mı? {yanlis_hash == ilk_hash}")


Bu örnekte os.urandom(16) ile 16 byte'lık rastgele bir salt oluşturuyoruz. Her şifre için farklı bir salt kullanmak, güvenlik açısından kritik. Hash'lenen salt ve şifre kombinasyonunu saklamanız gerekir ki, kullanıcı bir dahaki sefere giriş yapmaya çalıştığında aynı salt ile girdiği şifreyi hash'leyip depolanan hash ile karşılaştırabilesiniz. Salt'ı hash ile birlikte depolamak yaygın bir pratiktir, genelde veritabanında ayrı bir sütunda tutulur.

Ancak, şifre saklama konusunda salt kullanmak bile tam anlamıyla yeterli değil. Modern uygulamalarda şifreler için sadece SHA256 gibi hızlı hash algoritmaları yerine, özel olarak şifreler için tasarlanmış anahtar türetme fonksiyonları (Key Derivation Functions - KDF) kullanılıyor. Bu KDF'ler, kasıtlı olarak yavaş çalışacak şekilde tasarlanmıştır; bu sayede kaba kuvvet saldırılarının maliyetini kat kat artırırlar. Python'ın hashlib modülü bize PBKDF2 gibi seçenekler sunuyor, ki bu da şifreler için SHA256'dan çok daha güvenli bir yaklaşımdır.

CODE
12345678910111213141516171819202122232425262728293031
import hashlib
import os

def password_hash_pbkdf2(password, salt=None, iterations=100000):
    if salt is None:
        salt = os.urandom(16)
    
    # PBKDF2 algoritmasını kullanarak şifreyi hash'liyoruz
    # dklen: türetilmiş anahtarın uzunluğu (bytes olarak)
    # prf: sözde rastgele fonksiyon (HMAC-SHA256 kullanıyoruz)
    dk = hashlib.pbkdf2_hmac(
        'sha256',          # Hash algoritması
        password.encode('utf-8'), # Şifre (byte dizisi olarak)
        salt,              # Salt (byte dizisi olarak)
        iterations,        # İterasyon sayısı (güvenliği artırır)
        dklen=32           # Türetilmiş anahtar uzunluğu (SHA256 için 32 byte)
    )
    return salt.hex(), dk.hex()

[b]Örnek kullanım[/b]
sifre = "cokGizliSifre"
salt_hex_pbkdf2, hash_pbkdf2 = password_hash_pbkdf2(sifre)

print(f"\nPBKDF2 ile Hash: Salt = {salt_hex_pbkdf2}, Hash = {hash_pbkdf2}")

[b]Doğrulama örneği: aynı salt ve şifre ile tekrar hash'leyip karşılaştırma[/b]
kaydedilen_salt_bytes_pbkdf2 = bytes.fromhex(salt_hex_pbkdf2)
dogrulama_hash_pbkdf2 = password_hash_pbkdf2(sifre, salt=kaydedilen_salt_bytes_pbkdf2)[1]

print(f"PBKDF2 Doğrulama başarılı mı? {dogrulama_hash_pbkdf2 == hash_pbkdf2}")


Bu PBKDF2 örneği, iterations parametresiyle hash hesaplama işlemini binlerce kez tekrarlayarak saldırganların işini ne kadar zorlaştırdığını gösteriyor. İterasyon sayısı ne kadar yüksek olursa, hash'i kırmak o kadar uzun sürer. Günümüz standartlarında yüz binlerce veya milyonlarca iterasyon kullanmak yaygındır. Şifreler için bcrypt veya scrypt gibi daha modern KDF'ler de mevcut, ancak hashlib ile PBKDF2 de iyi bir başlangıç noktasıdır.

Peki, SHA256 kullanırken aklımızda bulundurmamız gereken başka neler var? encoding meselesi dışında, performans konusunda dikkatli olmak gerekebilir. Özellikle çok büyük veri setlerini veya milyonlarca küçük veriyi hash'lerken, bu işlemlerin CPU üzerinde bir yük oluşturabileceğini unutmayın. Ayrıca, hash fonksiyonlarının teorik olarak "çarpışma" (collision) riski taşıdığını bilmek de önemli. Yani, farklı iki girdinin aynı hash değerini üretme ihtimali teorik olarak var olsa da, SHA256 gibi güçlü algoritmalar için pratikte bu durumun yaşanma olasılığı yok denecek kadar düşüktür. Ancak yine de, hash değerini mutlak bir "benzersiz tanımlayıcı" olarak değil, bir "parmak izi" olarak düşünmek daha doğru olur.

Sonuç olarak, Python'ın hashlib modülü, SHA256 gibi kriptografik hash fonksiyonlarını kullanmak için bize güçlü ve esnek bir araç seti sunuyor. Metinlerden dosyalara, basit doğrulama işlemlerinden daha karmaşık güvenlik senaryolarına kadar birçok alanda karşımıza çıkıyor. Önemli olan, hangi durumda hangi yaklaşımın en uygun olduğunu bilmek ve güvenlik prensiplerini doğru uygulamak... Özellikle şifreler gibi hassas verilerle çalışırken ekstra dikkatli olmak şart.

Siz daha önce SHA256'yı hangi projelerinizde kullandınız? Ya da Python'da hashleme ile ilgili karşılaştığınız ilginç durumlar veya püf noktaları var mı? Deneyimlerinizi ve görüşlerinizi merak ediyorum, paylaşırsanız sevinirim!

Yanıt vermek için giriş yapmış olmalısınız.

0 alıntı seçildi