HotPDF, PDF için eliptik eğri anahtar anlaşmasını ve imza doğrulamasını saf Object Pascal ile gerçekleştirir; yol üzerinde ne OpenSSL bağlantısı ne de platform kripto sağlayıcısı vardır. Bu beş eğriyi kapsar: NIST asal aileleri için P-256, P-384 ve P-521, ayrıca Montgomery eğrisi anahtar anlaşması için X25519 ve X448. O kodu bağlamak yerine yazmanın nedeni dağıtımdır, saflık değil. Tek bir çalıştırılabilir dosya ve hiçbir kriptografik DLL gönderen bir Delphi ya da Free Pascal uygulamasının yönetecek sürüm kayması, algılanacak platform başına sağlayıcısı ve müşterisi sistem kitaplıklarını yamaladığında değişecek davranışı yoktur
Bedeli, aritmetiğin artık size ait olmasıdır. Büyük tamsayılı modüler çarpma affetmez bir koddur: yayınlanmış test vektörlerine karşı ya bayta özdeş sonuçlar üretir ya da inandırıcı görünen çöp üretir ve bu iki durum arasındaki mesafe tek bir karşılaştırma olabilir. Bu, o karşılaştırmanın öyküsüdür; çünkü hatanın biçimi, cisim aritmetiğinin herhangi bir Pascal portuna geneller
Bir PDF kitaplığının eğri aritmetiğine hiç ihtiyacı olur mu?
İki özellik onu içeri çeker. İlki belgelerin açık anahtarlı şifrelemesidir: ISO 32000 alıcı listesi işleyicisi, adlandırılmış sertifikalar için belge başına bir anahtarı sarmalar ve alıcı bir EC anahtarı taşıdığında sarmalama, RSA anahtar taşıması yerine anahtar anlaşması üzerinden yürür. ECDH olmadan böyle bir belgeyi açmanın yolu yoktur. İkincisi imza doğrulamasıdır. /ByteRange baytları üzerindeki bir ECDSA imzasını doğrulamak, imzalayan eğrisinde bir nokta çarpımı gerektirir ve P-384, P-256'nın hedef değil taban sayıldığı kamu ve nitelikli imza profillerinde yaygındır. HotPDF o çalışmanın sonuçlarını ECDSA ve CMS doğrulama yoluyla ve takılabilir imza sağlayıcı modeliyle açar
CIOS ve sondaki tek çıkarma
Montgomery çarpımı, indirgemenin bir kaydırma olduğu dönüştürülmüş bir alanda çalışarak bölmeyi önler. HotPDF'in kullandığı varyant, Coarsely Integrated Operand Scanning'dir; çarpma ile indirgemeyi limb limb iç içe geçirir, böylece ara değer asla modül genişliği artı bir limbi aşarak büyümez. Döngü gövdesi düpedüz ve test etmesi kolaydır. Kuyruk öyle değildir: iç içe geçmiş geçişlerden sonra akümülatör, modülün iki katına kadar olan aralıkta herhangi bir yerde olabilir; dolayısıyla algoritma, akümülatör asala ancak ve ancak eşit ya da büyükse asalın bir kopyasını kaldıran koşullu bir çıkarma ile biter
İki çok limbli sayıyı karşılaştırmak, borç taşıyarak en anlamlı limbten aşağıya yürümek demektir. Yazmanın bariz yolu, akümülatör limbini modül limbine gelen borcu ekleyerek karşılaştırmaktır. O ifade yanlıştır ve çoğu eğrinin sakladığı bir şekilde yanlıştır
// Yanlış: P[I] $FFFFFFFFFFFFFFFF olduğunda P[I] + Borrow taşabilir
if T[I] < P[I] + Borrow then
begin
Borrow := 1;
Break;
end;
// Doğru: hiçbir limbe ekleme yapmadan karşılaştır
if (T[I] < P[I]) or ((T[I] = P[I]) and (Borrow = 1)) then
begin
Borrow := 1;
Break;
end;
Bir borç taşması gerçekte neye benzer?
Üretim dışında her yerde çalışan bir eğri gibi görünür. P-384 ile P-521'in asalları tamamen birlerden oluşan limbler içerir; dolayısıyla P[I], $FFFFFFFFFFFFFFFF'e eşittir. Buna gelen bir borcunu ekleyin ve 64 bitlik işaretsiz bir değer sıfıra taşar. Karşılaştırma sonra akümülatör limbinin sıfırdan küçük olup olmadığını sorar, küçük olmadığına karar verir ve borç gerekmediği sonucuna varır. Sonucun bir limb'i bir kadar yanlıştır
P-256 kaçar, çünkü limblerinin hiçbiri tamamen birlerden oluşmaz; dolayısıyla toplama hiç taşmaz ve hatalı ifade tesadüfen doğrusuyla örtüşür. Bir test takımı için en kötü olası sonuç budur: en çok test edilen eğri geçer, daha az test edilenler işlenen değerlerine bağlı olarak aralıklı başarısız olur ve hata, tamamen geçerli belgelerde "geçersiz imza" doğrulama sonucu olarak yüzeye çıkar. HotPDF, tam da bu nedenle P-384 üzerinde açık bir kapı taşıyordu; aritmetik referans vektörlerine karşı kanıtlanana dek yanlış bir cevap yerine kullanılamaz durumu döndürüyordu
Hata gerçekte nasıl bulundu
Kodu okuyarak değil. Verimli dizi mekanikti ve yeniden kullanılabilir. Birincisi, sabitleri eliyin: p, R ve R^2'nin her limbi bağımsız yeniden üretildi ve limb limb karşılaştırıldı; bu, eğri hatalarının en yaygın tek kaynağını elemeye yeter. İkincisi, API'yi değil aritmetiği ölçümleyin: geçici bir döküm yordamı, bilinen bir nokta için R^2'nin, x^3'ün ve y^2'nin Montgomery çarpımının ara değerlerini yazdı; böylece bağımsız hesaplanmış gerçekle denetlenebildiler
O karşılaştırma doğrudan suçluyu işaret etti. x zinciri baştan sona doğrudu; oysa y^2, tam olarak tek limpte tam olarak bir farklıydı. Tek limbli birlik bir fark ne bir çarpma hatası ne bir elde yayılımı hatası ne de bir sabit hatasıdır; borç zinciri hatasıdır ve yordamdaki tek borç zinciri sondaki koşullu çıkarmadır. Bir ayrıntı bunu neredeyse rayından çıkardı: döküm için kullanılan referans sabitinin kendisi ilk denemede yanlış bayt sırasıyla yazılmıştı; bu, y değerinde bir uyuşmazlık üretti ve kısa süre için var olmayan ikinci bir kusur iması verdi. Kodunuzu suçlaması için ona güvenmeden önce zemin gerçekinizin bayt sırasını doğrulayın
Aynı yordamdaki komşu tuzaklar
O karşılaştırmanın birkaç satır ötesinde üç hata modu daha yaşar ve üçü de geliştirme boyunca bir noktada canlıydı
// 1. Akümülatörün modül genişliğinin bir üstünde bir limb değeri vardır.
// Yalnızca alt L limb değerini karşılaştırmak, T'nin tam olarak
// p artı 2^(64*L)'ye eşit olduğu durumu kaçırır; 2p, P-256 için
// 2^256'yı ve P-384 için 2^384'ü aştığından bu, rastgele girdilerin
// anlamlı bir payı için olur
if (T[L] <> 0) or NotLessThanModulus(T, P, L) then
SubtractModulus(T, P, L);
// 2. Genel amaçlı çok limbli bir çıkarma aynı taşma riskini taşır: Y[I]
// $FFFFFFFFFFFFFFFF olduğunda Y[I] + Borrow sıfıra taşar ve borç,
// temizlenmek yerine sonraki limbe aktarılmalıdır
Diff := X[I] - Y[I] - Borrow;
NextBorrow := Ord((X[I] < Y[I]) or ((X[I] = Y[I]) and (Borrow = 1)));
Üçüncüsü kod değil, kaynaklıktır. P-521'in asalı başlangıçta 131 yerine 130 onaltılık basamakla, bir F eksiğiyle aktarıldı ve Montgomery sabitleri sonra o yanlış asaldan hesaplandı; böylece sabitler kendi içinde tutarlı ve birlikte yanlıştı. Eğri parametreleri türetilmelidir, asla yazılmamalıdır: R'yi, gerçekten kullandığınız asaldan (1 shl (64 * L)) mod p olarak hesaplayın, sonra R * R mod p değerini R^2 sabitinizin iddia ettiği değerle çapraz denetleyin. Birbirine uyan bir sabit çifti, ikisi hakkında da hiçbir şey kanıtlamaz
Tek bir eğrinin ötesine ölçeklenen doğrulama stratejisi
X25519 ile X448'i yönetilebilir kılan teknik, sınırsız tamsayılı bir dilde bir ayna uygulaması yazmak ve Pascal denetim akışını satır satır ona aktarmaktı. Ayna doğru cevabı üretirken Pascal üretmediğinde kusur bir aktarım hatasıdır ve her iki uygulamada da aynı ara değeri yoklamak onu saniyeler içinde bulur. Üç klasik RFC 7748 merdiven hatasının üçü de böyle yakalandı: ikinci satırı çoktan değişmiş değeri yeniden kullanan sabit zamanlı bir takas, z'yi X'e çarpmak yerine eksi birinci kuvvetine döndüren sondaki ters alma ve yarım sözcük çarpımlarını bitsel or ile birleştirip eldeyi kaybeden küçük sabitli bir çarpma
Test malzemesi için vektörleri metin olarak değil bayt olarak alın. Özel bir anahtarı bir metin deseniyle çıkarmak, doğru bir uygulamanın tamamen çıkarma adımında yaşayan bir bayt kayması hatasıyla suçlanmasına yol açar. Onaltılıkları DER kodlamasından bilinen ofsetlerde dilimleyin ve bayt dizilerini karşılaştırın
Borç zinciri düzeltildikten sonra beş eğrinin tamamı yayınlanmış referans vektörleriyle bayt bayt örtüşüyor ve HotPDF artık hiçbirini kapı ile sınırlamıyor. Sertifika tabanlı imzalama ya da alıcı listesi şifrelemesi entegre ediyorsanız pratik çıkarım şudur: eğri seçimi artık bir yetenek sorusu değil politika kararıdır; imzalama tarafının profilleri ve bayt sırası tuzakları PAdES imzalama kılavuzunda kapsanır. Bileşen ayrıntıları ve desteklenen algoritma matrisi HotPDF Delphi PDF component ürün sayfasındadır