You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

埃及电子发票合规:PHP实现USB令牌CADES-BES哈希签名需求

使用PHP通过USB令牌为埃及电子发票哈希生成电子签名(无需Chilkat)

要实现USB令牌签名哈希,核心是利用PKCS#11标准(大多数USB令牌支持)结合PHP的OpenSSL扩展或系统命令工具完成。以下是两种可行方案:

方案一:纯PHP + OpenSSL PKCS#11引擎

此方案直接通过PHP的OpenSSL扩展调用PKCS#11引擎访问USB令牌私钥。

前置准备

  • 确认PHP已启用OpenSSL扩展:执行php -m | grep openssl验证
  • 获取令牌厂商提供的PKCS#11驱动文件(如.so或.dll)
  • 知晓令牌PIN码、私钥的别名/ID

代码实现

<?php
// 配置参数,替换为你的实际值
$pkcs11Driver = "/usr/lib/libeTPkcs11.so"; // PKCS#11驱动路径
$tokenPin = "123456"; // 令牌PIN,禁止硬编码,建议从安全环境变量读取
$privateKeyAlias = "invoice_signature_key"; // 令牌内私钥的别名/ID
$targetHash = "a1b2c3d4..."; // 需要签名的哈希值(十六进制格式)

// 加载并初始化PKCS#11引擎
$pkcs11Engine = openssl_get_engine("pkcs11");
if (!$pkcs11Engine || !openssl_engine_init($pkcs11Engine)) {
    die("PKCS#11引擎加载/初始化失败: " . openssl_error_string());
}

// 设置驱动路径
openssl_engine_ctrl($pkcs11Engine, ENGINE_CTRL_SET_CONFIG, 0, $pkcs11Driver);

// 构建PKCS#11私钥路径
$privateKeyUri = sprintf("pkcs11:pin=%s;object=%s", $tokenPin, $privateKeyAlias);
$privateKey = openssl_pkey_get_private($privateKeyUri);

if (!$privateKey) {
    die("获取私钥失败: " . openssl_error_string());
}

// 对哈希签名(算法需匹配埃及电子发票要求,示例用SHA-256)
$signature = '';
$signSuccess = openssl_sign(hex2bin($targetHash), $signature, $privateKey, OPENSSL_ALGO_SHA256);

if (!$signSuccess) {
    die("签名失败: " . openssl_error_string());
}

// 转换为Base64格式以便后续提交
$base64Signature = base64_encode($signature);
echo "生成的电子签名(Base64): " . $base64Signature . "\n";

// 释放资源
openssl_pkey_free($privateKey);
openssl_engine_finish($pkcs11Engine);
?>

关键说明

  • 若openssl_get_engine("pkcs11")失败,需在OpenSSL配置文件中启用PKCS#11引擎,或手动调用openssl_engine_load加载
  • 部分令牌需指定token名称,私钥URI格式可调整为:pkcs11:token=MyTokenName;pin=xxx;object=xxx
  • 哈希值需为二进制格式,若传入的是十六进制字符串,必须用hex2bin转换

方案二:PHP调用OpenSC命令行工具

如果PHP的PKCS#11引擎支持不佳,可通过调用pkcs11-tool(OpenSC工具包组件)完成签名,实现更稳定。

前置准备

  • 安装OpenSC工具包:apt install opensc(Debian/Ubuntu)或yum install opensc(CentOS/RHEL)
  • 确保Web服务器用户(如www-data)有权限访问USB设备和执行pkcs11-tool

代码实现

<?php
// 配置参数
$pkcs11Driver = "/usr/lib/libeTPkcs11.so";
$tokenPin = "123456";
$privateKeyId = "invoice_sign_key";
$targetHash = "a1b2c3d4..."; // 十六进制哈希值

// 创建临时文件存储哈希(避免命令行参数长度限制)
$hashTempFile = tempnam(sys_get_temp_dir(), "invoice_hash");
$signatureTempFile = tempnam(sys_get_temp_dir(), "invoice_sig");

// 写入二进制哈希到临时文件
file_put_contents($hashTempFile, hex2bin($targetHash));

// 构建签名命令
$signCommand = sprintf(
    "pkcs11-tool --module %s --pin %s --sign --id '%s' --input %s --output %s --hash sha256",
    escapeshellarg($pkcs11Driver),
    escapeshellarg($tokenPin),
    escapeshellarg($privateKeyId),
    escapeshellarg($hashTempFile),
    escapeshellarg($signatureTempFile)
);

// 执行命令并处理结果
$commandOutput = [];
$returnCode = 0;
exec($signCommand, $commandOutput, $returnCode);

if ($returnCode !== 0) {
    die("签名命令执行失败: " . implode("\n", $commandOutput));
}

// 读取并转换签名格式
$signature = file_get_contents($signatureTempFile);
$base64Signature = base64_encode($signature);
echo "生成的电子签名(Base64): " . $base64Signature . "\n";

// 清理临时文件
unlink($hashTempFile);
unlink($signatureTempFile);
?>

关键说明

  • pkcs11-tool的参数可根据令牌型号调整,比如用--label代替--id指定私钥标签
  • 生产环境中需严格控制临时文件的权限,避免哈希或签名泄露

内容的提问来源于stack exchange,提问作者Amr Ahmed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 17:05:22