---
title: 'Kriptografi Kötüye Kullanımı'
source: 'https://academia.sh/tr/kurslar/guvenli-kodlama/kriptografi-kotuye-kullanimi'
course: 'Güvenli Kodlama'
language: tr
updated: '2026-08-17T18:06:42+00:00'
license: 'CC BY-SA 4.0'
---

# Kriptografi Kötüye Kullanımı

Kriptografi çağrı noktalarının kapsaması ve yanlış kullanımın somut sonucu: on dört çağrı noktasının yedisinin merkezî katmanın dışında kalması, aynı anahtarla aynı başlangıç değerini yeniden kullanmanın kırk konumu okunur hâle getirmesi, bütünlük etiketi olmayan şifrelemede biçim denetiminin yirmi dört değişiklikten dördünü kaçırması ve ilkel çağrı tek dosyaya kapatıldığında yeni noktanın kendiliğinden kapsanması.

Önceki ders kimin ne yapabildiğini kodda denetledi: yetki matrisindeki uçlar sayıldı, eşzamanlı
isteğin aynı kontrolden iki kez geçtiği durum ölçüldü. Bütün o denetimler bir şeye dayanıyordu.
Oturumu bir imza taşıyordu, saha uygulamasının yükleme belirtecini bir anahtar üretmişti, yerel
depo bir şifreleme çağrısıyla kilitlenmişti. Bu konu o kalemleri ele alır ve ilk soru onların
nerede saklandığı değil, **nasıl çağrıldığıdır**.

Kriptografi Temelleri kursu algoritmaların özelliklerini ölçmüştü. Burada o özellikler girdidir;
ölçülen şey **çağrı noktasıdır**. Bir kod tabanında kaç nokta kriptografi çağırıyor, kaçı merkezî
bir katmandan geçiyor, dışarıda kalan noktaların yanlış ayarı somut olarak neye mal oluyor.

## Kriptografi Çağrı Noktaları

**KI1 — kurgu bölgesel ölçüm ağının kod tabanında on dört kriptografi çağrı noktası vardır.** Bir
bölümü merkezî bir kripto katmanının dört işlevini çağırır; kalanı ilkel çağrıyı doğrudan yapar ve
kip, başlangıç değeri, tuz gibi ayarları kendi seçer. Aşağıdaki envanter bir modeldir; kaynak
adları kurgudur.

```js
// kripto/kapsama.mjs — kurgu olcum agi kod tabanindaki kriptografi cagri noktalari
// envanteri (model). kaynak: cagriyi yapan bilesen; katman: merkezi kripto katmanindan
// gecip gecmedigi; kusur: dogrudan cagrida secilen yanlis ayar.
const noktalar = [
  ['portal/oturum', 'sifreleme', false, 'etiketsiz kip'],
  ['portal/kayit', 'parola karmasi', true, null],
  ['portal/fatura-baglantisi', 'imza', true, null],
  ['alim/paket-acma', 'sifreleme', true, null],
  ['alim/yedek-yol', 'sifreleme', false, 'sabit baslangic degeri'],
  ['alim/es-zamanlama', 'karma', false, 'kendi karma zinciri'],
  ['saha/yukleme-belirteci', 'imza', false, null],
  ['saha/yerel-onbellek', 'sifreleme', false, null],
  ['rapor/aktarim', 'sifreleme', true, null],
  ['rapor/dosya-adi', 'karma', true, null],
  ['rapor/arsiv', 'sifreleme', false, 'etiketsiz kip'],
  ['is-emri/imza', 'imza', true, null],
  ['is-emri/eski-uc', 'parola karmasi', false, 'tuzsuz karma'],
  ['bildirim/geri-cagirma', 'imza', true, null],
];

const say = (kume, kural) => kume.filter(kural).length;
const kusurlar = (kume) => {
  const g = {};
  for (const [, , , k] of kume.filter(([, , katman]) => !katman)) if (k) g[k] = (g[k] ?? 0) + 1;
  return Object.entries(g).sort((a, b) => b[1] - a[1]);
};
const yaz = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(''));

const D = [-26, 10, 10, 12, 12];
yaz(D, 'islem turu', 'nokta', 'katmanda', 'disarida', 'kusurlu');
for (const tur of ['sifreleme', 'imza', 'karma', 'parola karmasi']) {
  const t = noktalar.filter(([, i]) => i === tur);
  yaz(D, tur, t.length, say(t, ([, , k]) => k), say(t, ([, , k]) => !k), say(t, ([, , , k]) => k));
}
yaz(D, 'toplam', noktalar.length, say(noktalar, ([, , k]) => k),
  say(noktalar, ([, , k]) => !k), say(noktalar, ([, , , k]) => k));

console.log('\ndisarida kalan noktalarin kusur dagilimi:');
for (const [ad, n] of kusurlar(noktalar)) console.log(`  ${ad.padEnd(24)}${n}`);

// Yeni nokta eklendiginde ne oluyor: uc yeni cagri noktasi, iki ayri duzen.
const yeni = [
  ['saha/cevrimdisi-kuyruk', 'sifreleme'],
  ['portal/disa-aktarma', 'imza'],
  ['alim/olcum-arsivi', 'sifreleme'],
];
console.log('\nuc yeni cagri noktasi ekleniyor:');
const E = [-40, 8, 12, 18];
yaz(E, 'duzen', 'nokta', 'katmanda', 'yeni acik adayi');
// 1) Ilkel cagri serbest: yeni nokta katmani kullanmak zorunda degil.
yaz(E, 'katman var, dogrudan cagri serbest', noktalar.length + yeni.length,
  say(noktalar, ([, , k]) => k), yeni.length);
// 2) Ilkel cagri tek dosyada toplanmis: katmanin disina cikan nokta derlenmez.
yaz(E, 'ilkel cagri tek dosyaya kapatilmis', noktalar.length + yeni.length,
  say(noktalar, ([, , k]) => k) + yeni.length, 0);
console.log(`\nikinci duzende once kapatilmasi gereken nokta: ${say(noktalar, ([, , k]) => !k)}`);
```

```
islem turu                     nokta  katmanda    disarida     kusurlu
sifreleme                          6         2           4           3
imza                               4         3           1           0
karma                              2         1           1           1
parola karmasi                     2         1           1           1
toplam                            14         7           7           5

disarida kalan noktalarin kusur dagilimi:
  etiketsiz kip           2
  sabit baslangic degeri  1
  kendi karma zinciri     1
  tuzsuz karma            1

uc yeni cagri noktasi ekleniyor:
duzen                                      nokta    katmanda   yeni acik adayi
katman var, dogrudan cagri serbest            17           7                 3
ilkel cagri tek dosyaya kapatilmis            17          10                 0

ikinci duzende once kapatilmasi gereken nokta: 7
```

Toplam satırı bu dersin üç sütununu veriyor: on dört nokta var, yedisini merkezî katman örtüyor,
yedisi dışarıda kalıyor. Dördüncü sütun ise dışarıda kalmanın hemen açık anlamına gelmediğini
söylüyor — yedi noktanın beşi kusurlu, ikisi doğru ayarla çağırıyor. O iki nokta bugün doğrudur
çünkü onları yazan kişi ayarı bilerek seçmiştir; yarın da doğru kalacağını söyleyen hiçbir yapı
yoktur. Kapsamanın ölçüsü **şu anda kusurlu olan nokta sayısı değil, kusurlu olabilecek nokta
sayısıdır** ve o sayı yedidir.

Kusur dağılımı dört ayrı sınıf gösteriyor ve ikisi aynı kökten geliyor: bütünlük etiketi olmayan
bir kip seçmek ve başlangıç değerini sabit bırakmak. Üçüncüsü kendi karma zincirini yazmaktır,
dördüncüsü parolayı tuzsuz karmalamaktır. Aşağıdaki iki ölçüm önce üçüncü sınıfın, sonra ilk
ikisinin somut karşılığını sayar.

## Kendi Yazılan Karışımın Ölçüsü

Alım servisi yinelenen sayaç okumalarını ayırt etmek için elle yazılmış bir karışım işlevi
kullanıyor: her karakterin kodu toplanıyor ve otuz iki bitlik bir değer üretiliyor. İşlev
çalışıyor, sınamaları geçiyor ve hiçbir hata vermiyor.

```js
// kripto/zincir.mjs — envanterdeki "kendi karma zinciri" kusurunun olculmesi: alim servisi
// yinelenen okumayi ayirt etmek icin elle yazilmis bir karisim islevi kullaniyor (model).
import { createHash } from 'node:crypto';

const KAYIT = 20000;
const anahtarlar = Array.from({ length: KAYIT }, (_, i) =>
  `SAY-${4000 + (i % 2500)}|2026-03-${String(1 + (i % 28)).padStart(2, '0')}T06:00Z|${41000 + i}`);

// Elle yazilmis karisim: karakter kodlarinin toplami, 32 bitlik cikti.
const kendiKarisim = (s) => {
  let h = 0;
  for (let i = 0; i < s.length; i++) h = (h + s.charCodeAt(i)) | 0;
  return h >>> 0;
};
const hazirKarma = (s) => createHash('sha256').update(s).digest().readUInt32BE(0);

const olc = (f) => {
  const gorulen = new Set();
  let dusen = 0;
  for (const a of anahtarlar) {
    const k = f(a);
    if (gorulen.has(k)) dusen += 1; else gorulen.add(k);
  }
  return [gorulen.size, dusen];
};
const beklenen = KAYIT - 2 ** 32 * (1 - (1 - 1 / 2 ** 32) ** KAYIT);
console.log(`${KAYIT} kurgu okuma anahtari, hepsi ayri, cikti genisligi 32 bit:`);
console.log(`  32 bitte kuramsal beklenen sessiz dusme : ${beklenen.toFixed(2)}`);
for (const [ad, f] of [['hazir karma', hazirKarma], ['elle yazilmis karisim', kendiKarisim]]) {
  const [ayri, dusen] = olc(f);
  console.log(`  ${ad.padEnd(22)} ayri deger ${String(ayri).padStart(5)}, sessiz dusen ${dusen}`);
}
```

```
20000 kurgu okuma anahtari, hepsi ayri, cikti genisligi 32 bit:
  32 bitte kuramsal beklenen sessiz dusme : 0.05
  hazir karma            ayri deger 20000, sessiz dusen 0
  elle yazilmis karisim  ayri deger    67, sessiz dusen 19933
```

Otuz iki bitlik çıktı genişliğinde yirmi bin ayrı anahtarın çakışması kuramsal olarak 0,05
beklenir; hazır karmanın ilk otuz iki biti bu beklentiyi tutturuyor ve yirmi bin ayrı değer
üretiyor. Elle yazılmış karışım aynı kümede **altmış yedi** ayrı değer üretiyor ve on dokuz bin
dokuz yüz otuz üç okuma "zaten görülmüş" sayılarak sessizce düşüyor. Sebep açıktır: toplama işlemi
karakterlerin sırasını da, kaydın uzunluğunu da yok sayar, dolayısıyla çıktı uzayının otuz iki
bitlik genişliği hiçbir zaman kullanılmaz. Kendi algoritmasını yazmanın somut sonucu budur —
yazılan şey çalışır, kimse hata görmez ve düşünülmemiş olan özellik yoktur.

## Aynı Anahtar, Aynı Başlangıç Değeri

**KI2 — akış biçiminde çalışan bir şifrelemede aynı anahtar ve aynı başlangıç değeri iki kez
kullanılırsa, iki şifreli metnin bayt farkı iki düz metnin bayt farkına eşit olur.** Bu, bir
algoritma kusuru değildir; yapının kullanım koşulunun çiğnenmesidir. Ölçüm kendi yazdığımız
model üzerinde yapılır: aşağıdaki akış üreteci gerçek bir şifre değildir ve üretim kodunda
kendi şifresini yazan bir yaklaşımı temsil eder.

```js
// kripto/model.mjs — kendi yazdigimiz basit akis modeli ile hazir kimlik dogrulamali
// sifrelemenin ayni olcekte karsilastirilmasi. Model gercek bir sifre degildir; yalniz
// baslangic degeri yeniden kullanildiginda ve butunluk etiketi olmadiginda sizan bilgiyi
// saymak icin yazilmistir. Kurgu bolgesel olcum agindan iki sayac okumasi kullanilir.
import { createHash, createCipheriv, createDecipheriv } from 'node:crypto';

const ANAHTAR = createHash('sha256').update('kurgu-saha-anahtari').digest();
const OKUMA_A = Buffer.from('SAY-4417|2026-03-01T06:00Z|41982|sube-01');
const OKUMA_B = Buffer.from('SAY-4418|2026-03-01T06:00Z|41982|sube-02');
const BICIM = /^SAY-\d{4}\|\d{4}-\d{2}-\d{2}T\d{2}:\d{2}Z\|\d+\|sube-\d{2}$/;

// Kendi akis uretecimiz: anahtar ve baslangic degerinden bayt dizisi turetir.
function akis(bd, uzunluk) {
  const parcalar = [];
  for (let blok = 0; parcalar.length * 32 < uzunluk; blok++) {
    parcalar.push(createHash('sha256').update(ANAHTAR).update(bd).update(String(blok)).digest());
  }
  return Buffer.concat(parcalar).subarray(0, uzunluk);
}
const modelSifrele = (duz, bd) => Buffer.from(duz.map((b, i) => b ^ akis(bd, duz.length)[i]));
const modelCoz = (sifreli, bd) => Buffer.from(sifreli.map((b, i) => b ^ akis(bd, sifreli.length)[i]));

// Hazir yapi: kimlik dogrulamali sifreleme (AES-256-GCM); etiket paketle tasinir.
const aeSifrele = (duz, bd) => {
  const s = createCipheriv('aes-256-gcm', ANAHTAR, bd);
  return { govde: Buffer.concat([s.update(duz), s.final()]), etiket: s.getAuthTag() };
};
const aeCoz = ({ govde, etiket }, bd) => {
  const c = createDecipheriv('aes-256-gcm', ANAHTAR, bd);
  c.setAuthTag(etiket);
  return Buffer.concat([c.update(govde), c.final()]);
};

const BD1 = Buffer.alloc(12, 7), BD2 = Buffer.alloc(12, 9);
const esitSayisi = (x, y) => [...x].filter((b, i) => b === y[i]).length;
const yaz = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(''));

// 1) Ayni anahtarla ayni baslangic degeri: iki sifreli metin karsilastiriliyor.
console.log(`KI2 — ayni anahtar, iki kayit, uzunluk ${OKUMA_A.length} bayt,`
  + ` duz metinde esit konum ${esitSayisi(OKUMA_A, OKUMA_B)}:`);
const D = [-32, 14, 14, 14];
yaz(D, 'duzen', 'esit sifreli', 'fark okunur', 'sizan konum');
for (const [ad, c1, c2] of [
  ['model, ayni baslangic degeri', modelSifrele(OKUMA_A, BD1), modelSifrele(OKUMA_B, BD1)],
  ['model, ayri baslangic degeri', modelSifrele(OKUMA_A, BD1), modelSifrele(OKUMA_B, BD2)],
  ['etiketli, ayri baslangic degeri', aeSifrele(OKUMA_A, BD1).govde, aeSifrele(OKUMA_B, BD2).govde],
]) {
  const okunur = [...c1].every((b, i) => (b ^ c2[i]) === (OKUMA_A[i] ^ OKUMA_B[i]));
  yaz(D, ad, esitSayisi(c1, c2), okunur ? 'evet' : 'hayir', okunur ? OKUMA_A.length : 0);
}

// 2) Butunluk etiketi olmayan sifreleme: degistirilen paketi kim yakaliyor.
const DENEME = 24;
console.log(`\nKI3 — ${DENEME} paketin her birinde tek bit cevriliyor:`);
const E = [-32, 14, 14, 14];
yaz(E, 'duzen', 'bicim gecen', 'yakalanan', 'degisen bayt');
let gecen = 0, degisen = 0, aGecen = 0;
for (let k = 0; k < DENEME; k++) {
  const bd = Buffer.alloc(12, k + 16);
  const mc = Buffer.from(modelSifrele(OKUMA_A, bd));
  mc[k] ^= 1 << (k % 8);
  const cozulen = modelCoz(mc, bd);
  degisen += [...cozulen].filter((b, i) => b !== OKUMA_A[i]).length;
  if (BICIM.test(cozulen.toString('latin1'))) gecen += 1;

  const paket = aeSifrele(OKUMA_A, bd);
  paket.govde[k] ^= 1 << (k % 8);
  try { aeCoz(paket, bd); aGecen += 1; } catch { /* etiket reddetti */ }
}
yaz(E, 'model + bicim denetimi', gecen, DENEME - gecen, degisen);
yaz(E, 'kimlik dogrulamali sifreleme', aGecen, DENEME - aGecen, 0);
```

```
KI2 — ayni anahtar, iki kayit, uzunluk 40 bayt, duz metinde esit konum 38:
duzen                             esit sifreli   fark okunur   sizan konum
model, ayni baslangic degeri                38          evet            40
model, ayri baslangic degeri                 0         hayir             0
etiketli, ayri baslangic degeri              0         hayir             0

KI3 — 24 paketin her birinde tek bit cevriliyor:
duzen                              bicim gecen     yakalanan  degisen bayt
model + bicim denetimi                       4            20            24
kimlik dogrulamali sifreleme                 0            24             0
```

Birinci tablonun ilk satırı sızıntıyı sayıyla veriyor. İki sayaç okuması kırk baytlık kayıtlardır
ve düz metinde otuz sekiz konumda birbirine eşittir — ikisi de aynı tarihi, aynı okuma değerini ve
aynı biçimi taşır, yalnızca sayaç numarası ile şube kodunda ayrılır. Aynı başlangıç değeriyle
şifrelendiklerinde şifreli metinler de **tam olarak otuz sekiz konumda** eşit çıkıyor. Şifreli
metne bakan biri, iki kaydın nerede aynı nerede farklı olduğunu anahtarı hiç bilmeden okuyor.

"Fark okunur" sütunu daha keskin bir şey söylüyor: kırk konumun tamamında, iki şifreli metnin bayt
farkı iki düz metnin bayt farkına eşit. Şifreleme kaydın **değerini** değil yalnızca ham hâlini
gizler; iki kayıt arasındaki bütün ilişki şifreli tarafa aynen geçer. Bir okuma kümesinde bunun
anlamı, hangi kayıtların özdeş olduğunun ve bir şubenin okumalarının ne zaman durduğunun
sayılabilmesidir. İkinci ve üçüncü satır aynı ölçüde sıfır veriyor: başlangıç değeri her şifreleme
için ayrı olduğunda eşit konum sıfır, okunur fark yok. Kusur şifrelemede değil, tek bir
parametrenin sabit bırakılmasındadır.

## Değişikliği Fark Etmeyen Şifreleme

**KI3 — bütünlük etiketi olmayan bir şifreleme, çözmeyi reddedecek bir kaleme sahip değildir; her
şifreli metin bir düz metne çözülür.** İkinci tablo bu cümlenin kapsama karşılığını veriyor. Yirmi
dört pakette birer bit çevrildi; her çevirme çözülen düz metinde **tam olarak bir bayt** değiştirdi
— toplam yirmi dört bayt, paket başına bir. Akış biçiminde şifreli metnin bir konumundaki değişim
düz metnin aynı konumuna düşer, ne yayılır ne de fark edilir.

Bu noktada tek savunma alıcı tarafın biçim denetimidir ve tablo onun kapsamasını sayıyor: yirmi
dört değişikliğin yirmisini yakalıyor, **dördünü kaçırıyor**. Kaçırılan dördü, düz metnin biçim
kalıbına uyan konumlarına düşenlerdir — sayaç numarasının ya da okuma değerinin rakamları. Sonuç,
kaydın hâlâ geçerli göründüğü ama taşıdığı değerin başka olduğu bir pakettir; faturalama tarafında
bunun karşılığı sessizce yanlış bir tüketimdir. Bir savunma noktaların çoğunu örtebilir ve yine de
örtmediği noktalar tam olarak önemli olanlar olabilir.

Son satır aynı ölçünün öteki ucudur: kimlik doğrulamalı şifrelemede yirmi dört değişikliğin yirmi
dördü reddedildi ve biçim denetimine iş düşmedi. Buradaki fark bir güç farkı değil, **kapsama
farkıdır** — bütünlük denetimi paketin tamamını, biçim denetimi yalnızca kalıba giren alanları
örter.

## Yeni Nokta Eklendiğinde

Üçüncü tablo kursun üçüncü sorusunu soruyor. Kod tabanına üç yeni çağrı noktası ekleniyor: saha
uygulamasının çevrimdışı kuyruğu, portalın dışa aktarma akışı, alım servisinin ölçüm arşivi. İlk
düzende merkezî katman vardır ama ilkel çağrı serbesttir. Nokta sayısı on dörtten on yediye
çıkıyor, katmandaki nokta sayısı **yedide kalıyor** ve üç yeni nokta doğrudan açık adayı oluyor.
Katman kimseyi bağlamadığı için yeni nokta onu kullanmak zorunda değildir; kapsama sabit kalmaz,
her eklemede düşer.

İkinci düzende ilkel çağrılar tek bir dosyada toplanmıştır ve o dosyanın dışındaki hiçbir yer
şifreleme, imza ya da karma ilkelini çağıramaz. Üç yeni nokta katmandan geçmek zorundadır; katman
sayısı ona çıkar, yeni açık adayı sıfırdır. Kapsamayı sabit tutan şey katmanın var olması değil,
**katmanın dışına çıkmanın mümkün olmamasıdır**. Bedeli son satırda yazılı: bu düzene geçmeden önce
dışarıda kalan yedi noktanın yedisini de taşımak gerekir, çünkü tek dosya kuralı ancak istisnası
olmadığında iş görür. Yedi noktalık bir borç, üç yeni noktanın her birinde tekrarlanacak bir
kararın yerini alır.

## Özet

- Kurgu ölçüm ağının kod tabanında on dört kriptografi çağrı noktası var; yedisi merkezî katmandan
  geçiyor, yedisi dışarıda kalıyor ve dışarıdakilerin beşi kusurlu ayarla çağırıyor. Kapsamanın
  ölçüsü kusurlu nokta sayısı değil, kusurlu olabilecek nokta sayısıdır.
- Elle yazılmış toplama karışımı yirmi bin ayrı anahtarda altmış yedi ayrı değer üretti ve 19.933
  okuma sessizce düştü; hazır karmanın ilk otuz iki biti kuramsal beklentiyle uyumlu, sıfır düşme
  verdi.
- Aynı anahtarla aynı başlangıç değeri kullanıldığında iki kırk baytlık kaydın şifreli metinleri
  otuz sekiz konumda eşit çıkıyor ve kırk konumun tamamında fark doğrudan okunuyor; ayrı başlangıç
  değerinde bu sayılar sıfır.
- Bütünlük etiketi olmayan şifrelemede tek bit çevirmek düz metinde tam bir bayt değiştiriyor;
  biçim denetimi yirmi dört değişikliğin yirmisini yakalıyor, dördünü kaçırıyor. Kimlik doğrulamalı
  şifreleme aynı yirmi dördün yirmi dördünü reddediyor.
- İlkel çağrı serbestken üç yeni nokta üç açık adayı ekliyor ve kapsama düşüyor; ilkel çağrı tek
  dosyaya kapatıldığında kapsama sabit kalıyor, bedeli önce yedi noktanın taşınmasıdır.

## Sonraki Adım

Bu dersteki bütün ölçümler bir şeyi verilmiş saydı: anahtarı ve başlangıç değerini üreten kaynağın
tahmin edilemez olduğunu. Oysa o kaynak da kod tabanında bir çağrı noktasıdır ve on dört noktalık
envanterde ayrı bir satır olarak görünmez. Saha uygulamasının yükleme belirtecini, portalın parola
sıfırlama bağlantısını ve fatura dosya adını üreten çağrılar aynı soruyu paylaşır: üretilen değeri
üçüncü bir taraf önceden hesaplayabilir mi? Sonraki ders bu soruyu iki üreteci aynı ölçüde
koşturarak yanıtlar — tohum bilindiğinde kaç değer önceden çıkıyor ve belirteç üreten noktaların
kaçı zayıf üreteci çağırıyor.
