本文目录导读:

- 使用 OpenSSL 进行 PGP/GPG 签名(最常用)
- 使用 Hash + 数字签名(更轻量)
- 使用 Ed25519 签名(现代加密标准)
- Maven/Gradle Artifact 签名(针对 Java 发布)
- 完整示例:带元数据的签名格式
- 注意事项
在 PHP 中进行 Artifact(制品/构建产物)签名,通常有几种不同的场景,这里主要介绍最常见的几种情况,你可以根据具体需求选择对应的方法:
使用 OpenSSL 进行 PGP/GPG 签名(最常用)
这是签名发布包、JAR 文件或 Debian 包最标准的方式。
<?php
// 场景:对文件进行 PGP 签名
$fileToSign = '/path/to/your/artifact.tar.gz';
$privateKey = '/path/to/private-key.pem';
$passphrase = 'your-passphrase';
// 方法1:使用 exec 调用 GPG
exec("gpg --batch --yes --passphrase-fd 0 --armor --detach-sign --output {$fileToSign}.sig {$fileToSign}",
$output, $returnCode);
// 方法2:使用 PHP 的 gnupg 扩展(需要安装)
if (function_exists('gnupg_init')) {
$gpg = gnupg_init();
gnupg_setsignmode($gpg, GNUPG_SIG_MODE_DETACH);
gnupg_addsignkey($gpg, 'your-key-id', $passphrase);
$signature = gnupg_sign($gpg, file_get_contents($fileToSign));
file_put_contents($fileToSign . '.sig', $signature);
}
使用 Hash + 数字签名(更轻量)
适合自定义的校验机制:
<?php
// 对文件生成 SHA-256 哈希,然后用私钥签名
function signArtifact($filePath, $privateKeyPath) {
// 1. 计算文件哈希
$hash = hash_file('sha256', $filePath);
// 2. 读取私钥
$privateKey = file_get_contents($privateKeyPath);
$key = openssl_pkey_get_private($privateKey);
// 3. 签名
openssl_sign($hash, $signature, $key, OPENSSL_ALGO_SHA256);
return base64_encode($signature);
}
// 验证签名
function verifyArtifact($filePath, $signature, $publicKeyPath) {
$hash = hash_file('sha256', $filePath);
$publicKey = file_get_contents($publicKeyPath);
$key = openssl_pkey_get_public($publicKey);
return openssl_verify($hash, base64_decode($signature), $key, OPENSSL_ALGO_SHA256) === 1;
}
使用 Ed25519 签名(现代加密标准)
PHP 8.1+ 内置支持:
<?php
// 生成密钥对
$keyPair = sodium_crypto_sign_keypair();
$privateKey = sodium_crypto_sign_secretkey($keyPair);
$publicKey = sodium_crypto_sign_publickey($keyPair);
// 签名
$content = file_get_contents('/path/to/artifact.zip');
$signature = sodium_crypto_sign_detached($content, $privateKey);
file_put_contents('/path/to/artifact.sig', $signature);
// 验证
$signature = file_get_contents('/path/to/artifact.sig');
$isValid = sodium_crypto_sign_verify_detached($signature, $content, $publicKey);
Maven/Gradle Artifact 签名(针对 Java 发布)
如果是发布到 Maven 仓库的 JAR:
<?php
// 使用 maven-gpg-plugin 等价操作
exec('mvn gpg:sign-and-deploy-file -Dfile=my-artifact.jar -DpomFile=pom.xml');
// 或者手动对 .jar 和 .pom 文件进行签名
$files = ['my-artifact.jar', 'my-artifact.pom'];
foreach ($files as $file) {
exec("gpg --armor --detach-sign {$file}", $output, $code);
}
完整示例:带元数据的签名格式
<?php
class ArtifactSigner {
private $privateKey;
private $passphrase;
public function __construct($privateKeyPath, $passphrase = null) {
$this->privateKey = file_get_contents($privateKeyPath);
$this->passphrase = $passphrase;
}
public function sign($artifactPath) {
// 生成签名清单
$manifest = [
'file' => basename($artifactPath),
'size' => filesize($artifactPath),
'sha256' => hash_file('sha256', $artifactPath),
'md5' => md5_file($artifactPath),
'timestamp' => date(DATE_ATOM),
'version' => '1.0.0'
];
// 对清单内容签名
$content = json_encode($manifest, JSON_PRETTY_PRINT);
$key = openssl_pkey_get_private($this->privateKey, $this->passphrase);
openssl_sign($content, $signature, $key, OPENSSL_ALGO_SHA256);
// 保存签名文件
$sigFilePath = $artifactPath . '.sig';
file_put_contents($sigFilePath, json_encode([
'manifest' => $manifest,
'signature' => base64_encode($signature)
], JSON_PRETTY_PRINT));
return $sigFilePath;
}
public function verify($artifactPath, $sigFilePath, $publicKeyPath) {
$sigData = json_decode(file_get_contents($sigFilePath), true);
$manifest = $sigData['manifest'];
// 重新计算哈希
$currentHash = hash_file('sha256', $artifactPath);
if ($currentHash !== $manifest['sha256']) {
return false;
}
// 验证签名
$publicKey = file_get_contents($publicKeyPath);
$key = openssl_pkey_get_public($publicKey);
$content = json_encode($manifest, JSON_PRETTY_PRINT);
return openssl_verify($content, base64_decode($sigData['signature']), $key, OPENSSL_ALGO_SHA256) === 1;
}
}
注意事项
- 安全存储密钥:不要将私钥硬编码在代码中,使用环境变量或密钥管理服务
- 使用安全的哈希算法:推荐 SHA-256 或更强
- 考虑签名过期时间:在需签名的元数据中包含时间戳
- 备份签名验证公钥:用于后续验证
选择哪种方式取决于你的使用场景(是发布包、内部工具还是安全要求),可以根据需求灵活选择。