
本文详解如何在 php 中通过 gnupg 扩展正确实现 pgp 加密(使用公钥)与解密(使用私钥),重点纠正常见误区——解密时必须显式调用 adddecryptkey() 并传入私钥指纹及对应口令,而非复用 addencryptkey()。
本文详解如何在 php 中通过 gnupg 扩展正确实现 pgp 加密(使用公钥)与解密(使用私钥),重点纠正常见误区——解密时必须显式调用 adddecryptkey() 并传入私钥指纹及对应口令,而非复用 addencryptkey()。
在 PHP 中实现符合 OpenPGP 标准的 RSA 加密/解密,推荐使用原生 GnuPG 扩展(gnupg),它底层调用系统 GPG 二进制,安全可靠、兼容性强。但实践中常因 API 使用不当导致解密失败——典型错误是:在解密流程中误用 addencryptkey() 导入私钥,或完全忽略私钥口令(passphrase)参数。GnuPG 要求私钥解密前必须通过 adddecryptkey(fingerprint, passphrase) 显式授权,否则 decrypt() 将静默失败或抛出异常。
以下为经过验证的完整、健壮实现:
<?php
// 1. 设置 GPG 环境目录(确保 /tmp 可写且权限隔离,生产环境建议使用专用目录)
putenv('GNUPGHOME=/tmp/gnupg-' . uniqid());
// 2. 初始化 GnuPG 实例并启用异常模式(强烈推荐,便于调试)
$gpg = new gnupg();
$gpg->seterrormode(gnupg::ERROR_EXCEPTION);
// 3. 读取并导入密钥(注意:公钥用于加密,私钥用于解密)
$publicData = file_get_contents('/path/to/public.asc');
$privateData = file_get_contents('/path/to/private.asc');
$importedPub = $gpg->import($publicData);
$importedPriv = $gpg->import($privateData);
// 4. 配置加密与解密密钥(关键步骤!)
$gpg->addencryptkey($importedPub['fingerprint']);
// ✅ 正确:解密必须用 adddecryptkey(),且传入口令
$gpg->adddecryptkey($importedPriv['fingerprint'], 'your_private_key_passphrase');
// 5. 执行加密与解密
$plaintext = 'Hello, this is a confidential message.';
$encrypted = $gpg->encrypt($plaintext);
echo "Encrypted:\n" . $encrypted . "\n";
$decrypted = $gpg->decrypt($encrypted);
echo "Decrypted: " . $decrypted . "\n";
// 验证完整性
var_dump($plaintext === $decrypted); // bool(true)⚠️ 关键注意事项
- 口令不可省略:即使私钥未设口令,也需传入空字符串 '';若口令错误,decrypt() 将抛出 gnupgException。
- 密钥格式要求:.asc 文件必须为 ASCII-armored 格式(含 -----BEGIN PGP PUBLIC KEY BLOCK----- 头尾),可通过 gpg --armor --export KEYID > public.asc 生成。
- 环境隔离:GNUPGHOME 应指向独立、可写、非共享目录(如 /tmp/gnupg-xxx),避免多请求间密钥冲突或权限污染。
- 错误处理:务必启用 seterrormode(gnupg::ERROR_EXCEPTION),否则失败无提示;生产环境应捕获 gnupgException 并记录日志。
- 性能提示:密钥导入(import())开销较大,建议在长生命周期对象(如 Composer 服务类)中缓存指纹,避免每次加解密重复导入。
总结
PGP 在 PHP 中并非“仅靠公私钥文件即可运行”的黑盒流程。其核心在于严格遵循 GnuPG 的密钥管理契约:加密用 addencryptkey() 绑定公钥指纹;解密则必须用 adddecryptkey() 绑定私钥指纹+口令。跳过任一环节,或混淆方法用途,都将导致解密静默失败。掌握此逻辑,结合环境隔离与异常驱动开发,即可构建高可信度的端到端加密通信能力。



















