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
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
// 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
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