Tehnički članak

Post-kvantno i EdDSA PDF potpisivanje sa HotPDF u Delphi

HotPDF verifikuje ML-DSA-44, ML-DSA-65, ML-DSA-87, Ed25519 i Ed448 CMS potpise u učitanim PDF dokumentima, i potpisuje kroz priključne provajdere tako da privatni ključ nikada ne mora živeti unutar vašeg Delphi procesa. Ta druga polovina je deo koji većini timova treba prvi. Hardverski token, udaljeni servis za potpisivanje i nacionalna eID kartica sve odbijaju da predaju ključ, i dok se tok potpisivanja ne odvoji od skladišta ključeva, nijedan od njih ne može se uopšte koristiti

To razdvajanje je poenta THPDFSignatureProvider. HotPDF zadržava delove koje treba da poseduje — parsiranje CMS-a, izgradnju SignedData, raspored /ByteRange — i delegira jednu operaciju koju ne može posedovati, a to je pretvaranje izvoda u potpis ključem koji mu nije dozvoljeno da vidi. Sve ispod proizilazi iz te podele

Zašto ispravan ML-DSA potpis ne uspeva u verifikaciji?

Zato što HotPDF odbija ML-DSA na učitanom dokumentu koji ne deklariše proširenje za njega. ML-DSA — schema rešetkastog potpisa standardizovana kao FIPS 204, i razlog zašto ljudi kažu «post-kvantni PDF» — još uvek nema ISO 32000-2 registraciju. PDF koji nosi jedan takav koristi algoritam koji osnovni standard ne imenuje, a fajl koji tiho koristi neimenovani algoritam je fajl čiji verdikt niko drugi ne može reprodukovati

Zato HotPDF čini zahtev eksplicitnim. EnsureMLDSAExtensions podiže dokument na PDF 2.0 gde je dozvoljeno i upisuje /Extensions /HotPDF << /BaseVersion /2.0 /ExtensionLevel 1 >> u Katalog. Na strani čitanja, LoadedDocumentDeclaresMLDSAExtension prijavljuje da li je ta deklaracija preživela, a VerifyLoadedSignatureWithOptions primenjuje istu proveru pre nego što će poštovati Options.AllowMLDSA. Postavite zastavicu na nedeklarisanom dokumentu i ona ostaje isključena — opcija može olabaviti politiku, ali nikada strukturni zahtev

var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := 'contract-pq.pdf';
    Pdf.BeginDoc;
    Pdf.CurrentPage.SetFont('Arial', [], 11);
    Pdf.CurrentPage.TextOut(50, 720, 0, 'Supply agreement 2026-114');
    Pdf.EnsureMLDSAExtensions;   // declare before the signature is written
    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

Pozovite ga pre snimanja, ne posle. Deklaracija je deo potpisanog opsega bajtova, a Katalog zakrpan naknadno je ili nepotpisana izmena potpisanog fajla ili druga revizija koju će validator prijaviti kao izmenu

Tri porodice algoritama, jedna ulazna tačka verifikacije

Sve tri porodice dolaze kroz VerifyLoadedSignatureWithOptions, koji uzima indeks potpisa, izvorni tok, THPDFCMSVerifyOptions zapis i izlazni parametar za detalje potpisa. Zapis ima tačno tri polja, i svako odgovara na pitanje koje je nekada zahtevalo ponovnu izgradnju

SignatureProvider zamenjuje ugrađeni platformski provajder vašim sopstvenim. OpenSSLLibraryPath bira OpenSSL 3 biblioteku, koja isporučuje verifikaciju Ed25519 i Ed448 u čistom režimu koju Windows CNG ne nudi svuda. AllowMLDSA opredeljuje se za rešetkaste algoritme, podložno gore navedenoj proveri proširenja. Tačan OID algoritma koji je prepoznat vraća se u THPDFSignatureInfo.SignatureAlgorithmOID, tako da revizijski dnevnik može zabeležiti šta je verifikovano a ne šta je zatraženo

var
  Opts: THPDFCMSVerifyOptions;
  Info: THPDFSignatureInfo;
  Status: THPDFSignatureVerifyStatus;
  Src: TFileStream;
begin
  Opts := THPDFCMSVerifyOptions.Default;
  Opts.OpenSSLLibraryPath := 'C:\openssl3\libcrypto-3-x64.dll';
  Opts.AllowMLDSA := Pdf.LoadedDocumentDeclaresMLDSAExtension;
  Src := TFileStream.Create('contract-pq.pdf', fmOpenRead or fmShareDenyWrite);
  try
    Status := Pdf.VerifyLoadedSignatureWithOptions(0, Src, Opts, Info);
    if Status = svValid then
      Memo1.Lines.Add('signed with OID ' + string(Info.SignatureAlgorithmOID));
  finally
    Src.Free;
  end;
end;

Ed25519 i Ed448 ne trebaju deklaraciju proširenja, jer ih ISO 32000-2 već prima. Treba im provajder koji ih implementira, što na većini Windows primena znači usmeravanje OpenSSLLibraryPath na biblioteku koju isporučujete i kontrolišete, a ne na onu koja se slučajno nađe na mašini

Šta provajder za potpisivanje zapravo obećava?

Provajder obećava jednu stvar: za dat zahtev, vrati status i, pri potpisivanju, bajtove. THPDFSignatureProviderRequest nosi algoritam i njegov OID, OID izvoda, dužinu PSS soli, da li je ulaz poruka ili već izračunat izvod, sam ulaz, javni ključ ili sertifikat, identifikator ključa i identifikator operacije. Ništa u tom zapisu nije specifično za HotPDF — to je rečnik koji drajver tokena ili servis za potpisivanje već govori

Tri implementacije se isporučuju uz biblioteku. THPDFCallbackSignatureProvider obavija anonimne metode, što je najkraći put od postojeće interne rutine potpisivanja do radnog PDF potpisa. THPDFRemoteSignatureProvider obavija callback transporta sa granicom ponavljanja, registrom otkazivanja i ograničenjima ulaza i veličine potpisa, tako da zaglavljen HSM ne može postati zaglavljena aplikacija. THPDFPKCS11SignatureProvider serijalizuje RSA operacije protiv sesije u vlasništvu pozivaoca, već autentifikovane, i ručice privatnog ključa — HotPDF se nikada ne prijavljuje, nikada ne vidi PIN i nikada ne zatvara sesiju koju nije otvorio

var
  Provider: THPDFRemoteSignatureProvider;
begin
  Provider := THPDFRemoteSignatureProvider.Create(
    function(const Req: THPDFSignatureProviderRequest; Attempt: Integer;
      out Signature: TBytes): THPDFSignatureProviderStatus
    begin
      // POST Req.Input to the signing service; Req.KeyIdentifier selects the key
      if PostToSigningService(Req.KeyIdentifier, Req.Input, Signature) then
        Result := spsValid
      else
        Result := spsProviderError;
    end,
    3,          // RetryLimit
    1048576,    // MaxInputBytes
    65536);     // MaxSignatureBytes
  try
    // hand Provider to the signing call
  finally
    Provider.Free;
  end;
end;

Zašto enum statusa ima šest vrednosti umesto booleana

THPDFSignatureProviderStatus razlikuje spsValid, spsInvalid, spsUnsupported, spsMalformed, spsProviderError i spsCancelled, a njihovo sažimanje vas košta sposobnosti da delujete ispravno. Potpis koji je kriptografski pogrešan (spsInvalid) jeste bezbednosni događaj. Algoritam koji provajder ne implementira (spsUnsupported) jeste jaz u primeni. Neuspeh transporta (spsProviderError) vredi ponoviti, a korisnički otkazan prompt tokena (spsCancelled) ne vredi ponavljati uopšte

Pravilo za potpisivanje je usko: provajder potpisivanja vraća spsValid samo sa nepraznim potpisom. Provajderi verifikacije vraćaju spsValid ili spsInvalid, a ostale četiri ostaju različite na obe putanje. Ako pišete provajder, oduprite se iskušenju da sve što ne prepoznajete mapirate na spsInvalid — to pretvara nedostajući DLL u izveštaj da je potpis klijenta falsifikovan

Gde potpis zapravo sliše u fajl

Dve funkcije povezuju provajdere sa stvarnim PDF bajtovima. HPDFCMSBuildSignedDataWithProvider gradi odvojeni CMS iz izvoda dokumenta SHA-256, što je prava ulazna tačka kad vaš tok izračunava izvod drugde. HPDFCMSSignPDFStreamWithProvider potpisuje postojeće mesto za potpis u PDF toku i čuva standardni /ByteRange tok, što je prava ulazna tačka kad je HotPDF sam rasporedio mesto za potpis

Očuvanje tog toka je važnije nego što zvuči. Konvencija /ByteRange — dva opsega koja preskaču heks prozor potpisa — jeste ono što svaki validator proverava prvo, a putanja zasnovana na provajderu koja bi je prepisala bi prekinula PAdES usklađenost bez obzira na to koliko bila zdrava kriptografija. HotPDF čuva raspored identičnim ugrađenoj putanji potpisivanja, tako da dokument potpisan kroz PKCS#11 token verifikuje istim kodom za verifikaciju potpisa kao i onaj potpisan iz PFX fajla. Za pravila profila koja sede iznad izbora algoritma, pogledajte prolaz kroz PAdES osnovne potpise u Delphi, a za ECDSA-specifične zamke kodiranja koje prethode ovom modelu provajdera, beleške o ECDSA CMS verifikaciji i P1363 formatima potpisa

Redosled migracije koji ne ostavlja vaše dokumente na cedulju

Post-kvantna spremnost je problem rasporeda, a ne prekidač. Gotovo nijedan primenjeni PDF pregledač danas ne validira ML-DSA, tako da je dokument potpisan samo sa njim, iz ugla čitača, dokument sa potpisom koji se ne može verifikovati. Redosled koji preživljava susret sa stvarnim arhivama je: zadržite RSA ili ECDSA kao potpis koji će validator oceniti, dodajte deklaraciju proširenja i drugi ML-DSA potpis tamo gde politika zahteva dokaz otporan na kvant, i pomerite primarni potpis tek kad potrošački sistemi dostignu taj nivo

Ono što vam HotPDF danas daje jeste sposobnost da pišete i verifikujete oba, iz istog koda, sa algoritmom iskreno zabeleženim u fajlu i u rezultatu verifikacije. HotPDF je nativna VCL PDF komponenta za Delphi i C++Builder bez eksternog PDF izvršnog okruženja, tako da se putanje potpisivanja i verifikacije isporučuju unutar vašeg izvršnog fajla a ne pored njega — pogledajte stranicu HotPDF Delphi PDF komponente za kompletnu listu funkcija i probnu verziju