1. 数字签名基础:定义、作用与核心原理

数字签名这东西,说白了就是现实世界里手写签名的电子版。但你别小看它——它解决的问题可比手写签名多得多。

我刚开始接触密码学时,总觉得数字签名就是个「加密的逆过程」。后来踩了坑才明白,事情没那么简单。咱们今天就把这块地基打扎实。

1.1 数字签名到底是个啥?

官方定义我就不念了。用我的话讲:数字签名是一段附着在数据上的密码学凭证,它能证明三件事——你是谁、数据没被人动过、你没法事后抵赖。

你想想看,现实中的签名能伪造吧?能复印吧?能被人模仿笔迹吧?数字签名把这些漏洞全堵死了。

核心三要素:

  • 真实性(Authentication)—— 确认签名者的身份
  • 完整性(Integrity)—— 数据没被篡改
  • 不可否认性(Non-repudiation)—— 签名者无法抵赖

我记得有一次做金融系统的安全审计,对方技术负责人问我:「我们用了 HTTPS,为什么还要单独做签名?」我反问他:「HTTPS 能证明这笔交易是你发的吗?」他愣了一下,懂了。HTTPS 只保传输,不保来源。

1.2 公钥密码体系:不对称才是王道

数字签名依赖的是公钥密码体系(也叫非对称密码)。跟咱们平时用的 AES 这类对称密码不一样,它有两把钥匙:

角色 密钥 用途
签名者 私钥(自己保管) 生成签名
验证者 公钥(公开分发) 验证签名

这里有个关键点:私钥签名,公钥验签。跟加密正好反过来——加密是公钥加密、私钥解密。

我在项目中见过不少新手搞混这个逻辑。有人问我:「为什么签名不用公钥?」我告诉他:「如果公钥能签名,那所有人都能冒充你发消息了。」

1.3 哈希函数:数字签名的「压缩器」

直接对整份文件做签名,效率太低了。一份 1GB 的视频,你总不能拿私钥去算 RSA 吧?那得算到猴年马月去。

所以实际做法是:先对数据做哈希,再对哈希值签名。

哈希函数有几个硬性要求:

  • 单向性:从哈希值推不出原文
  • 抗碰撞性:找不到两个不同数据有相同哈希值
  • 固定输出长度:不管输入多大,输出都是固定长度(比如 SHA-256 就是 256 位)

避坑指南:我曾经遇到过团队用 MD5 做签名哈希,理由是「快」。我当场就让他们改了。MD5 的碰撞攻击早在 2004 年就被公开了,用 MD5 做签名等于没做。现在最低标准是 SHA-256,别省这点性能。

1.4 签名与验签的完整流程

咱们走一遍标准流程,你感受一下:

签名过程(发送方):

  1. 对原始数据计算哈希值 H
  2. 用私钥对 H 加密,得到签名 S
  3. 把原始数据 + 签名 S 一起发给对方

验签过程(接收方):

  1. 用同样的哈希算法计算收到的原始数据的哈希值 H'
  2. 用发送方的公钥解密签名 S,得到 H
  3. 比较 H 和 H' 是否相等

如果相等,说明数据没被改过,而且确实是私钥持有者签的。

注意:这里有个常见的坑——有人直接把签名结果当成「加密后的数据」来理解。不对。签名不是加密,它不隐藏数据内容,只提供验证凭证。数据本身还是明文传输的。

1.5 知识体系总览

下面这张图把数字签名的核心逻辑串起来了。我建议你多看两眼,后面所有漏洞排查都建立在这个框架上。

数字签名核心逻辑框架图 数字签名核心逻辑框架 签名方(私钥持有者) 原始数据 M 哈希函数 H() 私钥 SK 签名 S 传输 M + S 验证方(公钥持有者) 哈希函数 H() 公钥 PK 哈希值 H' 解密得 H 比较 H' 与 H 是否相等 相等 → 验证通过 ✅ 不相等 → 验证失败 ❌ 核心原则:私钥签名、公钥验签;哈希保证完整性,非对称密码保证真实性与不可否认性 常见哈希:SHA-256 | 常见算法:RSA、ECDSA、EdDSA

1.6 常见算法对比

实际项目中选哪个算法,得看场景。我列个对比表,你选型时直接参考:

算法 签名长度 性能 安全性 典型场景
RSA-2048 256 字节 中等 高(需足够密钥长度) 传统系统、PKI
ECDSA P-256 64 字节 快 高 移动端、IoT
Ed25519 64 字节 极快 极高 现代系统、区块链
SM2 64 字节 快 高(国密标准) 国内合规场景

我的建议:新项目直接上 Ed25519。签名短、性能好、安全性高,而且实现上不容易踩侧信道攻击的坑。RSA 虽然成熟,但密钥太长,签名也长,移动端体验不好。

1.7 一个常见的误解

有人觉得:「数字签名 = 加密的哈希值」。这个说法不准确。

真正的签名算法(比如 ECDSA)不是简单地对哈希值做「加密」。它有自己的数学结构。RSA 签名看起来像「私钥加密」,但那是 RSA 的特殊性质,不能推广到所有算法。

我见过有人用 RSA 的思路去理解 ECDSA,结果在实现验签逻辑时写错了参数顺序——公钥当私钥用,验签永远失败。排查了两天才找到原因。

记住:签名和加密是两个不同的操作。不要混用 API。OpenSSL 里签名用 EVP_DigestSign*,加密用 EVP_Seal*,接口都不一样。

1.8 小结

数字签名的基础就这些。说白了就是三样东西:私钥签名、公钥验签、哈希保完整。后面咱们讲漏洞排查时,所有问题都绕不开这三个环节——密钥泄露、哈希碰撞、验签逻辑缺陷。

嗯,地基打好了,后面就好办了。