Tehnički članak

Postkvantno i EdDSA PDF potpisivanje s HotPDF-om u Delphiju

HotPDF provjerava ML-DSA-44, ML-DSA-65, ML-DSA-87, Ed25519 i Ed448 CMS potpise u učitanim PDF dokumentima i potpisuje kroz priključive providere, pa privatni ključ nikad ne mora živjeti unutar vašeg Delphi procesa. Ovo drugo je dio koji većini timova treba prvi. Hardverski token, udaljeni servis za potpisivanje i nacionalna eID kartica svi odbijaju predati ključ, i dok cjevovod za potpisivanje nije odvojen od spremišta ključeva, nijedan od njih ne može se uopće koristiti

Ta je podjela smisao THPDFSignatureProvider. HotPDF zadržava dijelove koje bi trebao posjedovati: raščlanjivanje CMS-a, izgradnju SignedData, raspored /ByteRange, a delegira jednu operaciju koju ne može posjedovati, a to je pretvaranje sažetka u potpis ključem koji mu nije dopušteno vidjeti. Sve u nastavku slijedi iz te podjele

Zašto valjan ML-DSA potpis ne uspijeva u provjeri?

Zato što HotPDF odbija ML-DSA na učitanom dokumentu koji ne deklarira proširenje za njega. ML-DSA, shema rešetkastog potpisa normirana kao FIPS 204 i razlog što ljudi kažu postkvantni PDF, još nema registraciju u ISO 32000-2. PDF koji ga nosi koristi algoritam koji osnovni standard ne imenuje, a datoteka koja šutke koristi neimenovani algoritam jest datoteka čiju presudu nitko drugi ne može reproducirati

Stoga HotPDF čini zahtjev izričitim. EnsureMLDSAExtensions diže dokument na PDF 2.0 kad je dopušteno i zapisuje /Extensions /HotPDF << /BaseVersion /2.0 /ExtensionLevel 1 >> u katalog. Na strani čitanja, LoadedDocumentDeclaresMLDSAExtension prijavljuje je li ta deklaracija preživjela, a VerifyLoadedSignatureWithOptions primjenjuje isti test prije nego što poštuje Options.AllowMLDSA. Postavite oznaku na nedeklarirani dokument i ona ostaje isključena: opcija može olabaviti politiku, ali nikada strukturni zahtjev

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 to prije spremanja, a ne poslije. Deklaracija je dio potpisanog raspona bajtova, a katalog zakrpan naknadno ili je nepotpisana promjena potpisane datoteke ili je druga revizija koju će validator prijaviti kao izmjenu

Tri obitelji algoritama, jedna ulazna točka provjere

Sve tri obitelji dolaze kroz VerifyLoadedSignatureWithOptions, koji uzima indeks potpisa, izvorni stream, zapis THPDFCMSVerifyOptions i izlazni parametar za detalje potpisa. Zapis ima točno tri polja, i svako odgovara na pitanje koje je nekad zahtijevalo ponovnu izgradnju

SignatureProvider zamjenjuje ugrađeni platformski provider vašim vlastitim. OpenSSLLibraryPath bira biblioteku OpenSSL 3, koja opskrbljuje Ed25519 i Ed448 provjeru u čistom načinu koju Windows CNG ne nudi posvuda. AllowMLDSA pristupa rešetkastim algoritmima, podložno gornjoj provjeri proširenja. Točan OID algoritma koji je prepoznat vraća se u THPDFSignatureInfo.SignatureAlgorithmOID, pa dnevnik revizije može zabilježiti što je provjereno, a ne što 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. Trebaju providera koji ih implementira, što na većini Windows instalacija znači usmjeravanje OpenSSLLibraryPath na biblioteku koju isporučujete i kontrolirate, a ne na onu koja se slučajno nađe na stroju

Što provider za potpisivanje doista obećava?

Provider obećava jednu stvar: s obzirom na zahtjev, vrati status i, kod potpisivanja, bajtove. THPDFSignatureProviderRequest nosi algoritam i njegov OID, OID sažetka, duljinu PSS soli, je li ulaz poruka ili već izračunati sažetak, sam ulaz, javni ključ ili certifikat, identifikator ključa i identifikator operacije. Ništa u tom zapisu nije specifično za HotPDF: to je rječnik kojim upravljački program tokena ili servis za potpisivanje već govori

Tri implementacije stižu s knjižnicom. THPDFCallbackSignatureProvider omata anonimne metode, što je najkraći put od postojeće interne rutine potpisivanja do funkcionalnog PDF potpisa. THPDFRemoteSignatureProvider omata povratni poziv transporta s granicom ponavljanja, registrom otkazivanja i ograničenjima ulaza i veličine potpisa, tako da HSM koji se objesio ne može postati objesila aplikacija. THPDFPKCS11SignatureProvider serijalizira RSA operacije naspram pozivateljeve, već autentificirane PKCS#11 sesije i ručice privatnog ključa. HotPDF se nikad ne prijavljuje, nikad ne vidi PIN i nikad 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 vrijednosti umjesto bulean vrijednosti

THPDFSignatureProviderStatus razlikuje spsValid, spsInvalid, spsUnsupported, spsMalformed, spsProviderError i spsCancelled, a njihovo sažimanje košta vas sposobnosti ispravnog djelovanja. Potpis koji je kriptografski pogrešan (spsInvalid) sigurnosni je događaj. Algoritam koji provider ne implementira (spsUnsupported) praznina je u instalaciji. Kvar transporta (spsProviderError) vrijedi ponoviti, a otkazani upit tokena od strane korisnika (spsCancelled) uopće ne vrijedi ponavljati

Pravilo za potpisivanje je usko: provider za potpisivanje vraća spsValid samo s nepraznim potpisom. Provideri provjere vraćaju spsValid ili spsInvalid, a ostale četiri vrijednosti ostaju različite na oba puta. Ako pišete providera, odolite iskušenju da sve što ne prepoznajete preslikate na spsInvalid, jer to pretvara nedostajući DLL u prijavu da je potpis kupca krivotvoren

Gdje potpis doista slijeće u datoteku

Dvije funkcije povezuju providere sa stvarnim PDF bajtovima. HPDFCMSBuildSignedDataWithProvider izgrađuje odvojeni CMS iz sažetka SHA-256 dokumenta, što je prava ulazna točka kad vaš cjevovod računa sažetak drugdje. HPDFCMSSignPDFStreamWithProvider potpisuje postojeće mjesto za potpis u PDF streamu i čuva standardni /ByteRange cjevovod, što je prava ulazna točka kad je HotPDF sam rasporedio mjesto

Očuvanje tog cjevovoda važnije je nego što zvuči. Konvencija /ByteRange, dva raspona koji preskaču heksadecimalni prozor potpisa, ono je što svaki validator provjerava prvo, a put temeljen na provideru koji bi ga prepisao prekinuo bi PAdES sukladnost bez obzira na to koliko bila zdrava kriptografija. HotPDF drži raspored identičnim ugrađenom putu potpisivanja, pa dokument potpisan kroz PKCS#11 token prolazi provjeru istim kodom za provjeru potpisa kao onaj potpisan iz PFX datoteke. Za profilna pravila koja sjede iznad izbora algoritma pogledajte prikaz PAdES osnovnih potpisa u Delphiju, a za ECDSA-specifične zamke kodiranja koje prethode ovom modelu providera bilješke o ECDSA CMS provjeri i P1363 formatima potpisa

Redoslijed migracije koji ne ostavlja vaše dokumente u zagrebu

Postkvantna spremnost problem je rasporeda, a ne prekidač. Gotovo nijedan danas raspoređeni PDF preglednik ne provjerava ML-DSA, pa je dokument potpisan samo njime, iz perspektive čitatelja, dokument s potpisom koji se ne može provjeriti. Redoslijed koji preživljava kontakt sa stvarnim arhivima jest: zadržite RSA ili ECDSA kao potpis kojeg će validator suditi, dodajte deklaraciju proširenja i drugi ML-DSA potpis gdje politika zahtijeva kvantno-otporni dokaz, a primarni potpis premjestite tek kad potrošački sustavi dostignu

Ono što vam HotPDF danas daje jest sposobnost pisanja i provjere obaju, iz istog koda, s algoritmom iskreno zabilježenim u datoteci i u rezultatu provjere. HotPDF je izvorna VCL PDF komponenta za Delphi i C++Builder bez vanjskog PDF izvršnog okruženja, pa putovi potpisivanja i provjere stižu unutar vaše izvršne datoteke, a ne uz nju. Pogledajte stranicu HotPDF Delphi PDF komponente za cijeli popis značajki i probno preuzimanje