Sign Your First Document in 5 Minutes

A complete walkthrough from a fresh VCL project to a signed XAdES envelope. Works with Delphi 7 through RAD Studio 13 and C++Builder.

Delphi 7 – RAD Studio 13
C++ Builder
VeriFactu Profile

Before You Start

Two things only — sgcSign installed in the IDE, and a PFX certificate to sign with.

You'll need

  • sgcSign installed in your IDE — see the download page.
  • A PFX certificate file with its password (any X.509 PKCS#12 file works).
  • Delphi 7 through RAD Studio 13, or any version of C++ Builder. 32-bit and 64-bit Windows are both supported.
  • No external dependencies — sgcSign uses Windows CNG/BCrypt for cryptography and WinHTTP for network calls.
make-test-cert.sh
# No PFX yet? Generate a self-signed test cert with 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

# Now you have test.pfx with password "secret".

Create a New Project

Spin up a VCL Forms application in your IDE. Drop two memos and a button on the form — that is the entire UI.

Form layout

  • memoXMLTMemo, paste your unsigned XML in here.
  • memoSignedTMemo, signed XML appears here after the button click.
  • btnSignTButton, hooked to the OnClick handler in step 2.
  • No design-time components required — everything is created in code.
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

Add the Signing Code

Load a PFX provider, point a document signer at it with the VeriFactu profile, and call SignXML.

Delphi

  • TsgcPFXKeyProvider imports the .pfx via Windows CNG — modern SHA-256 signing works regardless of the original CSP.
  • TsgcDocumentSigner picks the right XAdES level based on the profile.
  • spVeriFactu selects Spanish AEAT VeriFactu — XAdES-EPES, B-B, RSA-SHA256, exclusive C14N.
  • Swap the constant for any of the 21 country profiles — see Country Profiles.
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

  • Same shape, same classes, same property names — the C++ wrapper is a 1:1 port of the Delphi API.
  • __finally block ensures the providers are released even if signing throws.
  • UnicodeString is used end-to-end — no ANSI/UTF-8 conversion to worry about.
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;
  }
}

Add the Required Units

Two units in your uses clause — the PFX provider and the document signer.

Delphi uses clause

Each key provider lives in its own unit so you only pay for what you reference. sgcSign_DocumentSigner brings in the routing layer that picks XAdES, PAdES, or CAdES based on the input.

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

C++ Builder includes

Same units, exposed as .hpp headers. The C++ Builder linker resolves the underlying static libraries automatically.

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

Run and Test

Press F9, paste an invoice into the top memo, click Sign XML. The signed envelope appears in the bottom memo.

Compile and run

Press F9 in the IDE. The form opens with two memos and a button. No exceptions, no missing units.

Paste the input

Drop any invoice XML (or any well-formed XML at all) into memoXML. The signer normalises it to UTF-8 internally.

Verify the result

memoSigned now contains your XML with an enveloped <ds:Signature> element appended. Save it, run it through any XAdES verifier — or use TsgcSignatureVerifier directly.

Unicode and the WideString Overload

On Delphi 7, string is AnsiString. Use the WideString overloads to round-trip Polish, Cyrillic, or Greek characters losslessly.

The pitfall

On Delphi 7 the string overload routes through the system ACP. Diacritics in 'Jarosław' only round-trip when the system ACP is CP1250. If the ACP is CP1252, characters get corrupted in the signed XML.

The WideString overloads bypass ACP entirely — UTF-16 to UTF-8 via WideCharToMultiByte with CP_UTF8. On Delphi 2009+ both overloads are equivalent; UnicodeString is already UTF-16.

d7-unicode.pas
var
  Doc: IXMLDocument;       // MSXML6
  XML, Signed: WideString; // = MSXML6 DOMString
  Sign: TsgcXAdESSigner;
begin
  Doc.SaveToXML(XML);            // WideString out, no ACP step
  Signed := Sign.SignXML(XML);   // resolves to WideString overload
  // Polish, Cyrillic, Greek round-trip losslessly
end;

UTC by Default

All X.509 / CRL / OCSP / TSA timestamps are stored as UTC TDateTime values, matching the underlying ASN.1 specs.

Display in local time

For end-user displays, use the *Local properties on each component (e.g. vCert.NotAfterLocal) or convert manually with sgcUTCToLocal from unit sgcSign_Time.

This matches RFC 5280 (X.509), RFC 3161 (TSA), and RFC 6960 (OCSP) which all specify UTC. The sgcUTCNow helper returns the current UTC TDateTime for code that needs to compare timestamps.

time-zones.pas
uses sgcSign_Time;

// Display certificate validity in local time
Memo1.Lines.Add('Cert expires: ' +
                DateTimeToStr(vCert.NotAfterLocal));
Memo1.Lines.Add('Now (UTC):    ' +
                DateTimeToStr(sgcUTCNow));

// Or convert manually
vLocal := sgcUTCToLocal(vCert.NotAfter);

Where to Go from Here

XAdES is just the start. PAdES, CAdES, profiles, key providers, and the centralised server are all one click away.

Features Overview

Tour the full XAdES, PAdES, CAdES API surface and the supporting timestamp + OCSP infrastructure.

Read more →

21 Country Profiles

VeriFactu, FatturaPA, KSeF, FACTUR-X, plus 9 EU employment-contract profiles. One-line jurisdiction switching.

Read more →

10 Key Providers

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

Read more →

sgcSign Server

Centralise signing across the build farm. REST API, web admin, GitHub Actions, Azure DevOps, Jenkins, Docker.

Read more →

Ready for Production?

Download the trial, ship a signed binary today, license sgcSign when you're happy.