本文目录导读:

我来为您详细介绍PHP项目中实现可链接签名(Linkable Signatures)和可追踪签名(Traceable Signatures)的方案。
可链接签名(Linkable Signatures)
核心概念
可链接签名允许验证者判断两个签名是否来自同一签名者,同时保护签名者身份。
PHP实现示例
<?php
class LinkableSignature {
private $privateKey;
private $publicKey;
public function __construct() {
$this->generateKeyPair();
}
private function generateKeyPair() {
// 使用椭圆曲线加密生成密钥对
$config = [
'private_key_type' => OPENSSL_KEYTYPE_EC,
'curve_name' => 'prime256v1'
];
$res = openssl_pkey_new($config);
openssl_pkey_export($res, $this->privateKey);
$details = openssl_pkey_get_details($res);
$this->publicKey = $details['key'];
}
// 生成可链接签名
public function sign($message, $tag) {
// 生成链接标签(linkability tag)
$linkTag = hash_hmac('sha256', $tag, $this->privateKey);
// 对消息签名
openssl_sign($message, $signature, $this->privateKey, OPENSSL_ALGO_SHA256);
return [
'signature' => base64_encode($signature),
'link_tag' => $linkTag,
'message' => $message
];
}
// 验证签名
public function verify($signedData, $publicKey) {
$signature = base64_decode($signedData['signature']);
$verification = openssl_verify(
$signedData['message'],
$signature,
$publicKey,
OPENSSL_ALGO_SHA256
);
return $verification === 1;
}
// 检查两个签名是否可链接
public function isLinkable($signature1, $signature2) {
return $signature1['link_tag'] === $signature2['link_tag'];
}
public function getPublicKey() {
return $this->publicKey;
}
}
// 使用示例
$signer1 = new LinkableSignature();
$signer2 = new LinkableSignature();
$message = "重要交易数据";
$tag = "user_session_123";
$signed1 = $signer1->sign($message, $tag);
$signed2 = $signer1->sign("另一条消息", $tag); // 同一签名者
$signed3 = $signer2->sign($message, $tag); // 不同签名者
echo "签名1和签名2是否可链接: " .
($signer1->isLinkable($signed1, $signed2) ? "是" : "否") . "\n";
echo "签名1和签名3是否可链接: " .
($signer1->isLinkable($signed1, $signed3) ? "是" : "否") . "\n";
可追踪签名(Traceable Signatures)
核心概念
可追踪签名允许指定追踪者(如管理员)在必要时揭示签名者身份。
PHP实现示例
<?php
class TraceableSignature {
private $privateKey;
private $publicKey;
private $traceKey; // 追踪密钥
private static $signerRegistry = [];
public function __construct($userId) {
$this->generateKeys();
$this->userId = $userId;
}
private function generateKeys() {
// 生成主密钥对
$config = [
'private_key_type' => OPENSSL_KEYTYPE_EC,
'curve_name' => 'prime256v1'
];
$res = openssl_pkey_new($config);
openssl_pkey_export($res, $this->privateKey);
$details = openssl_pkey_get_details($res);
$this->publicKey = $details['key'];
// 生成追踪密钥(用于身份揭示)
$this->traceKey = bin2hex(random_bytes(32));
}
// 生成可追踪签名
public function sign($message, $traceAuthority = null) {
// 生成加密的身份标签
$identityTag = $this->encryptIdentity($message);
// 生成签名
$signatureData = [
'message' => $message,
'identity_tag' => $identityTag,
'timestamp' => time()
];
$dataToSign = json_encode($signatureData);
openssl_sign($dataToSign, $signature, $this->privateKey, OPENSSL_ALGO_SHA256);
$signedDoc = [
'signature_data' => $signatureData,
'signature' => base64_encode($signature),
'signer_public_key' => $this->publicKey
];
// 注册签名者信息(用于追踪)
if ($traceAuthority) {
self::$signerRegistry[$identityTag] = [
'user_id' => $this->userId,
'trace_key' => $this->traceKey,
'timestamp' => time()
];
}
return $signedDoc;
}
// 加密身份信息
private function encryptIdentity($message) {
$identityInfo = json_encode([
'user_id' => $this->userId,
'public_key' => $this->publicKey
]);
// 使用消息和追踪密钥生成加密标签
$iv = openssl_random_pseudo_bytes(16);
$encrypted = openssl_encrypt(
$identityInfo,
'aes-256-cbc',
$this->traceKey,
0,
$iv
);
return base64_encode($iv . $encrypted);
}
// 追踪签名者身份(需要追踪权限)
public function traceSignature($signedDoc, $traceAuthorityKey) {
$identityTag = $signedDoc['signature_data']['identity_tag'];
// 检查追踪权限
if (!isset(self::$signerRegistry[$identityTag])) {
return null;
}
$registry = self::$signerRegistry[$identityTag];
// 解密身份信息
$data = base64_decode($identityTag);
$iv = substr($data, 0, 16);
$encrypted = substr($data, 16);
$decrypted = openssl_decrypt(
$encrypted,
'aes-256-cbc',
$registry['trace_key'],
0,
$iv
);
return json_decode($decrypted, true);
}
// 验证签名
public function verify($signedDoc) {
$signatureData = $signedDoc['signature_data'];
$dataToVerify = json_encode($signatureData);
$signature = base64_decode($signedDoc['signature']);
$verification = openssl_verify(
$dataToVerify,
$signature,
$signedDoc['signer_public_key'],
OPENSSL_ALGO_SHA256
);
return $verification === 1;
}
}
// 使用示例
$user1 = new TraceableSignature("user_001");
$user2 = new TraceableSignature("user_002");
$message = "交易记录 #12345";
// 用户1签名
$signedDoc1 = $user1->sign($message, "trace_authority");
echo "签名1验证: " . ($user1->verify($signedDoc1) ? "有效" : "无效") . "\n";
// 用户2签名
$signedDoc2 = $user2->sign($message, "trace_authority");
// 追踪签名者身份
$tracedIdentity = $user1->traceSignature($signedDoc1, "trace_key");
echo "追踪到的用户ID: " . $tracedIdentity['user_id'] . "\n";
完整的区块链签名系统
<?php
class BlockchainSignatureSystem {
private $signers = [];
private $signedDocuments = [];
private $traceKeys = [];
// 注册签名者
public function registerSigner($userId) {
$signer = new TraceableSignature($userId);
$this->signers[$userId] = $signer;
return $signer;
}
// 签名文档
public function signDocument($userId, $document, $traceable = false) {
if (!isset($this->signers[$userId])) {
throw new Exception("用户未注册");
}
$signedDoc = $this->signers[$userId]->sign($document, $traceable);
$docId = hash('sha256', json_encode($signedDoc));
$this->signedDocuments[$docId] = [
'document' => $signedDoc,
'timestamp' => time(),
'userId' => $userId
];
return $docId;
}
// 检查签名链接性
public function checkLinkability($docId1, $docId2) {
$doc1 = $this->signedDocuments[$docId1] ?? null;
$doc2 = $this->signedDocuments[$docId2] ?? null;
if (!$doc1 || !$doc2) return false;
// 检查是否来自同一用户
return $doc1['userId'] === $doc2['userId'];
}
// 追踪文档签名者
public function traceDocument($docId, $authorityKey) {
if (!isset($this->signedDocuments[$docId])) {
return null;
}
$doc = $this->signedDocuments[$docId];
$signer = $this->signers[$doc['userId']];
return $signer->traceSignature(
$doc['document'],
$authorityKey
);
}
// 验证文档签名链
public function verifySignatureChain($docIds) {
$results = [];
foreach ($docIds as $i => $docId) {
if (!isset($this->signedDocuments[$docId])) {
$results[] = false;
continue;
}
$doc = $this->signedDocuments[$docId];
$signer = $this->signers[$doc['userId']];
$results[] = $signer->verify($doc['document']);
}
return $results;
}
}
// 完整示例
$system = new BlockchainSignatureSystem();
// 注册用户
$alice = $system->registerSigner("alice_001");
$bob = $system->registerSigner("bob_002");
// 签名文档
$doc1 = $system->signDocument("alice_001", "合同A", true);
$doc2 = $system->signDocument("alice_001", "合同B", true);
$doc3 = $system->signDocument("bob_002", "合同C", true);
// 检查链接性
echo "文档1和文档2是否由同一人签名: " .
($system->checkLinkability($doc1, $doc2) ? "是" : "否") . "\n";
echo "文档1和文档3是否由同一人签名: " .
($system->checkLinkability($doc1, $doc3) ? "是" : "否") . "\n";
// 验证签名链
$chainVerification = $system->verifySignatureChain([$doc1, $doc2, $doc3]);
print_r($chainVerification);
安全最佳实践
<?php
class SecureSignatureSystem {
// 密钥管理
private function secureKeyStorage($privateKey, $userId) {
// 使用加密存储
$encryptedKey = openssl_encrypt(
$privateKey,
'aes-256-gcm',
hash('sha256', $this->masterKey),
0,
$iv,
$tag
);
// 存储到安全数据库
return [
'encrypted_key' => base64_encode($encryptedKey),
'iv' => base64_encode($iv),
'tag' => base64_encode($tag)
];
}
// 防重放攻击
private function preventReplay($signature) {
$nonce = bin2hex(random_bytes(16));
$timestamp = time();
$signedData = [
'signature' => $signature,
'nonce' => $nonce,
'timestamp' => $timestamp
];
// 检查时间戳
if (abs(time() - $timestamp) > 300) { // 5分钟过期
throw new Exception("签名已过期");
}
return $signedData;
}
// 审计日志
private function auditLog($action, $details) {
$logEntry = [
'timestamp' => time(),
'action' => $action,
'details' => $details,
'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown'
];
// 写入安全审计日志
error_log(json_encode($logEntry), 3, '/var/log/signature_audit.log');
}
}
项目集成建议
- 使用成熟的加密库:如
phpseclib或sodium扩展 - 密钥管理:使用硬件安全模块(HSM)或密钥管理服务
- 性能优化:使用缓存和批量处理
- 合规性:遵循相关法规(如eIDAS、GDPR)
- 监控告警:设置异常签名检测
这个实现提供了可链接签名和可追踪签名的完整解决方案,适用于数字货币、电子合同、身份验证等场景。