Signiere dein erstes Dokument in 5 Minuten

Ein kompletter Durchgang von einem frischen VCL-Projekt bis zur signierten XAdES-Envelope. Funktioniert mit Delphi 7 bis RAD Studio 13 und C++ Builder.

Delphi 7 – RAD Studio 13
C++ Builder
VeriFactu-Profil

Bevor du startest

Nur zwei Dinge — sgcSign in der IDE installiert und ein PFX-Zertifikat zum Signieren.

Du brauchst

  • sgcSign installiert in deiner IDE — siehe die Download-Seite.
  • Eine PFX-Zertifikatsdatei mit Passwort (jede X.509-PKCS#12-Datei funktioniert).
  • Delphi 7 bis RAD Studio 13 oder jede Version von C++ Builder. 32-Bit- und 64-Bit-Windows werden beide unterstützt.
  • Keine externen Abhängigkeiten — sgcSign verwendet Windows CNG/BCrypt für Kryptografie und WinHTTP für Netzwerkaufrufe.
make-test-cert.sh
# Noch kein PFX? Erzeuge ein selbstsigniertes Test-Zertifikat mit OpenSSL:
openssl req -x509 -newkey rsa:2048 \
  -keyout key.pem -out cert.pem \
  -days 365 -nodes \
  -subj "/CN=sgcSign Test"

openssl pkcs12 -export \
  -inkey key.pem -in cert.pem \
  -out test.pfx \
  -password pass:secret

# Jetzt hast du test.pfx mit dem Passwort "secret".

Erstelle ein neues Projekt

Erstelle eine VCL-Forms-Anwendung in deiner IDE. Platziere zwei Memos und einen Button auf dem Formular — das ist die gesamte UI.

Formular-Layout

  • memoXMLTMemo, hier fügst du dein unsigniertes XML ein.
  • memoSignedTMemo, hier erscheint das signierte XML nach dem Button-Klick.
  • btnSignTButton, verknüpft mit dem OnClick-Handler aus Schritt 2.
  • Keine Design-Time-Komponenten nötig — alles wird im Code erstellt.
Unit1.dfm
object Form1: TForm1
  Caption = 'sgcSign Quick Start'
  ClientWidth  = 800
  ClientHeight = 600

  object memoXML: TMemo
    Left = 8
    Top  = 8
    Width  = 784
    Height = 240
  end

  object memoSigned: TMemo
    Left = 8
    Top  = 288
    Width  = 784
    Height = 300
  end

  object btnSign: TButton
    Left = 8
    Top  = 256
    Caption = 'Sign XML'
  end
end

Füge den Signatur-Code hinzu

Lade einen PFX-Provider, richte einen Document-Signer mit dem VeriFactu-Profil darauf und rufe SignXML auf.

Delphi

  • TsgcPFXKeyProvider importiert die .pfx über Windows CNG — modernes SHA-256-Signieren funktioniert unabhängig vom ursprünglichen CSP.
  • TsgcDocumentSigner wählt das richtige XAdES-Level basierend auf dem Profil.
  • spVeriFactu wählt das spanische AEAT-VeriFactu — XAdES-EPES, B-B, RSA-SHA256, Exclusive C14N.
  • Tausche die Konstante gegen eines der 21 Länderprofile — siehe Länderprofile.
Unit1.pas
procedure TForm1.btnSignClick(Sender: TObject);
var
  vKeyProvider: TsgcPFXKeyProvider;
  vSigner: TsgcDocumentSigner;
begin
  vKeyProvider := TsgcPFXKeyProvider.Create(nil);
  try
    vKeyProvider.FileName := 'certificate.pfx';
    vKeyProvider.Password := 'secret';
    vKeyProvider.LoadFromFile;

    vSigner := TsgcDocumentSigner.Create(nil);
    try
      vSigner.KeyProvider := vKeyProvider;
      vSigner.Profile := spVeriFactu;
      memoSigned.Text := vSigner.SignXML(memoXML.Text);
    finally
      vSigner.Free;
    end;
  finally
    vKeyProvider.Free;
  end;
end;

C++ Builder

  • Gleiche Form, gleiche Klassen, gleiche Property-Namen — der C++-Wrapper ist ein 1:1-Port der Delphi-API.
  • Der __finally-Block stellt sicher, dass die Provider auch bei Signatur-Exceptions freigegeben werden.
  • UnicodeString wird end-to-end verwendet — keine ANSI-/UTF-8-Konvertierung nötig.
Unit1.cpp
void __fastcall TForm1::btnSignClick(TObject *Sender)
{
  TsgcPFXKeyProvider *vKeyProvider = new TsgcPFXKeyProvider(NULL);
  try {
    vKeyProvider->FileName = "certificate.pfx";
    vKeyProvider->Password = "secret";
    vKeyProvider->LoadFromFile();

    TsgcDocumentSigner *vSigner = new TsgcDocumentSigner(NULL);
    try {
      vSigner->KeyProvider = vKeyProvider;
      vSigner->Profile = spVeriFactu;
      memoSigned->Text = vSigner->SignXML(memoXML->Text);
    } __finally {
      delete vSigner;
    }
  } __finally {
    delete vKeyProvider;
  }
}

Erforderliche Units hinzufügen

Zwei Units in deiner uses-Klausel — der PFX-Provider und der Document-Signer.

Delphi-uses-Klausel

Jeder Key Provider lebt in seiner eigenen Unit, sodass du nur das bezahlst, was du referenzierst. sgcSign_DocumentSigner bringt die Routing-Schicht mit, die basierend auf der Eingabe XAdES, PAdES oder CAdES wählt.

Unit1.pas
uses
  Classes, SysUtils, Forms, StdCtrls, Controls,
  // sgc
  sgcSign_KeyProvider_PFX,
  sgcSign_DocumentSigner;

C++ Builder-Includes

Dieselben Units, als .hpp-Header bereitgestellt. Der C++ Builder-Linker löst die zugrunde liegenden statischen Bibliotheken automatisch auf.

Unit1.cpp
#include "sgcSign_KeyProvider_PFX.hpp"
#include "sgcSign_DocumentSigner.hpp"

Ausführen und testen

Drücke F9, füge eine Rechnung ins obere Memo ein, klicke auf Sign XML. Die signierte Envelope erscheint im unteren Memo.

Kompilieren und ausführen

Drücke F9 in der IDE. Das Formular öffnet sich mit zwei Memos und einem Button. Keine Exceptions, keine fehlenden Units.

Eingabe einfügen

Füge ein beliebiges Rechnungs-XML (oder beliebiges wohlgeformtes XML) in memoXML ein. Der Signer normalisiert es intern auf UTF-8.

Ergebnis verifizieren

memoSigned enthält jetzt dein XML mit angehängtem <ds:Signature>-Element. Speichere es, jage es durch einen beliebigen XAdES-Verifier — oder nutze direkt TsgcSignatureVerifier.

Unicode und der WideString-Overload

In Delphi 7 ist string gleich AnsiString. Nutze die WideString-Overloads, um polnische, kyrillische oder griechische Zeichen verlustfrei zu übertragen.

Die Stolperfalle

In Delphi 7 läuft der string-Overload über das System-ACP. Diakritika in 'Jarosław' kommen nur dann verlustfrei durch, wenn das System-ACP CP1250 ist. Ist das ACP CP1252, werden Zeichen im signierten XML beschädigt.

Die WideString-Overloads umgehen das ACP vollständig — UTF-16 zu UTF-8 über WideCharToMultiByte mit CP_UTF8. Ab Delphi 2009 sind beide Overloads äquivalent; UnicodeString ist bereits UTF-16.

d7-unicode.pas
var
  Doc: IXMLDocument;       // MSXML6
  XML, Signed: WideString; // = MSXML6 DOMString
  Sign: TsgcXAdESSigner;
begin
  Doc.SaveToXML(XML);            // WideString-Output, kein ACP-Schritt
  Signed := Sign.SignXML(XML);   // wählt den WideString-Overload
  // Polnisch, Kyrillisch, Griechisch laufen verlustfrei durch
end;

Standardmäßig UTC

Alle X.509-/CRL-/OCSP-/TSA-Timestamps werden als UTC-TDateTime-Werte gespeichert, passend zu den zugrundeliegenden ASN.1-Specs.

Anzeige in Ortszeit

Für End-User-Anzeigen nutze die *Local-Properties an jeder Komponente (z. B. vCert.NotAfterLocal) oder konvertiere manuell mit sgcUTCToLocal aus der Unit sgcSign_Time.

Das passt zu RFC 5280 (X.509), RFC 3161 (TSA) und RFC 6960 (OCSP), die alle UTC vorschreiben. Der Helper sgcUTCNow liefert das aktuelle UTC-TDateTime für Code, der Timestamps vergleichen muss.

time-zones.pas
uses sgcSign_Time;

// Zertifikatsgültigkeit in Ortszeit anzeigen
Memo1.Lines.Add('Cert expires: ' +
                DateTimeToStr(vCert.NotAfterLocal));
Memo1.Lines.Add('Now (UTC):    ' +
                DateTimeToStr(sgcUTCNow));

// Oder manuell konvertieren
vLocal := sgcUTCToLocal(vCert.NotAfter);

Wie es weitergeht

XAdES ist nur der Anfang. PAdES, CAdES, Profile, Key Provider und der zentrale Server sind alle einen Klick entfernt.

Funktionsübersicht

Tour durch die vollständige XAdES-, PAdES-, CAdES-API-Oberfläche und die unterstützende Timestamp- + OCSP-Infrastruktur.

Mehr erfahren →

21 Länderprofile

VeriFactu, FatturaPA, KSeF, FACTUR-X plus 9 EU-Arbeitsvertragsprofile. Jurisdiktion in einer Zeile wechseln.

Mehr erfahren →

10 Key Provider

PFX, PEM, Windows Store, PKCS#11, Azure Trusted Signing, AWS KMS, Google KMS, Vault, Certum, CSC v2.

Mehr erfahren →

sgcSign Server

Zentralisiere das Signieren über die Build-Farm. REST-API, Web-Admin, GitHub Actions, Azure DevOps, Jenkins, Docker.

Mehr erfahren →

Bereit für die Produktion?

Lade die Testversion herunter, liefere heute eine signierte Binary aus und lizenziere sgcSign, wenn du zufrieden bist.