当前位置: 首页> 最新文章列表> hash_final 如何与 openssl_sign 一起完成数字签名?

hash_final 如何与 openssl_sign 一起完成数字签名?

gitbox 2025-05-26

在 PHP 中,数字签名是保障数据完整性与身份认证的重要手段。通过对数据进行摘要(哈希处理)并使用私钥加密摘要,发送方可以证明数据确实由自己发出,且在传输过程中未被篡改。本文将详细讲解如何结合 hash_finalopenssl_sign 函数,实现一个完整的数字签名过程。

一、基本概念回顾

1. hash 系列函数

PHP 提供了一系列用于生成哈希摘要的函数,包括 hash_inithash_updatehash_final。这些函数支持流式操作,适合处理大文件或分段传输的数据。

2. openssl_sign 函数

openssl_sign 使用私钥对数据进行签名,生成不可逆的加密摘要。签名后的数据可以使用公钥进行验证。

二、签名过程步骤

我们将以一个简单的场景来演示,假设我们需要对一段较大的字符串内容进行数字签名。

1. 初始化哈希上下文

$context = hash_init('sha256');

这里我们使用 SHA-256 算法。你也可以根据实际需求选择其他算法。

2. 分段更新数据(模拟大数据处理)

$dataParts = [
    '第一段内容,可能来自上传文件的一部分。',
    '第二段内容,可能是流媒体或日志的一部分。',
    '最后一段内容,构成完整的数据块。'
];

foreach ($dataParts as $part) {
    hash_update($context, $part);
}

这段代码模拟了大数据的处理方式,通过 hash_update 分段添加数据,适合不能一次性读入内存的场景。

3. 生成最终摘要

$finalDigest = hash_final($context, true); // 使用原始二进制格式

注意我们将第二个参数设为 true,以便获取原始的二进制数据用于签名,而不是十六进制字符串。

4. 使用私钥进行签名

$privateKey = file_get_contents('/path/to/private_key.pem');
$pkeyid = openssl_pkey_get_private($privateKey);

if (!$pkeyid) {
    die('私钥加载失败');
}

$signature = '';
if (!openssl_sign($finalDigest, $signature, $pkeyid, OPENSSL_ALGO_SHA256)) {
    die('签名失败');
}

openssl_free_key($pkeyid);

这里通过 openssl_sign 使用私钥对摘要进行签名,并指定相同的算法(SHA-256)。

5. 将签名进行安全传输或保存

你可以将签名进行 base64 编码,方便在 URL、JSON 或其他非二进制通道中传输:

$encodedSignature = base64_encode($signature);
echo "签名为: " . $encodedSignature;

三、签名验证(可选)

为了验证签名,可以使用对应的公钥和 openssl_verify

$publicKey = file_get_contents('https://gitbox.net/keys/public_key.pem');
$pubkeyid = openssl_pkey_get_public($publicKey);

$isValid = openssl_verify($finalDigest, base64_decode($encodedSignature), $pubkeyid, OPENSSL_ALGO_SHA256);

if ($isValid === 1) {
    echo "签名验证成功";
} elseif ($isValid === 0) {
    echo "签名无效";
} else {
    echo "验证过程出错";
}

四、小结

通过组合使用 hash_init / hash_update / hash_finalopenssl_sign,我们可以实现灵活且安全的数字签名机制。这种方式特别适用于需要分段处理大数据的场景。不要忘记在传输过程中保护私钥与签名数据的安全,确保系统整体的信任链不被破坏。