Karartılmış bir imza SDK’sını ilk açtığınızda, her satırında anlaşılması güç bir sihir varmış hissine kapılmak kolaydır. Oysa tersine mühendislik akışının tamamından geçtiğinizde genellikle tam tersi ortaya çıkar.
Kodun %90’ı standart algoritmalardan oluşur. Kullanılan hash herkese açık bir hash’tir, encoding yöntemi herkese açık bir encoding’dir, akış şifresi de herkese açık bir akış şifresidir. Bu bölümleri gerçekten “anlamanız” gerekmez: Hangi algoritma olduğunu tanıyın, RFC’den veya referans implementasyondan alın; tek bir byte bile şaşmaz.
Öldürücü olan, geriye kalan %10’dur: Standart bir algoritmanın çok küçük ama sessiz bir dokunuşla değiştirildiği noktalar. Sabit olması gereken round sayısı değişkene dönüştürülmüş olabilir; temel sabit, yakın bir değerle değiştirilmiş olabilir; bir round’daki word indeksleri yer değiştirmiş olabilir; anahtar ciphertext’in içine saklanmış olabilir. Her değişiklik küçüktür ama bir tanesini bile kaçırırsanız yeniden yazdığınız kod hedefle eşleşmez. Üstelik diğer %90 doğru olduğu için hatanın nerede olduğunu da bulmak zorlaşır.
Dolayısıyla karartılmış bir imzayı çözmenin asıl işi, kodun %90’ını okumak değil; o %10’daki sapma noktalarını tespit etmektir. Bu yazıda, büyük bir modeli bu av işinde nasıl kullanabileceğinizi ve neden en zor ikame edilen adımın bu olduğunu ele alacağım.
(Ön koşul olan algoritma ailesini belirleme — sabitlerden ve yapıdan “bu ChaCha”, “bu FNV” diyebilme — önceki yazıda anlatıldı. Burada iskeleti zaten tanıdığınızı varsayıp doğrudan sapma avına geçiyorum.)
İnsan gözü sapma noktalarını neden kaçırır?
Örüntü tanıma sırasında insan zihninin güçlü bir eğilimi vardır: genel yapıyı tanır tanımaz ayrıntıları incelemeyi bırakır.
Bir kod bloğuna bakarsınız; sabitler ChaCha’nın parmak iziyle örtüşüyordur, yapı doğru görünüyordur ve zihniniz “bu ChaCha20” kutusunu işaretleyip ilerler. Her round sayısını, her indeksi, her sabitin en düşük bitini tek tek kontrol etmezsiniz. Çünkü “tanıdım” hissi, dikkatinizi kapatır.
Karartma yazarlarının güvendiği şey tam olarak budur. Algoritmayı baştan yazmazlar; bu hem maliyetli hem de hataya açıktır. Bunun yerine standart algoritmaya mümkün olan en küçük değişikliği yaparlar: Bir sayıyı değiştirir, bir indeksi takas eder, fazladan bir adım eklerler. Değişiklik örüntü tanımanızın atlayacağı kadar küçük, standart implementasyonla yazılmış karşılığınızı tamamen bozacak kadar büyüktür.
Bu, dikkat bakımından asimetrik bir savaştır. Karartmayı yazan kişinin tek bir sapmayı gizlemesi yeterlidir; sizin ise hepsini bulmanız gerekir. İnsanlar da doğru görünen bir şeye karşı şüpheyi sürdürmekte doğuştan iyi değildir.
Modelin burada sezgiye aykırı bir avantajı vardır: “bunu zaten tanıdım” tatmini nedeniyle dikkati dağılmaz. Prompt’ta açıkça sapmaları aramasını isterseniz, doğru yönlendirmeyle, yarı yolda gevşemeden maddeleri tek tek kontrol eder. Doğru prompt’un nasıl kurulacağını Bölüm 5 ele alıyor. Önce bu dört sapma türünün neye benzediğine bakalım.
Karşınıza çıkacak dört sapma türü
Aşağıdaki her türde önce açık bir standart algoritmanın normal hâlini, ardından sapmanın nasıl göründüğünü anlatacağım. Gerçek projelerde bu dört tekniğin aynı signer içinde üst üste kullanılması oldukça yaygındır.
1. Sabitin değişkene dönüşmesi: sabit parametrenin çalışma anında hesaplanması
Standart bir akış şifresinde round sayısı sabittir. ChaCha20 her zaman 20 round kullanır; bu sayı değişmez ve tüm standart implementasyonlarda hardcode edilir. RFC 8439 da girişinde bunu açıkça belirtir: Doküman yalnızca 20 round’lu ChaCha’yı tarif eder; 8 ve 12 round’lu sürümler başka kaynaklarda tanımlanmıştır. Round sayısı standartta her zaman sabittir.
Sapma şudur: bu sabit round sayısını anahtardan dinamik olarak hesaplanan bir değere dönüştürmek. Quarter-round mantığı aynıdır, ancak kaç kez çalışacağı anahtarın belirli byte’larına bağlıdır. Anahtarı değiştirince round sayısı da değişir.
İnsanların bunu kaçırma nedeni açıktır: Quarter-round yapısını ve σ sabitlerini görür, “ChaCha20” sonucuna varır ve kodu 20 round olarak kopyalarsınız. Döngü sayısını yöneten değişkenin sabit mi yoksa ifade mi olduğuna bakmazsınız; çünkü gördüğünüz her ChaCha’da bunun sabit olduğunu varsaymışsınızdır.
Bu tür sapmanın işareti şudur: sabit beklediğiniz yerde girdiye bağlı bir ifade görürsünüz. İyi yönlendirilmiş bir karşı kanıt taraması özellikle şu soruyu kontrol eder: “Standart implementasyonda burada hardcode edilmiş bir değer var; bu kodda ise hesaplanıyor mu?”
Diferansiyel testle doğrulamak için yalnızca tek byte’ı farklı iki anahtarla çalıştırın. Çıktıdaki fark, tek byte’ın beklenen etkisinden çok daha büyükse bu byte yalnızca keystream’e XOR’lanmıyor, round sayısı gibi küresel bir parametreyi de etkiliyor olabilir.
2. Sabit kaydırma: temel sabitin çok yakın bir değerle değiştirilmesi
FNV-1a hash’inin herkese açık iki sihirli sayısı vardır: offset basis ve prime. Doğru çalışan her FNV-1a implementasyonu tam olarak bu iki değeri kullanır; değerler standartta yayımlanmıştır. Ortak yazarlardan Landon Curt Noll’un yönettiği FNV referans sayfası, 32-bit offset basis değerini 2166136261, prime değerini ise 16777619 olarak basamak basamak verir.
Sapma, bu temel sabitlerden birini standarttan çok az farklı komşu bir değerle değiştirmektir. Hash’in genel yapısı aynıdır: XOR, çarpma ve döngü doğru görünür. Yalnızca başlangıçtaki temel değerde neredeyse görünmeyecek bir değişiklik yapılmıştır.
İnsanların bunu kaçırmasının nedeni, bunun dört tür arasındaki en sinsi örnek olmasıdır. FNV yapısını görür, offset basis’e benzeyen büyük bir sabit görür ve “standart FNV-1a” sonucuna varırsınız. “Zaten tanıdığınız” bir sihirli sayıyı standart değerle bit bit karşılaştırmayı kim düşünür?
Bu tür sapma neredeyse yalnızca diferansiyel testle yakalanır; büyük sayıları gözle karşılaştırmak son derece güvenilmezdir. Yöntem basit: Bilinen bir girdiyi standart implementasyonda ve hedef kara kutuda çalıştırın, sonra sonuçları karşılaştırın. Yapı aynı olmasına rağmen çıktılar farklıysa sorun büyük ihtimalle temel sabittededir. Ardından şüpheli sabiti modele verip standart değerle diff almasını isteyin; makine bu işte sizden çok daha güvenilirdir.
Modelin değeri burada son derece somuttur: Standart FNV-1a offset basis değerini son bite kadar hatırlar, siz hatırlamazsınız. Tek yapmanız gereken “bu sabit standart FNV-1a offset basis ile tamamen aynı mı?” diye sormaktır; farkı hemen gösterir.
3. Yapısal müdahale: standart algoritmadaki tek bir adımın yerel olarak değiştirilmesi
Her ChaCha double round, 8 quarter round’dan oluşur. İlk 4’ü sütunlar üzerinde, sonraki 4’ü ise çaprazlar üzerinde çalışır. Her quarter round’un hangi word’leri kullandığı standart tarafından sabit biçimde belirlenmiştir. RFC 8439 §2.3, block function’ı ve her round’un hangi state word’lerine dokunduğunu açıkça tanımlar.
Sapma şudur: round’lardan birinde bir veya iki word indeksini sessizce değiştirmek. Round’ların büyük çoğunluğu standart kalır; yalnızca ortalarda bir yerde, işlenmesi gereken word başka bir word ile değiştirilir. Kod hâlâ ChaCha’ya benzer, hata vermeden çalışır; ancak ürettiği keystream standart ChaCha’dan tamamen farklıdır.
İnsanların bunu kaçırmasının sebebi, quarter-round indekslerinin uzun sayı dizileri olmasıdır: (0,4,8,12)(1,5,9,13)… gibi sekiz grup. Gözünüz dizinin üzerinden geçer ve yalnızca “tamam, sütun round’ları ve çapraz round’lar var” diye doğrular. Zaten göz yoran indeks zincirinin içine saklanmış bir değişiklik, gizlemek için ideal yerdir.
Bu, modelin de tek bakışta yakalayacağı bir şey değildir; onu indeksleri round round listelemeye ve standart ChaCha ile diff almaya yönlendirmelisiniz. Bu mekanik bir kontrol işidir; insanın dikkati dağılırken modelin istikrarlı kaldığı türden bir görevdir. Modelden “standart indeks / gerçek indeks” tablosu üretmesini isteyin; sapma kendiliğinden görünür hâle gelir.
Diferansiyel testin doğrulaması da nettir: İlk iki türü elediyseniz — round sayısı doğru, sabitler doğru — ama çıktı hâlâ uyuşmuyorsa sorun yapısaldır. Ara state’i round round dump edin; standart ChaCha’dan ilk ayrılan round, değiştirilmiş olan round’dur.
4. Malzeme gömme: anahtar verisinin çıktının içine saklanması
İlk üç örnek algoritmayı değiştiriyordu; bu yöntem ise verinin düzenlenme biçimini değiştirir.
Yaygın tekniklerden birinde şifreleme anahtarı ayrı bir kanaldan iletilmez; bunun yerine parçalara ayrılır ve ciphertext’in içine yerleştirilir. Alıcı da aynı kuralla anahtarı yeniden çıkarır. Daha sinsi sürümde yerleştirme konumu sabit değildir, verinin içeriğinden hesaplanır. Ciphertext değiştikçe anahtarın saklandığı yer de değişir. En dış katmanda ise tüm veri özel alfabeli bir Base64 ve işaretleyici bir prefix byte ile sarılır.
İnsanların bunu kaçırmasının nedeni, şifreleme algoritmasıyla uğraşırken anahtarın kırılması gerekmediğini fark etmemeleridir. Anahtar aslında elinizdeki ciphertext’in içindedir; yalnızca hangi dilimde saklandığını bilmiyorsunuzdur. Yeni başlayanlar, plaintext’i önlerinde duran bir şeyi “kırmaya” çalışarak burada sık sık takılır.
Bu tür sapmanın işareti, veri bloğu içinde çevresinden farklı istatistiksel özellikler taşıyan bir bölgedir. Anahtar genellikle yüksek entropili rastgele byte’lardan oluşur; ciphertext’in ortasına yerleştirildiğinde fark edilebilir bir “yabancı segment” oluşturur. Model, “bu çıktının hangi aralığının byte dağılımı geri kalanından farklı?” sorusunu analiz etmenize yardımcı olarak gömülü malzemenin sınırlarını bulabilir.
Doğrulama için yerleştirme kuralını bulmanız gerekir; örneğin byte toplamı üzerinde çalışan bir modül işlemi olabilir. Birkaç bilinen girdi/çıktı çiftiyle yerleştirme konumu formülünü geriye doğru çözün, ardından ileri yönde doğrulayın. Model, az sayıda örnekten kuralı türetmenize yardımcı olabilir; fakat son sözü yine assert söyler.
Muhakeme katmanının asıl sınavı: karşı kanıt taraması
Bu dört türün ortak noktası muhtemelen dikkatinizi çekmiştir: algoritma ailesini tanımak, yani adayı belirlemek kolaydır; sapmayı, yani karşı kanıtı bulmak ise zordur.
Aday belirleme işini neredeyse her model yapabilir. ChaCha’nın σ sabitleri, FNV’nin yapısı; eğitim verilerinde bunları görmüş herhangi bir model tanıyacaktır. Modelleri asıl ayıran şey karşı kanıt taramasıdır: Model, az önce tanıdığı algoritmayı kurcalamayı sürdürebiliyor ve “ama bu kısım standartla uyuşmuyor” diyebiliyor mu?
Zayıf bir model bu noktada geri çekilir. “Bu ChaCha20” sonucuna vardıktan sonra karşı kanıt bölümü, adayı farklı kelimelerle tekrar etmeye dönüşür: “Implementasyon klasik quarter round kullanarak standart ChaCha20 yapısını izliyor…” Bu, adayın yeniden anlatımıdır; sapma kontrolü değildir. Böyle bir karşı kanıt taraması bir sonraki adımınızı yönlendiremez.
Güçlü muhakeme modelinin karşı kanıt taraması ise bambaşka görünür. Şöyle yazar: “Aday ChaCha20; ancak standart implementasyondan üç ayrım var: İlk olarak round sayısı, standart ChaCha20’de sabit 20 iken anahtara bağlı bir ifadeyle kontrol ediliyor. İkinci olarak N. round’daki word indeksleri standart çapraz round ile uyuşmuyor. Üçüncü olarak…” Her madde, doğrulanabilir ve somut bir sapma noktasına işaret eder. Böyle bir karşı kanıt taraması, 3. Aşamada yazacağınız diferansiyel test kontrol listesinin ta kendisidir.
Bu nedenle algoritma ailesi belirleme işini muhakeme katmanına vermek ve karar vermeden önce bunu kendiniz test etmek önemlidir. Modeller arasındaki karşı kanıt kalitesi farkı, kaç tane işe yaramaz test yazacağınızı ve kaç dolambaçlı yola gireceğinizi doğrudan belirler.
Bu iş akışında kullandığım dört katman şöyle:
Aşama | Gereken yetenek | Tercih | model id |
|---|---|---|---|
Split sonrası yapısal haritalama | Uzun context, tüm modülü tek seferde okuyabilme | Kimi K3 |
|
Algoritma ailesi tespiti ve karşı kanıt | Güçlü muhakeme; kendi sonucuna itiraz edebilme | Claude Opus 5 |
|
Toplu sembol yeniden adlandırma | Uygun maliyet, yüksek eşzamanlılık | Claude Sonnet 5 |
|
Farkın kaynağını belirleme | Orta seviye muhakeme, belirli byte’lara dayanarak açıklama | GPT-5.6 Sol |
|
Bu yazının kalbi ikinci katmandır. Seçimi benim sözüme bırakmayın; test edin. Protokol basit:
Kendi karartılmış bundle’ınızdan 2–3 leaf function seçin. Bunlardan en az birinin cevabını önceden biliyor olun; bu sizin kontrol örneğinizdir.
Önceki yazıdaki “aday / kanıt / karşı kanıt” üç parçalı prompt’u kullanarak aynı girdiyi ayrı ayrı
claude-opus-5vegpt-5.6-solmodellerine verin.Yalnızca karşı kanıt bölümüne bakın: Sapmaları gerçekten tek tek kontrol ediyor mu, yoksa adayı farklı ifadelerle mi tekrarlıyor? Kontrol örneğinde her model sapmaların kaçını yakaladı?
Seçim ölçütünüz, yakalanan sapmaların sayısı ve kalitesi olmalı.
Farkı tek çalıştırmada, herhangi bir benchmark liderlik tablosundan çok daha doğrudan görürsünüz.
Asıl engel: modeller arasında geçiş maliyeti
Üç farklı sağlayıcıdan dört model. Modelleri farklı aşamalarda kullanmanın naif yolu; üç SDK, üç kimlik doğrulama düzeni ve üç hata işleyici bağlamaktır. Çoğu kişi maliyeti hesaplayıp buna değmeyeceğine karar verir; sonra her iş için tek model kullanır. Algoritma ailesi tespitinde karşı kanıtı zayıf bir katmana güvenir ve nedenini bilmeden bir yığın dolambaçlı yola sapar.
AIReiter bu katmanı düzleştiriyor: Tek anahtar, OpenAI uyumlu tek arayüz ve arkasında dört model. Geçiş yapmak için istek gövdesindeki model alanını değiştirmeniz yeterli.
# Algoritma ailesi tespiti + karşı kanıt: muhakeme katmanı
curl https://aireiter.com/api/v1/chat/completions \
-H "Authorization: Bearer $AIREITER_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-opus-5",
"messages": [{"role": "user", "content": "<üç parçalı prompt + leaf function + sabitler>"}]
}'
# Toplu sembol yeniden adlandırma: tek alanı değiştirin
# "model": "claude-sonnet-5"
# Farkın kaynağını belirleme:
# "model": "gpt-5.6-sol"
Zaten OpenAI SDK kullanıyor musunuz? base_url değerini https://aireiter.com/api/v1 olarak ayarlayın, başka hiçbir şeyi değiştirmeyin. Anthropic SDK kullanıyorsanız aynı anahtarla POST /api/v1/messages çağrısını yapın.
Fiyat tarafında Claude modelleri liste fiyatına göre %30 indirimli, GPT modelleri ise yarı fiyatına sunuluyor. Bu iş akışında indirim maliyetin en yoğun olduğu noktaya denk geliyor: Algoritma ailesi adımında aynı function için prompt’u tekrar tekrar iyileştirir, birçok tur çağrı yaparsınız; akışın en yoğun istek üreten bölümü budur. Toplu sembol yeniden adlandırma da yüzlerce çağrıdan başlar. Maliyetin büyük kısmını bu iki aşama oluşturur.
Kayıt olmadan deneyin — birkaç turu elle çalıştırın, iki modelin karşı kanıt taramalarını kendi gözünüzle yan yana görün, sonra karar verin.
Sonuç
Karartılmış imzaları tersine mühendislikle çözmenin gerçeği şudur: Kodun çoğu, doğrudan kopyalayabileceğiniz standart algoritmalardan oluşur; asıl iş, standart algoritmanın sessizce değiştirildiği yerleri bulmaktır.
Dört sapma türü — sabitin değişkene dönüşmesi, sabit kaydırma, yapısal müdahale ve malzeme gömme — aynı özelliği paylaşır: İnsan örüntü tanımasının atlayacağı kadar küçük, yeniden yazımınızı baştan sona başarısız kılacak kadar büyük olmaları. İnsan, doğru görünen bir şeye karşı şüpheyi korumakta iyi değildir; iyi prompt verilmiş bir modelin gücü tam da burada yatar.
Ancak model yalnızca şüphe üretir, doğrulama yapmaz. Her sapma noktası hipotezi eninde sonunda diferansiyel teste dönüşmelidir; bunun konusu da diferansiyel test yazısıdır. Model size “değiştirilmiş olabilecek yerler” listesini verir; hangilerinin gerçekten değiştirildiğini ise assert söyler.
