5 分钟内签署您的第一个文档

从全新 VCL 项目到已签名 XAdES 信封的完整演练。适用于 Delphi 7 至 RAD Studio 13 和 C++Builder。

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

开始之前

只需两件事——在 IDE 中安装 sgcSign,以及用于签名的 PFX 证书。

您需要准备

  • 在 IDE 中安装 sgcSign——参见下载页面
  • 一个带密码的 PFX 证书文件(任何 X.509 PKCS#12 文件均可)。
  • Delphi 7 至 RAD Studio 13,或任意版本的 C++ Builder。同时支持 32 位和 64 位 Windows。
  • 无外部依赖——sgcSign 使用 Windows CNG/BCrypt 进行加密,使用 WinHTTP 进行网络调用。
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".

创建新项目

在 IDE 中新建一个 VCL 窗体应用程序。在窗体上放置两个备注框和一个按钮——这就是全部界面。

窗体布局

  • memoXML——TMemo,在此粘贴未签名的 XML。
  • memoSigned——TMemo,点击按钮后已签名的 XML 显示在此处。
  • btnSign——TButton,与步骤 2 中的 OnClick 处理程序关联。
  • 无需设计时组件——所有内容均通过代码创建。
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

添加签名代码

加载 PFX 提供者,使用 VeriFactu 配置文件将文档签名器指向它,然后调用 SignXML

Delphi

  • TsgcPFXKeyProvider 通过 Windows CNG 导入 .pfx——无论原始 CSP 为何,现代 SHA-256 签名均可正常工作。
  • TsgcDocumentSigner 根据配置文件选择正确的 XAdES 等级。
  • spVeriFactu 选择西班牙 AEAT VeriFactu——XAdES-EPES、B-B、RSA-SHA256、排他性 C14N。
  • 可将常量替换为 21 个国家配置文件中的任意一个——参见国家配置文件
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

  • 相同的结构、相同的类、相同的属性名——C++ 封装是 Delphi API 的 1:1 移植。
  • __finally 块确保即使签名抛出异常,提供者也会被释放。
  • 端到端使用 UnicodeString——无需担心 ANSI/UTF-8 转换问题。
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;
  }
}

添加所需单元

uses 子句中只需两个单元——PFX 提供者和文档签名器。

Delphi uses 子句

每个密钥提供者独立在自己的单元中,按需引用。sgcSign_DocumentSigner 引入根据输入选择 XAdES、PAdES 或 CAdES 的路由层。

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

C++ Builder 包含文件

相同的单元,以 .hpp 头文件形式提供。C++ Builder 链接器自动解析底层静态库。

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

运行和测试

按 F9 键,将发票粘贴到上方备注框,点击签名 XML。已签名的信封将出现在下方备注框中。

编译和运行

在 IDE 中按 F9。窗体将打开,显示两个备注框和一个按钮。无异常,无缺失单元。

粘贴输入

将任意发票 XML(或任何格式正确的 XML)放入 memoXML。签名器内部将其规范化为 UTF-8。

验证结果

memoSigned 现在包含您的 XML,并附有封装的 <ds:Signature> 元素。保存它,通过任何 XAdES 验证器运行——或直接使用 TsgcSignatureVerifier

Unicode 和 WideString 重载

在 Delphi 7 中,stringAnsiString。使用 WideString 重载可无损往返传输波兰语、西里尔语或希腊语字符。

潜在陷阱

在 Delphi 7 中,string 重载通过系统 ACP 路由。'Jarosław' 中的带逆字符仅在系统 ACP 为 CP1250 时才能无损往返。如果 ACP 为 CP1252,字符将在已签名的 XML 中损坏。

WideString 重载完全绕过 ACP——通过带 CP_UTF8WideCharToMultiByte 从 UTF-16 转换为 UTF-8。在 Delphi 2009+ 上,两种重载等价;UnicodeString 已经是 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

所有 X.509 / CRL / OCSP / TSA 时间戳均以 UTC TDateTime 值存储,与底层 ASN.1 规范匹配。

以本地时间显示

对于终端用户显示,使用每个组件的 *Local 属性(如 vCert.NotAfterLocal),或使用单元 sgcSign_Time 中的 sgcUTCToLocal 手动转换。

这符合 RFC 5280(X.509)、RFC 3161(TSA)和 RFC 6960(OCSP)的规定,均指定使用 UTC。sgcUTCNow 辅助函数返回当前 UTC TDateTime,供需要比较时间戳的代码使用。

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);

接下来可以探索

XAdES 只是开始。PAdES、CAdES、配置文件、密钥提供者和集中式服务器都只需一键即可访问。

功能概览

浏览完整的 XAdES、PAdES、CAdES API 接口以及配套的时间戳 + OCSP 基础设施。

阅读更多 →

21 个国家配置文件

VeriFactu、FatturaPA、KSeF、FACTUR-X,加上 9 个 EU 劳动合同配置文件。一行切换司法管辖区域。

阅读更多 →

10 个密钥提供者

PFX、PEM、Windows 存储、PKCS#11、Azure Trusted Signing、AWS KMS、Google KMS、Vault、Certum、CSC v2。

阅读更多 →

sgcSign 服务器

集中管理构建场中的签名。REST API、Web 管理台、GitHub Actions、Azure DevOps、Jenkins、Docker。

阅读更多 →

准备好投入生产了吗?

下载试用版,立即发布已签名的二进制文件,满意后再购买 sgcSign 许可证。