OpenPGP 仍然是许多机构交换文件的方式。银行要求付款批次用它的公钥加密,合作伙伴发来用 GnuPG 加密的报表,发布包需要附带一个分离签名。在 Delphi 中,这通常意味着要在每台机器上安装 GnuPG,并从命令行调用 gpg.exe,同时还要处理随之而来的路径、密钥环和退出码问题。
sgcCrypto 现在自行实现了 OpenPGP,使用纯 Object Pascal。无需部署 DLL,无需调用命令行工具,也不依赖 Indy。密钥、加密、解密、签名和验证都只是对 TBytes 的几个函数调用,而且结果可与 GnuPG 双向互操作。
版本 4 和版本 6
支持两代格式:
- 版本 4(RFC 4880 和 RFC 6637)是 GnuPG、Kleopatra 和大多数邮件客户端目前使用的格式。与现有工具交换密钥和文件时请选择它。
- 版本 6(RFC 9580)是当前的标准。它增加了认证加密(使用 OCB、EAX 或 GCM 的 AEAD)、用于口令的 Argon2,以及原生的 Ed25519、Ed448、X25519 和 X448 密钥。
向多个收件人加密时,库会选择每个人都能读取的格式:如果所有人都支持,就使用 RFC 9580 的 AEAD 格式,否则使用经典的完整性保护格式。发给新旧密钥混合收件人的消息,在任何地方都能打开。
生成密钥
一次调用就能创建完整的密钥:一个主签名密钥、一个加密子密钥、用户 ID,以及把它们绑定在一起的自签名。
uses
sgcCrypto_PGP, sgcCrypto_PGP_Cert;
var
oAlice: TsgcPGPKey;
begin
// v4 Ed25519 + Curve25519, the default key type of GnuPG
oAlice := sgcPGP_GenerateKey('Alice <alice@example.com>', 'secret',
pgpkEd25519, 4);
try
Memo1.Text := oAlice.SaveToArmored(False); // public key, share it
SaveSecretKey(oAlice.SaveToArmored(True)); // protected secret key
finally
oAlice.Free;
end;
end;
支持的密钥类型有 RSA 2048、3072 和 4096,Ed25519,Ed448(版本 6),以及基于 NIST P-256、P-384 和 P-521 的 ECDSA 与 ECDH。可以导入 Brainpool 密钥。私钥用你的口令保护,版本 4 使用迭代 SHA-256,版本 6 使用 Argon2 加 AES-OCB。
加密和解密
可以向一个或多个公钥加密,并可选择由发送方签名。输出默认是 ASCII armor 格式,可直接附加到邮件或上传到服务器。
// encrypt to Bob, signed by Alice, compressed with ZIP
vEncrypted := sgcPGP_Encrypt(vData, [oBob], oAlice);
// or protect a file with a passphrase only
vEncrypted := sgcPGP_EncryptSymmetric(vData, 'shared passphrase');
解密需要一个包含你的私钥的密钥环。被锁定的私钥会在私有副本上用口令解锁,因此密钥环本身不会改变。结果会告诉你消息是发给谁的、使用了什么加密方式,以及其中的签名是否有效。
var
oRing: TsgcPGPKeyRing;
vResult: TsgcPGPDecryptResult;
begin
oRing := TsgcPGPKeyRing.Create;
try
oRing.LoadFromFile('bob-secret.asc');
vData := sgcPGP_Decrypt(vEncrypted, oRing, 'bob passphrase', oContacts,
vResult);
if vResult.Verify.Valid then
Log('Signed by ' + vResult.Verify.SignerUserID);
finally
oRing.Free;
end;
end;
签名和验证
支持用于文件和发布包的分离签名、内联签名消息,以及必须保持可读的文本所用的明文签名,还提供文本模式,使签名与换行符风格无关。
// detached signature, the classic file.sig
vSignature := sgcPGP_Sign(vData, oAlice);
if sgcPGP_VerifyDetached(vData, vSignature, oContacts, vVerify) then
Log('Valid signature from ' + vVerify.SignerUserID);
// cleartext signed text, readable without any tool
vSigned := sgcPGP_ClearSign('Payment batch 2026-10 approved', oAlice);
与 GnuPG 协同工作
每项功能都与 GnuPG 2.4.5 进行了双向测试:GnuPG 生成的文件和签名可以在 Delphi 中解密和验证,库生成的所有内容都能被 gpg --decrypt 和 gpg --verify 接受。这包括 GnuPG 2.4 对其自己生成的密钥默认写出的 OCB 加密消息,许多 OpenPGP 库无法读取这种消息。版本 6 的支持则对照 RFC 9580 的示例密钥和消息进行了检查。
密钥以 armor 文本的形式在两个世界之间流动。从 Delphi 导出密钥后运行 gpg --import,或者把 gpg --export --armor 的输出加载到 TsgcPGPKeyRing 中。
为不可信输入而设计
解密外部文件的应用必须假定其中一些是恶意的。库会拒绝旧的无保护加密格式,对所有解密失败报告相同的错误,因此无法被用作 oracle,拒绝文档上的 SHA-1 签名,并对口令工作因子和解压后的大小设置了限制,使精心构造的消息无法拖垮服务器。
其他新功能
- AES-OCB(RFC 7253)和 AES-EAX 认证加密,可在 sgcCrypto 中单独使用。
- 新的纯 Object Pascal 单元
sgcCrypto_Deflate提供 DEFLATE 和 ZLIB 压缩。 - 一个 VCL 演示
Demos\18.Cryptography\09.OpenPGP,在一个窗口中包含密钥生成、导入和导出、加密、解密、签名和验证。
OpenPGP 单元可在 Delphi 7 到 Delphi 13 和 C++Builder 下编译,支持 Win32 和 Win64。DSA 和 ElGamal 密钥可以加载但不能使用,也不支持旧的 CAST5、3DES 和 IDEA 密码。
延伸阅读
对某个具体集成、银行格式或需要导入的密钥有疑问?欢迎联系我们。你会收到编写这些代码的人的回复。
