3、数字签名概念:公私钥体系

聊到日志防篡改,数字签名是跑不掉的核心。你想想看,一条日志从产生到存储,中间经过好几个环节,怎么保证它没被人动过?数字签名就是干这个的。

我个人理解,数字签名其实就是现实世界里“亲笔签名”的电子版。只不过现实里签的是名字,电子世界里签的是——数学。

3.1 公私钥体系,说白了就是两把钥匙

公钥和私钥,是一对天生配对的数学钥匙。我给你打个比方:

  • 私钥:你自己保管的,谁也不能给。它是签名用的。
  • 公钥:公开出去的,谁都可以拿。它是验签用的。

我在项目中遇到过好几次,有人把私钥和公钥混着用,结果签名验签死活对不上。这里我强调一下:私钥签名,公钥验签,方向一定是固定的。

3.2 签名过程到底做了什么?

数字签名不是直接把内容加密。它有一套固定的流程。我习惯把它拆成三步:

  1. 哈希计算:对原始日志内容,跑一次哈希算法(比如SHA-256),得到一个固定长度的“摘要”。
  2. 私钥加密:用自己的私钥,对这个摘要进行加密。加密后的结果,就是签名。
  3. 附加输出:把原始日志 + 签名,一起存起来或发送出去。

你看,签名其实只加密了摘要,没加密原文。所以日志内容本身是明文的,任何人都能读。但签名是加密的,只有拿着对应公钥的人才能验。

// 伪代码示意:签名生成
digest = SHA256(log_content)
signature = RSA_private_encrypt(digest, private_key)
output = log_content + signature

3.3 验签过程,是签名的逆运算

验签就是反过来走一遍:

  1. 拆分:从收到的数据里,把原始日志和签名分开。
  2. 哈希原文:对原始日志,跑同样的哈希算法,得到摘要A。
  3. 公钥解密签名:用公钥解密签名,得到摘要B。
  4. 比对:如果摘要A == 摘要B,说明日志没被篡改,签名有效。

我曾经排查过一个线上问题,验签一直失败。查了半天,发现是验签时用了不同的哈希算法。嗯,这里要注意:签名时的哈希算法,必须和验签时完全一致。

// 伪代码示意:签名验证
digest_A = SHA256(received_log)
digest_B = RSA_public_decrypt(received_signature, public_key)
if (digest_A == digest_B) {
    // 签名有效
} else {
    // 数据被篡改或签名无效
}

3.4 公钥体系的两个核心特性

特性 说明
防抵赖性 私钥只有你一个人有,签名就是你发的,赖不掉。
完整性 日志内容一改,哈希值就变,验签必失败。

你想想看,这两个特性对日志存储多重要。日志一旦被改,马上能发现。谁改的,也能查到。

3.5 签名 ≠ 加密,别搞混了

很多人刚接触公私钥体系时,会把数字签名和数字加密搞混。我早期做项目时也踩过这个坑。

数字签名:私钥签名,公钥验签。目的是防篡改、防抵赖。内容本身可以是明文的。

数字加密:公钥加密,私钥解密。目的是保密。内容不能被别人看到。

我们做日志签名防篡改,用的是数字签名。日志内容不需要保密,但绝不能被人偷偷改掉。

3.6 实际项目中的密钥管理要点

私钥泄露 = 信任崩塌

私钥一旦泄露,别人就可以冒充你签名。所有已签名的日志,都可能被重新签名。我在项目中见过,因为私钥存成了明文文本文件,被开发同学git push上去了……那个项目后来全部重置。

建议做法

私钥放入硬件安全模块(HSM)或密钥管理服务(KMS)。代码里只引用密钥ID,不接触私钥原文。

3.7 签名算法的选型建议

算法不是越强越好,要看场景和性能。我个人常用的几种:

算法 签名长度 性能 推荐场景
RSA-2048 256字节 适中 通用场景,兼容性好
ECDSA P-256 64字节 较快 高并发、嵌入式场景
Ed25519 64字节 很快 区块链、高性能需求

做日志签名,日志量大的话,我建议优先考虑ECDSA或Ed25519。签名短、计算快,存储和带宽压力都小。

3.8 本章知识结构图

下面的SVG图,画的是数字签名的核心流程:签名与验签。你一眼就能看明白公私钥的角色。

数字签名核心流程 发送方 私钥 (签名) 原始日志 哈希算法
(SHA-256) 签名 传输 日志 + 签名 接收方 公钥 (验签) 提取日志 哈希算法
(SHA-256)
比对摘要 通过 / 失败

记住一句话

私钥签名是“你是谁”的证明,公钥验签是“你说了算不算”的检查。日志防篡改,全靠这套机制。