Technisch artikel

HotPDF: digital signatures and PAdES-ready signing in Delphi

Deze gelokaliseerde versie behandelt PDF Digital Signatures and PAdES in Delphi with HotPDF en gebruikt het bijgewerkte Engelse basisartikel als technische referentie voor teams rond Delphi, PDF en documentsoftware

De pagina zet de bijgewerkte basis om in concrete controlepunten voor ontwerp, implementatie en validatie

Wat uit de Engelse basis is gesynchroniseerd

Het basisartikel is uitgebreid met praktische context, technische keuzes en concrete voorbeelden, zodat deze pagina als werkgids dient en niet als korte samenvatting

Belangrijke punten in de bijgewerkte versie:

  • Gebruik eerst kleine reproduceerbare invoerbestanden
  • Laat productnamen, API-namen, bestandsnamen en literal waarden ongewijzigd
  • Bewaar validatoruitvoer en versiegegevens samen met het gegenereerde testbestand

Praktische implementatiekeuzes

Begin met het bestandstype, het verwachte resultaat en de foutstatus die de gebruiker moet zien. Koppel daarna elke API-aanroep aan een controleerbaar resultaat, zodat validatie, logging en support het klantenscenario kunnen reproduceren

  • Gebruik eerst kleine reproduceerbare invoerbestanden
  • Laat productnamen, API-namen, bestandsnamen en literal waarden ongewijzigd
  • Bewaar validatoruitvoer en versiegegevens samen met het gegenereerde testbestand

Code en API-punten

Codevoorbeelden blijven ongewijzigd zodat ontwikkelaars ze direct kunnen vergelijken met Delphi-, C++Builder- en Lazarus/FPC-projecten

if THotPDF.SignPDFWithPFX('invoice-unsigned.pdf', 'invoice-signed.pdf',
    'company-cert.pfx', 'pfx-password') then
  Writeln('Signed: invoice-signed.pdf')
else
  raise Exception.Create('PFX signing failed');
var
  Doc: THotPDF;
  Fs: TFileStream;
  PdfBytes, HashInput, SigHex: AnsiString;
  R1Start, R1Len, R2Start, R2Len, CStart, CLen: Integer;
begin
  // 1. Write the document with a reserved /Contents hole
  Doc := THotPDF.Create(nil);
  try
    Doc.FileName := 'placeholder.pdf';
    Doc.BeginDoc;
    Doc.CurrentPage.AddSignedSignatureField('Sig1',
      Rect(50, 100, 350, 150), 8192, 'adbe.pkcs7.detached',
      'Contract approval', 'Boston, MA', 'legal@example.com');
    Doc.EndDoc;
  finally
    Doc.Free;
  end;

  // 2. Load the saved bytes; the returned offsets are 0-based
  Fs := TFileStream.Create('placeholder.pdf', fmOpenRead);
  try
    SetLength(PdfBytes, Fs.Size);
    Fs.ReadBuffer(PdfBytes[1], Fs.Size);
  finally
    Fs.Free;
  end;
  THotPDF.PreparePDFForSigning(PdfBytes, R1Start, R1Len, R2Start, R2Len,
    CStart, CLen);

  // 3. Hash both spans and sign externally (HSM, token, service)
  HashInput := Copy(PdfBytes, R1Start + 1, R1Len) +
               Copy(PdfBytes, R2Start + 1, R2Len);
  SigHex := SignWithHsm(HashInput);  // your integration: returns CMS as hex

  // 4. Splice the signature into the reserved hole
  THotPDF.InsertSignatureHex(PdfBytes, SigHex);
  Fs := TFileStream.Create('signed.pdf', fmCreate);
  try
    Fs.WriteBuffer(PdfBytes[1], Length(PdfBytes));
  finally
    Fs.Free;
  end;
end;
// PAdES baseline signature field (ETSI EN 319 142-1)
Pdf.CurrentPage.AddPAdESSignatureField(
  'ApprovalSig', Rect(50, 100, 350, 150), 'B-B',
  'Contract approval', 'Boston, MA', 'legal@example.com');

// Document timestamp: larger reservation for the TSA token and chain
Pdf.CurrentPage.AddDocumentTimestampSignature('ArchiveTS', 16384);

Controle vóór publicatie

Controleer het uitvoerbestand met dezelfde tools die de klant of het archief gebruikt. Noteer componentversie, testgegevens, validatorversie en waargenomen resultaat