Teknik Makale

Delphi'de SHAKE256 XOF: Keccak Alan Ayrımı

PDFlibPas, SHA-3 ve SHAKE256'yı Object Pascal'da tek bir Keccak-f[1600] permütasyonu üzerinde uygular. İki aile tam olarak iki yerde farklılaşır: FIPS 202 §6.2 ve §6.3'e göre SHA-3 için $06, SHAKE için $1F olan pad10*1 alan baytı ve rate kuralı. SHAKE256, çıktı uzunluğundan bağımsız olarak rate'ini 136 baytta sabitler

İkinci fark, insanların yanlış yaptığı farktır, çünkü hiç fark gibi görünmez. SHA3-256 da 136 rate ile çalışır; bu yüzden SHA-3 kod yolunu kopyalayarak kurulmuş bir SHAKE256, üzerine attığınız her 32 baytlık testi geçer ve birisi ilk kez 64 istediğinde çöp üretir. Aşağısı, iki ailenin PDFlibDigest içinde nasıl tek bir bağlam kaydını paylaştığı, tek atışlık giriş noktasının nerede durduğu ve akış tabanlı XOF'un Ed448 veya ML-DSA'dan önce neden var olmak zorunda olduğudur

SHA-3 ve SHAKE256 neden tek bir Keccak bağlamını paylaşır?

Çünkü aile başına tek durum tek bir bayttır ve PDFlibPas onu TSHA3Context içinde Suffix olarak saklar. Alan ayırıcı sonlandırma rutinine sabit kodlanmak yerine bağlamda yaşadığında, SHA3AbsorbBlock, SHA3Update ve SHA3Final iki aileye de değişmeden hizmet eder ve kütüphanede 24 turlu permütasyonun tam olarak bir kopyası vardır. İki yolun ayrıldığı yer başlatıcılardır ve tamamen ayrılırlar

PDFlibPas'te iki aileye hizmet eden tek Keccak bağlamı: TSHA3Context alan ayırıcıyı tek bir Suffix baytında saklar, SHA3Init soneki $06'ya ayarlar ve Rate'i 200 eksi iki kez çıktı uzunluğu olarak türetir, SHAKE256Init ise rate 136 baytta sabitlenmiş $1F ayarlar; böylece SHA3AbsorbBlock, SHA3Update ve SHA3Final ikisine de değişmeden hizmet eder
Aile başına tek durum bir bayt olduğu için her iki özet ailesi de 24 turlu permütasyonun tek bir kopyasını paylaşır ve yolların ayrıldığı tek yer iki başlatıcıdır
Type
  TSHA3Context= Record
    State: Array [0.. 24] Of UInt64;
    Buffer: Array [0.. 135] Of Byte;
    BufferLength: Integer;
    Rate: Integer;
    OutputLength: Integer;
    // Alan ayırıcı: SHA3 için $06, SHAKE için $1F (FIPS 202 §6.2/6.3)
    Suffix: Byte;
  End;

Procedure SHA3Init(Var Context: TSHA3Context; OutputBits: Integer);
Begin
  FillChar(Context, SizeOf(Context), 0);
  Context.OutputLength:= OutputBits div 8;
  Context.Rate:= 200- 2* Context.OutputLength;   // rate, özet boyutunu izler
  Context.Suffix:= $06;
End;

// SHAKE256: çağıran ne isterse istesin rate 136 baytta sabittir,
// çünkü SHAKE genişletilebilir çıktılı bir fonksiyondur
Procedure SHAKE256Init(Var Context: TSHA3Context; OutputBytes: Integer);
Begin
  FillChar(Context, SizeOf(Context), 0);
  Context.OutputLength:= OutputBytes;
  Context.Rate:= 136;
  Context.Suffix:= $1F;
End;

SHA3Init'teki formül SHA3-256, SHA3-384 ve SHA3-512 için 136, 104 ve 72 bayt rate verir; yani sabit uzunluklu aile için rate ve güvenlik seviyesi birbirine kaynaklanmıştır. SHAKE256Init bu bağı bilerek kırar: OutputLength bir güvenlik gücü bildirimi değil bir bayt talebi olur ve ne kadar çıktı çekerseniz çekin sünger kapasitesi 512 bitte kalır. Bu ayrışma genişletilebilir çıktılı bir fonksiyonun tanımının ta kendisidir ve bunu tek bir bağlam üzerinde iki başlatıcı olarak yazmak, ayrımı kaynakta bir yorumun içine gömülü değil görünür kılar

Tek atışlık giriş noktasındaki 136 bayt tavanı

PDFlibPas'taki kolaylık fonksiyonları 1..136 bayt dışındaki her şeyi reddeder ve bu sınır keyfi değil dürüsttür. SHAKE256StreamRange ve SHAKE256ByteArray ikisi de son bloğu dolduran, bir kez permüte eden ve çıktıyı doğrudan durumdan okuyan SHA3Final üzerinden geçer. O durumun yalnızca ilk Rate baytı yasal çıktıdır; bu yüzden tek bir sıkma en fazla 136 bayt verir ve ötesi için blok başına taze bir permütasyon gerekir. Gerçek iki tüketici de zaten pencerenin içine sığar: PDF imza profili 32 bayt özetler ve Ed448, RFC 8032 §5.2'ye göre 114 gerektirir. SHAKE256StreamRange, SHA256StreamRange ve SHA3_256StreamRange ile aynı FirstLength, SecondStart, SecondLength üçlüsünü alır; böylece doğrulama kodu bir imza /ByteRange'ini her algoritma için aynı şekilde yürür ve XOF'u asla özel duruma almaz

Konum rate-1'e düştüğünde pad10*1'de ne ters gider?

Hiçbir şey, iki dolgu baytını da atamak yerine duruma XOR'larsanız. FIPS 202 §B.2, alan sonekini geçerli emme konumuna ve $80'i bloğun son baytına koyar. Mesaj konumu Rate- 1'de bırakırsa, bu iki yazma aynı baytı hedefler ve $9F'de birleşmek zorundadır. XOR yerine saklayın ve biri kazanır; dolgu 136'da tam olarak bir mesaj uzunluğu için sessizce yanlış olur ve sahip olduğunuz her regresyon vektörü geçer, çünkü hiçbiri oraya düşmez. PDFlibPas'taki PLShakeXOFFinalize ikisini de XOR'lar; bu da çakışan durumu dallanma olmadan genel durumdan çıkarır

PDFlibPas'te pad10*1 çakışma durumu: PLShakeXOFFinalize alan sonekini geçerli emme konumuna ve $80'i bloğun son baytına koyar; konum Rate eksi 1'e düştüğünde iki yazma tek bir baytı hedefler, XOR onları $9F'de birleştirir ve düz bir saklama 136'daki bir mesaj uzunluğunu bozardı
XOR yerine saklamak bir dolgu baytının kazanmasına izin verir ve kusur 136'daki tam olarak bir mesaj uzunluğu için belirdiğinden, dolgu sessizce yanlışken sahip olduğunuz her regresyon vektörü geçebilir
// Son kısmi bloğu doldurur ve sıkma aşamasına girer
Procedure PLShakeXOFFinalize(Var Ctx: TPLShakeXOF);
Begin
  If Not Ctx.Absorbing Then
    Exit;
  Ctx.Absorbing:= False;
  // sonek SqueezePos'ta, $80 Rate-1'de; SqueezePos = Rate-1 olduğunda iki
  // XOR aynı bayta düşer ve doğru şekilde $9F'de birleşir
  Ctx.State[Ctx.SqueezePos div 8]:= Ctx.State[Ctx.SqueezePos div 8]xor
    (UInt64(Ctx.Suffix)shl (8* (Ctx.SqueezePos and 7)));
  Ctx.State[(Ctx.Rate- 1)div 8]:= Ctx.State[(Ctx.Rate- 1)div 8]xor
    (UInt64($80)shl (8* ((Ctx.Rate- 1)and 7)));
  SHA3Permute(Ctx.State);
  Ctx.SqueezePos:= 0;
End;

TPLShakeXOF: doğrudan süngerin içine emme

PDFlibPas sınırsız çıktıyı ayrı bir kayıt olan TPLShakeXOF üzerinden sunar; bu kayıt yalnızca 25 UInt64 sözcük olarak State, Rate, Suffix, bir Absorbing bayrağı ve SqueezePos tutar. Mesaj arabelleği yoktur: PLShakeXOFAbsorb gelen baytları doğrudan duruma XOR'lar ve bir bloğu doldurduğunda permüte eder; SqueezePos her iki aşamada da ofset görevi görür. PLShakeXOFInit varyantı tek bir boolean ile seçer: 168 rate için SHAKE128'de True, 136 rate için SHAKE256'da False. PLShakeXOFSqueeze ise çağıran istediği bayt sayısını alana kadar permüte etmeye devam eder. Blok ötesi çıktı 200 baytta kontrol edildi; bu, iki varyantta da ilk blok sınırının ötesidir

PDFlibPas'te TPLShakeXOF üzerinden akış tabanlı SHAKE: State, Rate, Suffix, bir Absorbing bayrağı ve SqueezePos tutan ama mesaj arabelleği olmayan bir kayıt; PLShakeXOFInit 168 rate ile SHAKE128 veya 136 rate ile SHAKE256 seçer, PLShakeXOFAbsorb baytları doğrudan süngere XOR'lar, PLShakeXOFFinalize doldurup permüte eder ve PLShakeXOFSqueeze çağıran her baytı alana kadar permüte etmeye devam eder
Önce birleştirmeden birkaç çağrıda emmek, Ed448'in 114 baytını çekmesini ve ML-DSA portunun süresiz sıkmasını sağlayan şeydir; 136 bayt tavanlı tek atış giriş noktasının destekleyemeyeceği bir kapsam
Var
  Ctx: TPLShakeXOF;
  Digest: Array [0.. 113] Of Byte;   // Ed448 114 bayt ister, RFC 8032 §5.2
Begin
  PLShakeXOFInit(Ctx, False);        // False = SHAKE256, rate 136
  PLShakeXOFAbsorb(Ctx, @Dom4[1], Length(Dom4));
  PLShakeXOFAbsorb(Ctx, @Prefix[1], Length(Prefix));
  PLShakeXOFAbsorb(Ctx, @Msg[1], Length(Msg));
  PLShakeXOFFinalize(Ctx);
  PLShakeXOFSqueeze(Ctx, @Digest[0], SizeOf(Digest));
End;

// Ya da tek bir giriş arabelleği ve tek bir çıkış arabelleği yeterliyse:
//   PLShakeXOF(False, Input, Output, 114)

Birkaç çağrıda emmek göründüğünden daha önemlidir. Ed448, özetlemeden önce mesajı bir dom4 dizesi ve 57 baytlık bir değerle önekler ve bir reddetme örnekleyicisi, önce dizeleri birleştirmeden bir tohum ve dizin baytları beslemek ister. Akış kaydının iki tüketiciden önce yerleşmesi meselenin ta kendisiydi: saf Pascal Ed448 ve Brainpool eğri işi tek atışta 114 bayt ister ve FIPS 204 ML-DSA portu iki varyanttan da süresiz sıkar. İkisi de tek atışlık API'ye karşı yazılamazdı

PDFlibPas, SHAKE256'yı bir özet seçici olarak açığa çıkarmayı neden reddeder?

Çünkü onu seçmenin yasal bir yolu yoktur. PDFlibDigitalSign içindeki TPDFlibDigestAlgorithm, daAuto, daSHA1, daSHA256, daSHA384, daSHA512, daSHA3_256, daSHA3_384, daSHA3_512 çalıştırır ve durur. daSHAKE256 diye bir şey yoktur ve bu eksiklik bir karardır, bir gözden kaçırma değil. RFC 8702, SHAKE'i CMS'de kayıtlı yapar, ama bir PDF imzasının içinde ISO/TS 32002'nin SHAKE256'yı koyduğu tek yer, imza algoritmasının onu seçtiği ve çağıranın seçmediği Ed448'in dahili özetidir. Onu bağımsız bir DigestAlgorithm değeri olarak yayınlamak, herkesin SHAKE256'yı RSA veya ECDSA ile eşleştirip hiçbir doğrulayıcının kabul etmeyeceği bir imza sözlüğü üretmesine izin verirdi. Yetenek gelir, seçici gelmez ve doğrulama tarafı kodu /ByteRange düzeni üzerinde doğrudan SHAKE256StreamRange çağırır. Karşı tarafın bugün doğrulaması gereken bir imza için özet seçiyorsanız, zaman damgalı ve uzun vadeli doğrulama verili PAdES B-B'den B-LTA iş akışı içindeki daSHA256'dan daSHA3_512'ye kadar olan değerler yanıt olmaya devam eder; SHA-3'ün PDF'de rutin hâle gelip gelmeyeceğini ISO/TS 32001 yönetir

Bir XOF'u test etmek: geçmiş gibi görünen vektör

Çıktının tam uzunluğunu karşılaştırın ve birden fazla vektör kullanın. Boş dize SHAKE256 sonucu herkesin ezberlediği sonuçtur ve tam da bu kadar yaygın alıntılandığı için zayıf bir testtir. abc için 32 baytlık SHAKE256 çıktısı daha kötüdür: ilk 16 baytı, 483366601360a8771c6863080cc4114d, birkaç komşu vektörle çakışır; bu yüzden kesilmiş bir karşılaştırma başarı rapor ederken ayırt edici yarısı 8db44530f8f1e1ee4f94ea37e78b5739 kontrolsüz kalır. PDFlibPas regresyonu iki vektörü de tam uzunlukları üzerinde karşılaştırır. Ayrıca bir blok ötesi durum ekleyin, çünkü bir rate sınırını asla geçmeyen bir sıkma döngüsü hiç test edilmemiştir

SHAKE'i mevcut bir SHA-3 uygulamasına katlamaktan çıkan daha geniş ders, paylaşılan kodun asla risk olmadığıdır. Keccak-f[1600] iki aile için de aynı permütasyondur ve ya vektörlerle eşleşir ya eşleşmez. Risk, farklılaşan iki baytta ve bir tamsayıda ve dürüstçe belirtmeniz gereken ama çağıranların keşfetmesine bırakmamanız gereken tavanda yaşar. Özet katmanının, yerel bir Object Pascal kod tabanında imzalama, şifreleme ve PDF/A araçlarının yanına nasıl oturduğunu görmek için PDFlibPas Delphi PDF kütüphanesi ürün sayfası eksiksiz bileşen setini ve desteklenen derleyici matrisini listeler