← Kursa Dön
📄 Text · 22 min

Kriptoloji: Hash, AES, RSA ve Dijital İmza

Kriptoloji Nedir?

Kriptoloji, bilgiyi yetkisiz erişimden koruma bilimidir. Kelime Yunanca *kryptos* (gizli) ve *logos* (bilim) kelimelerinden gelir. Günümüzde her gün farkında olmadan kriptografi kullanıyorsun — WhatsApp mesajından banka işlemine, Netflix'ten GitHub'a kadar.

Ama bu hikaye dünden başlamadı. Binlerce yıllık bir geçmişi var.

Tarihçe: Caesar'dan Quantum'a

Caesar Şifresi (MÖ 58): Julius Caesar, askerlerine gönderdiği mesajlarda her harfi alfabede 3 ileri kaydırıyordu. "SALDIR" → "VDOGLU" gibi. Basit ama o dönem için yeterliydi.

Enigma Makinesi (1930-1945): Nazi Almanyası, Enigma adlı elektromekanik bir cihazla mesajlarını şifreliyordu. Olası anahtar sayısı yaklaşık 159 katrilyon (159 × 10¹⁸) idi. Alan Turing ve ekibi bu şifreyi kırarak savaşın seyrini değiştirdi.

Modern Kriptografi (1970+): DES, RSA, AES gibi algoritmalar ortaya çıktı. Artık kağıt-kalem yerine matematik ve bilgisayar bilimi var. Bugün kullandığımız AES-256'yı kırmak için evrendeki tüm atomları bilgisayar yapsan bile yetmez — o kadar güçlü.

# Caesar cipher — tarihin en eski şifreleme yöntemi
def caesar_encrypt(text, shift):
    result = ""
    for char in text:
        if char.isalpha():
            base = ord('A') if char.isupper() else ord('a')
            result += chr((ord(char) - base + shift) % 26 + base)
        else:
            result += char
    return result

message = "Saldiri gece baslar"
encrypted = caesar_encrypt(message, 3)
print(f"Orijinal:  {message}")
print(f"Şifreli:   {encrypted}")
# Şifreli:   Vdoglul jhfh edvodu

Kriptolojinin iki ana dalı var: kriptografi (şifreleme yapma) ve kriptanaliz (şifre kırma). Biz bu derste kriptografi tarafına odaklanacağız.


Hash Fonksiyonları — Dijital Parmak İzi

Parmak İzi Analojisi

Bir hash fonksiyonunu dijital parmak izi olarak düşün. Tıpkı her insanın parmak izi benzersiz olduğu gibi, her verinin hash değeri de benzersizdir. Parmak izinden insanı yeniden oluşturamazsın — hash'ten de orijinal veriyi geri elde edemezsin.

Hash fonksiyonlarının üç temel özelliği var:

  1. Tek yönlü (one-way): Hash'ten orijinal veriye dönemezsin.

  2. Deterministik: Aynı girdi her zaman aynı çıktıyı verir.

  3. Çığ etkisi (avalanche effect): Girdide 1 bit değişiklik, çıktıyı tamamen değiştirir.

import hashlib

# Çığ etkisini gör — 1 harf fark, tamamen farklı hash
text1 = "Merhaba Dünya"
text2 = "merhaba Dünya"  # sadece 'M' → 'm'

hash1 = hashlib.sha256(text1.encode('utf-8')).hexdigest()
hash2 = hashlib.sha256(text2.encode('utf-8')).hexdigest()

print(f"'{text1}' → {hash1}")
print(f"'{text2}' → {hash2}")
print(f"Eşleşme:    {hash1 == hash2}")  # False
# İki hash birbirine hiç benzemez!

Hash fonksiyonları şifreleme değildir — veriyi gizlemez, sadece bir "özet" (digest) üretir. Sabit uzunlukta çıktı verir: SHA-256 her zaman 64 karakter hex string döner, girdi ister 1 byte ister 1 TB olsun.

hashlib Modülü — Python'un Hash Araç Kutusu

Python'un hashlib modülü, tüm yaygın hash algoritmalarını standart kütüphanede sunar. Hiçbir ek kurulum gerektirmez.

import hashlib

data = "Python kriptografi dersi".encode('utf-8')

# MD5 — 128 bit, ARTIK GÜVENLİ DEĞİL (collision bulundu)
md5_hash = hashlib.md5(data).hexdigest()
print(f"MD5:     {md5_hash}")        # 32 karakter

# SHA-256 — 256 bit, günümüzde standart
sha256_hash = hashlib.sha256(data).hexdigest()
print(f"SHA-256: {sha256_hash}")     # 64 karakter

# SHA-3 — en yeni standart (Keccak tabanlı)
sha3_hash = hashlib.sha3_256(data).hexdigest()
print(f"SHA3:    {sha3_hash}")       # 64 karakter

# Mevcut algoritmaları listele
print(f"\nKullanılabilir: {sorted(hashlib.algorithms_available)}")

⚠️ Dikkat: MD5 artık güvenli kabul edilmiyor. 2004'te çarpışma (collision) saldırısı bulundu — iki farklı girdi aynı MD5 hash'ini üretebiliyor. Güvenlik gerektiren hiçbir yerde MD5 kullanma. Sadece dosya bütünlüğü gibi güvenlik-dışı kontrollerde kabul edilebilir, ama SHA-256 tercih et.

SHA Ailesi Karşılaştırma

AlgoritmaÇıktı (bit)GüvenlikKullanım
MD5128❌ KırıkSadece checksum
SHA-1160❌ KırıkKullanma
SHA-256256✅ GüvenliGenel amaç
SHA-512512✅ GüvenliYüksek güvenlik
SHA3-256256✅ GüvenliYeni projeler

Dosya Hash'i Hesaplama — Bütünlük Kontrolü

İnternetten büyük bir dosya indirdin. Acaba dosya tam indi mi? Yoksa bozulma veya değişiklik var mı? İşte dosya hash'i burada devreye girer.

Büyük dosyaları hash'lerken dikkatli olmalısın — tüm dosyayı belleğe yüklemek yerine parça parça (chunk) okumalısın. Aksi takdirde 4 GB'lık bir ISO dosyası RAM'ini tüketir.

import hashlib

def calculate_file_hash(filepath, algorithm='sha256', chunk_size=8192):
    """Dosya hash'ini parça parça hesapla (bellek dostu)."""
    h = hashlib.new(algorithm)
    with open(filepath, 'rb') as f:
        while True:
            chunk = f.read(chunk_size)
            if not chunk:
                break
            h.update(chunk)
    return h.hexdigest()

# Kullanım
file_hash = calculate_file_hash("document.pdf")
print(f"SHA-256: {file_hash}")

# İki dosyayı karşılaştır
hash1 = calculate_file_hash("original.zip")
hash2 = calculate_file_hash("downloaded.zip")
print(f"Dosyalar eşit mi? {hash1 == hash2}")

update() metodu hash nesnesine parça parça veri eklemenizi sağlar. h.update(a); h.update(b) ile h.update(a + b) aynı sonucu verir — büyük dosyaları parça parça hash'lemenin temeli budur.

💡 İpucu: Linux/Mac'te sha256sum dosya.txt komutuyla dosya hash'ini terminal üzerinden hesaplayabilirsin. Python kodunun ürettiği hash ile karşılaştırarak doğrulama yapabilirsin.


HMAC — Mesaj Doğrulama

Hash tek başına bir şeyi garanti etmez: mesajı kimin gönderdiğini. Bir saldırgan mesajı değiştirir ve yeni hash'ini hesaplarsa, alıcı farkı anlayamaz. İşte HMAC (Hash-based Message Authentication Code) bu sorunu çözer.

HMAC, hash hesaplamasına bir gizli anahtar ekler. Anahtarı bilmeyen biri geçerli bir HMAC üretemez. Böylece hem mesajın bütünlüğünü hem de göndericinin kimliğini doğrularsın.

import hmac
import hashlib

# Gönderici ve alıcı bu anahtarı paylaşır (güvenli kanaldan)
secret_key = b"super-secret-key-2024"

# Gönderici tarafı: mesajı imzala
message = "100 TL transfer et, hesap: TR12345"
signature = hmac.new(secret_key, message.encode('utf-8'), hashlib.sha256).hexdigest()
print(f"Mesaj:  {message}")
print(f"HMAC:   {signature}")

# Alıcı tarafı: mesajı doğrula
received_message = "100 TL transfer et, hesap: TR12345"
expected_sig = hmac.new(secret_key, received_message.encode('utf-8'), hashlib.sha256).hexdigest()

# Güvenli karşılaştırma (timing attack'a karşı)
is_valid = hmac.compare_digest(signature, expected_sig)
print(f"Geçerli mi? {is_valid}")  # True

Neden == yerine hmac.compare_digest() kullanıyoruz? Normal string karşılaştırması ilk farklı karakterde durur — bu süre farkı saldırgana ipucu verir (timing attack). compare_digest() her zaman sabit sürede çalışır.

⚠️ Dikkat: HMAC anahtarını asla kaynak koduna veya Git reposuna yazma. Ortam değişkenleri (os.environ) veya güvenli bir secret manager kullan. Anahtarın sızması, tüm HMAC güvenliğini ortadan kaldırır.


Password Hashing — Neden SHA-256 Yetmez?

"Parolaları SHA-256 ile hash'leyip veritabanına kaydedeyim" diye düşünebilirsin. Mantıklı görünüyor ama tehlikeli bir hata olur. Neden mi?

Rainbow Table Problemi

SHA-256 çok hızlı çalışır — modern bir GPU saniyede milyarlarca SHA-256 hesaplayabilir. Saldırganlar yaygın parolaların hash'lerini önceden hesaplayıp devasa tablolar oluşturur. Buna rainbow table denir. "123456", "password", "qwerty" gibi parolaların SHA-256 hash'leri zaten biliniyor.

import hashlib

# Rainbow table simülasyonu — saldırganın bakış açısı
common_passwords = ["123456", "password", "qwerty", "admin", "letmein"]
rainbow_table = {}

# Saldırgan önceden hesaplar
for pwd in common_passwords:
    h = hashlib.sha256(pwd.encode()).hexdigest()
    rainbow_table[h] = pwd

# Veritabanından çalınan hash
stolen_hash = hashlib.sha256("admin".encode()).hexdigest()

# Saldırgan tablosunda arar
if stolen_hash in rainbow_table:
    print(f"Parola kırıldı: {rainbow_table[stolen_hash]}")
    # Parola kırıldı: admin

Çözüm: Salt + Yavaş Hash

İki savunma mekanizması var:

Salt: Her parola için rastgele bir değer eklenir. Aynı parola bile farklı hash üretir — rainbow table işe yaramaz hale gelir.

Yavaş hash: Özellikle yavaş çalışmak üzere tasarlanmış algoritmalar kullanılır. bcrypt, scrypt ve Argon2 bu iş için tasarlandı. Yavaşlık burada bir özellik, hata değil.

import hashlib
import os

# Salt ile SHA-256 (temel kavram gösterimi)
def hash_password_with_salt(password):
    salt = os.urandom(16)  # 16 byte rastgele salt
    salted = salt + password.encode('utf-8')
    hashed = hashlib.sha256(salted).hexdigest()
    # Salt'ı hash ile birlikte sakla (salt gizli değildir)
    return salt.hex() + ":" + hashed

def verify_password(password, stored):
    salt_hex, stored_hash = stored.split(":")
    salt = bytes.fromhex(salt_hex)
    salted = salt + password.encode('utf-8')
    computed = hashlib.sha256(salted).hexdigest()
    return computed == stored_hash

stored = hash_password_with_salt("güçlü_parola_123")
print(f"Saklanan: {stored}")
print(f"Doğrulama: {verify_password('güçlü_parola_123', stored)}")  # True
print(f"Yanlış:    {verify_password('yanlış_parola', stored)}")     # False

💡 İpucu: Gerçek projelerde parola hash'leme için bcrypt, scrypt veya argon2-cffi kütüphanelerini kullan. Python 3.x standart kütüphanesinde hashlib.scrypt() fonksiyonu mevcut ama daha yüksek seviyeli kütüphaneler daha güvenli varsayılanlar sunar.

Parola Hash Algoritması Karşılaştırma

AlgoritmaHızBellekTercih
SHA-256❌ Çok hızlıDüşükParola için KULLANMA
bcrypt✅ YavaşDüşükİyi seçim
scrypt✅ YavaşYüksekDaha iyi
Argon2✅ AyarlanabilirAyarlanabilirEn iyi (2015 kazananı)

Simetrik Şifreleme — Tek Anahtar, Tek Kasa

Kasa Analojisi

Simetrik şifrelemeyi bir kasa olarak düşün. Kasayı kilitlemek ve açmak için aynı anahtar kullanılır. Mesajı gönderen kasa ile kilitler, alan aynı anahtarla açar. Basit ve hızlı — ama bir sorun var: anahtarı karşı tarafa güvenli bir şekilde nasıl ulaştıracaksın?

AES (Advanced Encryption Standard), 2001'den beri dünya standardı olan simetrik şifreleme algoritmasıdır. ABD hükümeti tarafından seçildi ve bugün hâlâ kırılmamış durumda. AES-128, AES-192 ve AES-256 olmak üzere üç anahtar boyutu var.

AES Modları: CBC vs GCM

AES bir blok şifredir — veriyi 16 byte'lık bloklara böler ve her bloğu şifreler. Ama blokları nasıl birbirine bağlayacağın önemli. İşte modlar burada devreye girer:

CBC (Cipher Block Chaining): Her blok, önceki bloğun şifreli halinin XOR'u ile şifrelenir. IV (Initialization Vector) gerektirir. Yaygın ama bütünlük kontrolü sağlamaz.

GCM (Galois/Counter Mode): Hem şifreler hem de bütünlük kontrolü yapar (AEAD). Modern uygulamalarda her zaman GCM tercih et. TLS 1.3 ve çoğu modern protokol GCM kullanır.

Python'da XOR Cipher — Kavramsal Örnek

AES'i stdlib ile doğrudan uygulayamayız (çok karmaşık), ama simetrik şifrelemenin temel mantığını XOR ile gösterebiliriz. XOR şifreleme, simetrik şifrelemenin en basit formudur.

import os

def xor_cipher(data, key):
    """XOR tabanlı basit simetrik şifreleme (eğitim amaçlı)."""
    # Anahtarı veri uzunluğuna genişlet (tekrarlayarak)
    extended_key = (key * (len(data) // len(key) + 1))[:len(data)]
    return bytes(a ^ b for a, b in zip(data, extended_key))

# Rastgele anahtar üret
key = os.urandom(16)  # 128 bit anahtar

# Şifrele
plaintext = "Gizli mesaj: Buluşma saat 3'te".encode('utf-8')
ciphertext = xor_cipher(plaintext, key)
print(f"Şifreli (hex): {ciphertext.hex()}")

# Aynı anahtarla çöz (XOR kendi tersidir!)
decrypted = xor_cipher(ciphertext, key)
print(f"Çözülmüş:      {decrypted.decode('utf-8')}")
# Gizli mesaj: Buluşma saat 3'te

XOR'un güzel yanı: aynı işlem hem şifreler hem çözer. A XOR K = C ve C XOR K = A. Ama gerçek dünyada XOR cipher güvenli değildir — anahtar tekrarı, bilinen düz metin saldırıları gibi zafiyetleri var.

⚠️ Dikkat: Yukarıdaki XOR cipher sadece eğitim amaçlıdır. Gerçek projelerde kesinlikle AES-GCM kullan. Kendi şifreleme algoritmanı icat etme — bu kriptografinin 1 numaralı kuralıdır: "Don't roll your own crypto."

Fernet ile Gerçek Simetrik Şifreleme

Gerçek uygulamalarda cryptography kütüphanesinin Fernet modülünü kullan. Fernet, AES-128-CBC üzerine HMAC doğrulaması ekler ve kullanımı son derece basittir.

# NOT: Bu örnek 'cryptography' kütüphanesi gerektirir
# Kurulum: pip install cryptography

# from cryptography.fernet import Fernet
#
# # Anahtar üret (güvenli bir yerde sakla!)
# key = Fernet.generate_key()
# print(f"Anahtar: {key.decode()}")
#
# cipher = Fernet(key)
#
# # Şifrele
# plaintext = b"Cok gizli veri: kredi kart no 4532-XXXX"
# encrypted = cipher.encrypt(plaintext)
# print(f"Sifreli: {encrypted}")
#
# # Çöz
# decrypted = cipher.decrypt(encrypted)
# print(f"Cozulmus: {decrypted.decode()}")
#
# # Anahtar yanlışsa DecryptionError fırlatır
# wrong_key = Fernet.generate_key()
# wrong_cipher = Fernet(wrong_key)
# # wrong_cipher.decrypt(encrypted)  # InvalidToken hatası!

# Fernet avantajları:
# - Otomatik IV üretimi
# - HMAC ile bütünlük kontrolü
# - Timestamp ile zaman aşımı desteği (token TTL)

💡 İpucu: Fernet anahtarını Fernet.generate_key() ile üret ve bir dosya veya ortam değişkeninde sakla. Anahtarı kaybedersen şifreli verileri asla geri açamazsın. Yedek anahtarın olduğundan emin ol.


Asimetrik Şifreleme — Açık Kilit, Gizli Anahtar

Açık Kilit Analojisi

Asimetrik şifrelemeyi bir asma kilit olarak düşün. Herkese açık kilitlerin kopyalarını dağıtırsın (public key). İsteyen herkes bir kutuya mesaj koyup senin asma kilitinle kilitleyebilir. Ama kilidi açacak tek anahtar — gizli anahtar (private key) — sadece sende.

Simetrik şifrelemede en büyük sorun anahtar paylaşımıydı: anahtarı karşı tarafa nasıl güvenle göndereceksin? Asimetrik şifreleme bu sorunu çözer — public key herkesle paylaşılabilir, gizli kalması gereken sadece private key'dir.

RSA Nasıl Çalışır?

RSA (Rivest–Shamir–Adleman, 1977), en bilinen asimetrik şifreleme algoritmasıdır. Güvenliği, büyük sayıların çarpanlarına ayrılmasının (factorization) zorluğuna dayanır.

Temel mantık şöyle: iki büyük asal sayıyı çarpmak kolay (milisaniye), ama çarpımdan orijinal asal sayıları bulmak çok zor (yıllar). 7 × 13 = 91 kolay. Peki 323'ün çarpanları? Biraz düşünmen gerekir (17 × 19).

# RSA'nın temel matematik mantığı — küçük sayılarla gösterim
# UYARI: Bu sadece kavramsal gösterim, gerçek RSA değil!

# 1. İki asal sayı seç
p, q = 61, 53
n = p * q           # 3233 (modül)
phi = (p-1) * (q-1) # 3120 (Euler totient)

# 2. Public exponent seç (genellikle 65537)
e = 17  # phi ile aralarında asal olmalı

# 3. Private exponent hesapla: d * e ≡ 1 (mod phi)
d = pow(e, -1, phi)  # Python 3.8+ modüler ters
print(f"Public key:  (e={e}, n={n})")
print(f"Private key: (d={d}, n={n})")

# 4. Şifrele: c = m^e mod n
message = 42  # küçük bir sayı
ciphertext = pow(message, e, n)
print(f"\nOrijinal:  {message}")
print(f"Şifreli:   {ciphertext}")

# 5. Çöz: m = c^d mod n
decrypted = pow(ciphertext, d, n)
print(f"Çözülmüş:  {decrypted}")
# Orijinal mesaj geri geldi!

Gerçek RSA'da n sayısı en az 2048 bit (yaklaşık 617 basamaklı bir sayı). Bu boyuttaki bir sayıyı çarpanlarına ayırmak, mevcut bilgisayarlarla milyonlarca yıl sürer.

Production'da cryptography kütüphanesi ile RSA kullanımı: rsa.generate_private_key(public_exponent=65537, key_size=2048) ile anahtar üretilir, public_key.encrypt(message, padding.OAEP(...)) ile şifrelenir, private_key.decrypt(ciphertext, padding.OAEP(...)) ile çözülür. Kurulum: pip install cryptography.

Simetrik vs Asimetrik Karşılaştırma

ÖzellikSimetrik (AES)Asimetrik (RSA)
Anahtar sayısı1 (paylaşılan)2 (public + private)
Hız✅ Çok hızlı❌ Yavaş (~100x)
Anahtar dağıtımı❌ Zor✅ Kolay
KullanımVeri şifrelemeAnahtar değişimi, imza
Tipik boyut128-256 bit2048-4096 bit

Pratikte ikisi birlikte kullanılır: RSA ile simetrik anahtarı güvenle paylaşırsın, sonra hızlı AES ile veriyi şifrelersin. Buna hibrit şifreleme denir ve TLS/HTTPS tam olarak böyle çalışır.


Elliptic Curve Cryptography (ECC) — RSA'nın Modern Alternatifi

ECC (Eliptik Eğri Kriptografisi), RSA ile aynı işi yapar ama çok daha küçük anahtarlarla. 256 bit ECC anahtarı, 3072 bit RSA anahtarıyla eşdeğer güvenlik sağlar. Bu da daha az hesaplama, daha az bant genişliği ve daha hızlı işlem demek.

Neden ECC Daha Verimli?

RSA'nın güvenliği büyük sayıların çarpanlarına ayrılmasının zorluğuna dayanırken, ECC eliptik eğri üzerinde ayrık logaritma probleminin zorluğuna dayanır. Bu problem matematiksel olarak daha zor, bu yüzden aynı güvenlik seviyesine daha kısa anahtarla ulaşılır.

Güvenlik SeviyesiRSA AnahtarECC AnahtarKazanç
80 bit1024 bit160 bit6.4x
128 bit3072 bit256 bit12x
256 bit15360 bit512 bit30x

Bitcoin, Signal, WhatsApp ve modern TLS bağlantıları ECC kullanır. Mobil ve IoT gibi kaynak kısıtlı ortamlarda büyük avantaj sağlar.

Popüler ECC eğrileri: P-256 (NIST), Curve25519 (Daniel Bernstein) ve secp256k1 (Bitcoin).


Dijital İmza — Kim Gönderdi, Değiştirildi mi?

Dijital imza, gerçek hayattaki ıslak imzanın dijital karşılığıdır — ama çok daha güvenli. İki şeyi garanti eder:

  1. Kimlik doğrulama (authentication): Mesajı gerçekten iddia eden kişi mi gönderdi?

  2. Bütünlük (integrity): Mesaj yolda değiştirilmiş mi?

  3. İnkar edememe (non-repudiation): Gönderen "Ben göndermedim" diyemez.

İmzalama Süreci

Dijital imza, asimetrik şifrelemenin tersine çalışır:

  • İmzalama: Private key ile yapılır (sadece gönderen yapabilir)

  • Doğrulama: Public key ile yapılır (herkes yapabilir)

# Dijital imzanın kavramsal gösterimi (basitleştirilmiş)
import hashlib
import hmac

# Gönderici: mesajı imzala
def sign_message(message, private_key):
    """Mesajı hash'le ve private key ile imzala (basitleştirilmiş HMAC)."""
    msg_hash = hashlib.sha256(message.encode('utf-8')).digest()
    signature = hmac.new(private_key, msg_hash, hashlib.sha256).hexdigest()
    return signature

# Alıcı: imzayı doğrula
def verify_signature(message, signature, private_key):
    """İmzanın geçerli olduğunu doğrula."""
    expected = sign_message(message, private_key)
    return hmac.compare_digest(signature, expected)

key = b"private-key-of-sender"
msg = "Sözleşmeyi onaylıyorum."

sig = sign_message(msg, key)
print(f"İmza: {sig[:32]}...")
print(f"Geçerli:    {verify_signature(msg, sig, key)}")           # True
print(f"Değişmiş:   {verify_signature(msg + '!', sig, key)}")     # False

Gerçek dijital imza RSA veya ECDSA (Elliptic Curve Digital Signature Algorithm) kullanır. Yukarıdaki HMAC örneği kavramsal gösterimdir — gerçek asimetrik imzada public key ile doğrulama yapılır, private key paylaşılmaz. Production'da cryptography kütüphanesi ile private_key.sign(message, padding.PSS(...), hashes.SHA256()) ve public_key.verify(signature, message, ...) kullanılır.


SSL/TLS — HTTPS Nasıl Çalışır?

Tarayıcıda 🔒 kilit simgesini görüyorsun — peki arka planda ne oluyor? TLS (Transport Layer Security), tüm internet trafiğini koruyan protokoldür. HTTPS = HTTP + TLS.

El Sıkışma (TLS Handshake)

TLS bağlantısı kurulurken bir "el sıkışma" gerçekleşir. Bu süreç yaklaşık 2-4 mesaj alışverişi sürer (TLS 1.3'te sadece 1 round-trip). İşte adımlar:

1. Client Hello: Tarayıcı desteklediği şifreleme yöntemlerini ve rastgele bir sayı gönderir.

2. Server Hello + Sertifika: Sunucu şifreleme yöntemini seçer, dijital sertifikasını (public key) gönderir.

3. Sertifika Doğrulama: Tarayıcı, sertifikanın güvenilir bir CA tarafından imzalandığını doğrular.

4. Anahtar Değişimi: ECDHE ile ortak simetrik anahtar üretilir — ağ üzerinden doğrudan gönderilmez.

5. Şifreli İletişim: Tüm veri AES-GCM ile şifrelenir.

Tarayıcı                              Sunucu
   |                                      |
   |--- Client Hello (desteklenenler) --->|
   |                                      |
   |<-- Server Hello + Sertifika ---------|
   |                                      |
   |--- Anahtar Değişimi (ECDHE) ------->|
   |                                      |
   |<===== AES-GCM ile şifreli tünel ===>|
   |   (artık tüm veri şifreli akar)     |

TLS hibrit şifreleme kullanır: asimetrik (ECDHE) sadece anahtar değişimi için, sonra hızlı simetrik (AES) devam eder.

import ssl
import socket

# Python ile bir sunucunun TLS sertifikasını incele
def inspect_tls_certificate(hostname, port=443):
    """Bir web sitesinin TLS sertifika bilgilerini al."""
    context = ssl.create_default_context()
    with socket.create_connection((hostname, port)) as sock:
        with context.wrap_socket(sock, server_hostname=hostname) as ssock:
            cert = ssock.getpeercert()
            print(f"Sunucu:    {hostname}")
            print(f"Protokol:  {ssock.version()}")
            print(f"Cipher:    {ssock.cipher()[0]}")
            print(f"Konu:      {cert.get('subject', 'N/A')}")
            print(f"Veren:     {cert.get('issuer', 'N/A')}")
            expire = cert.get('notAfter', 'N/A')
            print(f"Bitiş:     {expire}")

# Kullanım (internet bağlantısı gerektirir)
# inspect_tls_certificate("www.google.com")
# inspect_tls_certificate("github.com")

Python secrets Modülü — Kriptografik Güvenli Rastgele

random modülü kriptografik olarak güvenli değildir. Oyun, simülasyon, istatistik için uygundur ama parola, token, anahtar üretmek için asla kullanma. secrets modülü, işletim sisteminin kriptografik rastgele sayı üretecini (CSPRNG) kullanır.

import secrets
import string

# 1. Güvenli token üret
token_hex = secrets.token_hex(32)       # 64 karakter hex
token_url = secrets.token_urlsafe(32)   # URL-safe base64
token_bytes = secrets.token_bytes(32)   # 32 byte ham veri

print(f"Hex token:     {token_hex}")
print(f"URL-safe:      {token_url}")
print(f"Bytes (len):   {len(token_bytes)}")

# 2. Güvenli parola üret
alphabet = string.ascii_letters + string.digits + "!@#$%"
password = ''.join(secrets.choice(alphabet) for _ in range(16))
print(f"Parola:        {password}")

# 3. Güvenli rastgele sayı
number = secrets.randbelow(1_000_000)  # 0 ile 999999 arası
print(f"Rastgele sayı: {number}")

API key doğrulama için secrets.compare_digest(stored, received) kullan — timing attack'a karşı sabit zamanlı karşılaştırma yapar. OTP üretimi için: ''.join(str(secrets.randbelow(10)) for _ in range(6)).

💡 İpucu: Token uzunluğu en az 32 byte (256 bit) olmalı. secrets.token_hex(32) veya secrets.token_urlsafe(32) kullan. Daha kısa tokenler brute-force saldırılarına karşı savunmasız kalabilir.

random vs secrets

Özellikrandomsecrets
Güvenlik❌ Tahmin edilebilir✅ Kriptografik güvenli
KaynakMersenne Twister (PRNG)OS CSPRNG
KullanımOyun, simülasyonParola, token, anahtar
HızHızlıBiraz yavaş

JWT Token Yapısı — Gerçek Dünya Uygulaması

JWT (JSON Web Token), modern web uygulamalarında kimlik doğrulama için en yaygın kullanılan yapıdır. Her API çağrısında "Ben kimim" sorusuna cevap verir. JWT, öğrendiğimiz tüm kavramları bir araya getirir: Base64 encoding, JSON, hash ve dijital imza.

JWT'nin Üç Parçası

Bir JWT token şöyle görünür:

eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWxpIn0.XXXXXXXXXXX
|______ Header ______|.|_____ Payload _____|.|__ Signature __|

Header: Algoritma ve token tipi bilgisi. {"alg": "HS256", "typ": "JWT"}

Payload: Taşınan veri (claims). {"user": "ali", "role": "admin", "exp": 1735689600}

Signature: Header + Payload'ın gizli anahtarla imzalanmış hali. Değişiklik yapılırsa imza tutmaz.

import json
import hashlib
import hmac
import base64

def base64url_encode(data):
    """JWT için URL-safe Base64 encoding (padding olmadan)."""
    return base64.urlsafe_b64encode(data).rstrip(b'=').decode()

def create_jwt(payload, secret_key):
    """Basit JWT oluştur (HS256 — eğitim amaçlı)."""
    header = {"alg": "HS256", "typ": "JWT"}

    # Header ve Payload'ı encode et
    header_b64 = base64url_encode(json.dumps(header).encode())
    payload_b64 = base64url_encode(json.dumps(payload).encode())

    # İmzala: HMAC-SHA256(header.payload, secret)
    message = f"{header_b64}.{payload_b64}".encode()
    signature = hmac.new(
        secret_key.encode(), message, hashlib.sha256
    ).digest()
    sig_b64 = base64url_encode(signature)

    return f"{header_b64}.{payload_b64}.{sig_b64}"

# JWT oluştur
token = create_jwt(
    {"user": "ali", "role": "admin", "exp": 1735689600},
    "super-secret-key"
)
print(f"JWT: {token}")
import json
import hashlib
import hmac
import base64

def base64url_decode(data):
    """JWT Base64URL decode (padding ekle)."""
    padding = 4 - len(data) % 4
    data += '=' * padding
    return base64.urlsafe_b64decode(data)

def verify_jwt(token, secret_key):
    """JWT token'ı doğrula ve payload'ı döndür."""
    parts = token.split('.')
    if len(parts) != 3:
        return None, "Geçersiz token formatı"

    header_b64, payload_b64, sig_b64 = parts

    # İmzayı yeniden hesapla
    message = f"{header_b64}.{payload_b64}".encode()
    expected_sig = hmac.new(
        secret_key.encode(), message, hashlib.sha256
    ).digest()

    actual_sig = base64url_decode(sig_b64)

    if not hmac.compare_digest(expected_sig, actual_sig):
        return None, "İmza geçersiz — token değiştirilmiş!"

    payload = json.loads(base64url_decode(payload_b64))
    return payload, "Geçerli"

# Doğrula
payload, status = verify_jwt(token, "super-secret-key")
print(f"Durum: {status}")
print(f"Payload: {payload}")

# Yanlış anahtarla dene
_, status2 = verify_jwt(token, "wrong-key")
print(f"Yanlış anahtar: {status2}")

⚠️ Dikkat: JWT payload'ı şifreli değildir — sadece Base64 encoded'dır. Herkes decode edip içeriği okuyabilir. JWT'nin amacı gizlilik değil, bütünlük ve kimlik doğrulamadır. Hassas verileri (parola, kredi kartı) asla JWT payload'ına koyma.

JWT'de kullanılan HS256 (HMAC-SHA256) simetrik, RS256 (RSA-SHA256) asimetrik imza kullanır. Mikro servis mimarisinde RS256 tercih edilir — her servis public key ile doğrulama yapabilir, private key sadece auth servisinde kalır.



Özet

  • Hash fonksiyonları (SHA-256, SHA-3) verinin dijital parmak izini üretir — tek yönlüdür, geri döndürülemez. Dosya bütünlüğü kontrolü, veri doğrulama ve HMAC ile mesaj kimlik doğrulaması için kullanılır.

  • Parola hash'leme için SHA-256 yetmez — rainbow table saldırılarına karşı salt ekle ve kasıtlı olarak yavaş algoritmalar (bcrypt, scrypt, Argon2) kullan.

  • Simetrik şifreleme (AES) tek anahtarla çalışır, çok hızlıdır ve büyük verileri şifrelemek için idealdir. Modern uygulamalarda AES-GCM modunu tercih et.

  • Asimetrik şifreleme (RSA, ECC) iki anahtar kullanır: herkese açık public key ve gizli private key. Anahtar değişimi ve dijital imza için kritiktir. ECC, RSA'dan çok daha küçük anahtarlarla aynı güvenliği sağlar.

  • TLS/HTTPS, hibrit şifreleme kullanır — asimetrik şifreleme ile anahtar değişimi, simetrik şifreleme ile veri transferi. JWT tokenlar, HMAC veya RSA imzası ile mesaj bütünlüğünü ve kimlik doğrulamayı sağlar.

  • Python'da güvenli rastgele üretim için her zaman `secrets` modülünü kullan, random modülünü asla güvenlik amaçlı kullanma. Kriptografik işlemler için hashlib, hmac ve secrets stdlib modülleri temel araçlarındır; AES/RSA gibi ileri işlemler için cryptography kütüphanesini tercih et.