数字签名 = 先对内容算哈希,再用自己的私钥签那个哈希——它要证明的不是"内容没被看到",而是"内容是谁发的、有没有被改";这两件事必须分清,因为实现它们的算法完全一样。
5-3 已经埋下了伏笔:"公钥加密/私钥解密"是保密,"私钥签名/公钥验证"是认证——同一对钥匙,用法反过来。 5-5 补上了另一块:签名签的其实是哈希,不是原文。
这一节就是把这两块拼起来。拼好之后你会发现,本章后面一半的内容(证书、HTTPS、代码签名、邮件签名)用的都是这同一个结构。
一、四步流程:先摘要,再签名
数字签名(digital signature)的流程固定为四步:
- 对内容算哈希 —— 几百 MB 的文件变成 32 字节的指纹;
- 用自己的私钥"加密"这个指纹 —— 得到的这串东西就是签名;
- 把【原内容 + 签名】一起发出去;
- 对方用你的公钥解开签名得到指纹,再对收到的内容算一次哈希 —— 两个指纹一致,就同时说明了两件事:内容没被改过,而且这份内容确实出自持有对应私钥的人。
第 2 步为什么要绕一圈去签哈希,而不是直接签原文? 因为签名运算很贵(5-7 会实测它有多贵),而哈希把任意长度的内容压缩成固定 32 字节——于是"签一份 1 GB 的文件"和"签一句话"的成本完全一样。
二、动手 Demo:签名、验证、和一次篡改
priv = "PRIVATE-KEY-1307" # 只有签名者持有
doc = "转账 100 元给 alice"
h = hashlib.sha256(doc.encode()).hexdigest() # ① 算摘要
sigv = hashlib.sha256((h + priv).encode()).hexdigest()[:32] # ② 用私钥签摘要
# 三、篡改:把 100 改成 900
doc2 = "转账 900 元给 alice"
h2 = hashlib.sha256(doc2.encode()).hexdigest()
sig2 = hashlib.sha256((h2 + priv).encode()).hexdigest()[:32]
实跑输出:
一、四步流程
① 对内容算哈希 内容 → 定长指纹
② 用【自己的私钥】加密这个指纹 指纹 → 签名
③ 把【内容 + 签名】一起发出去
④ 对方用【你的公钥】解开签名得到指纹,再对收到的内容算一次哈希,
两个指纹一致 → 内容没被改,而且确实是你发的
二、实际算一遍
内容 转账 100 元给 alice
内容哈希 c613e35eb7dad98a8e890e124b8b92bc...
签名 a5aa03ecbb5ee85716ed830682153156
对方收到后:重新算内容的哈希 → c613e35eb7dad98a8e890e124b8b92bc...
再用公钥验证签名 → 通过
三、改一个字符,签名立刻对不上
被改的内容 转账 900 元给 alice
新算的签名 bfafa9d163c0b0f6c23fcf000e7b0479
原来的签名 a5aa03ecbb5ee85716ed830682153156
→ 不一致(100 变成 900,签名完全变样)
改的人如果没有私钥,就算把内容改了,也造不出匹配的新签名。
四、三个概念别混:哈希、加密、签名
技术 回答什么问题 用不用密钥
哈希 内容有没有变 不用(谁都能算)
加密 内容能不能被人看到 用(收件人的公钥)
签名 是谁发的、有没有变 用(发件人的私钥)
→ 一句话:加密解决【保密】,签名解决【认证】,哈希解决【完整性】。
五、为什么先哈希再签,而不是直接签原文
· 原文可能几百 MB,哈希只有 32 字节:签名成本与内容长度无关
· 同一份内容用哈希再签,签名长度固定,便于存档与比对
· 反过来说:只要哈希算法被攻破(如 MD5、SHA-1),
基于它的签名也一起失效——这就是【加密的危殆化】。
六、电子签名不是数字签名(法律概念 vs 技术概念)
说法 属于 含义
电子签名 法律概念 电子形式的签名行为,范围很宽(含手写签名扫描件等)
数字签名 技术概念 必须用密码学实现,可验证、不可抵赖
→ 法律上认可的【可靠电子签名】,通常要求落在数字签名这一类上。
读这个输出:
- 第二段和第三段连起来看,就是签名能提供的全部保证:内容改一个字,摘要全变,签名也就对不上。而"改的人造不出匹配的新签名"这一句才是关键——它不是因为签名算法难,而是因为对方没有私钥。
- 第四段那张表建议背下来。现实中最常见的混乱就是把这三种目的搞混:用加密去代替签名(以为别人看不见就等于别人不能伪造),或者用签名去代替加密(以为签了名内容就保密了)。它们解决的是完全不同的问题,而且通常需要同时使用。
- 第六段是一个容易被忽略、但在实际业务里很重要的区分:"电子签名"是法律概念,"数字签名"是技术概念。扫描一份手写签名贴进 PDF,法律上可能构成电子签名;但它不是数字签名,因为任何拿到这个图片的人都能复制粘贴——不会留下"是谁签的、内容有没有被改"的密码学证据。
三、签名与加密的分工:一张对照表
| 谁用钥匙 | 谁验证 | 保护什么 | |
|---|---|---|---|
| 加密 | 发送方用接收方的公钥 | 接收方用私钥 | 保密:中途没人看得懂 |
| 签名 | 发送方用自己的私钥 | 任何人有发送方公钥就能验 | 认证 + 完整性:是谁发的、有没有改 |
一个常被忽略的推论:签名不提供保密性。一份签了名的文件仍然是明文——任何人都能读,只是改不了、也冒充不了。所以真实业务里经常是"先签名、再加密"或者"既签名又加密",两者叠加使用。
四、⚠️ 2026 现状
- 【签名的算法选型已经和加密算法分开考虑了】。 Ed25519(椭圆曲线签名)是 2026 年新场景的默认选择:签名快、密钥小(公钥约 68 字节)、而且签名值具有确定性。而 ECDSA 有一个实现层面的坑必须知道:它每次签名都依赖一个随机数,随机数一旦被重用或可预测,私钥会直接暴露(2010 年索尼 PS3 的签名密钥就是这么被还原的)。Ed25519 从设计上抹掉了这个失败模式。
- 【签名的"长期有效性"问题已经有了成熟的解法,叫时间戳】。 证书有效期只有几年,但一份签名的软件或文档可能要验十几年——如果只按"当前时间"判断,证书一过期,所有旧签名会集体失效。解法是给签名加时间戳:由时间戳服务证明"这个签名是在证书还有效的时候做的"(详见 5-13)。你看到下载页写"已签名并加时间戳",就是这件事。
- 【"不可抵赖"这个法律效力是有前提的,前提是私钥没被共享】。 数字签名的法律效力建立在"私钥只有本人持有"这个假设上。如果私钥被复制、共享给了同事、或者存在一个没有口令保护的笔记本里——"这件事是你做的"这个主张就站不住了。所以工程实践里,"私钥保护"(硬件模块、口令保护、按人分发、可单独吊销)不是可选项,它是签名有效性的组成部分(这一点在 5-12 讲 SSH 密钥管理和客户证书时会展开)。
- 【后量子时代,签名算法的替换比加密更麻烦】。 NIST 的后量子签名标准是 ML-DSA(FIPS 204)与 SLH-DSA(FIPS 205)——代价是体积:ML-DSA-65 的签名约 3,309 字节,而 ECC 签名只有 64~72 字节(约 46 倍)。这个体积会传导到证书链大小、握手数据量、以及硬件安全模块的吞吐能力上。所以签名的迁移不是"换个名字",而是一串工程改造(5-9)。
30 秒实验
今天做两个动作,各 15 秒:
- 随便找一封带"数字签名"的邮件或文件(很多办公软件导出 PDF 时可以签名),看一眼它的签名属性面板:你会看到"签名者""签名时间""证书颁发者"这几栏。这一眼就把本节抽象的流程变成了具体界面——"签名者"就是你刚才理解的私钥持有者,"证书颁发者"是 5-4 的 CA。
- 想一个场景并回答:如果你把一份文件签了名发给对方,对方能不能读到内容?——能,签名不保密。那对方能不能改成别的金额再转发出去?——不能,改一个字签名就对不上。这两个答案合起来,就是"签名"和"加密"的分界线。
这一节要带走的一句是:加密保护的是"别人看不见",签名保护的是"别人赖不掉"——数字签名做的事,是把一个只有你能做的动作,变成一个全世界都能验证的证据。
常见误区
-
错误:签名就是把文件内容加密一遍。——纠正:签名不加密,文件是明文。准确的说法是"对内容的摘要做一次只有私钥能做的运算"——任何人拿到你的公钥都能验证这个签名,但没有任何人能伪造一个新的。这个区别的实用后果很直接:如果你需要内容保密,签名完全不够,还得另外加密(5-7);反过来,如果你只需要证明"是谁发的、有没有改",加密又是多余的。看清目的再选工具,别把两者混为一谈。
-
错误:有了数字签名,内容就一定是安全可信的。——纠正:签名证明的是"来源"和"完整",不证明"内容本身是善意的"。一个攻击者完全可以拿自己合法申请的证书,给一段恶意代码签名——签名验证全部通过。这正是真实世界里恶意软件常见的形态:"有签名"只说明"这不是中途被替换的版本",不代表"这个东西值得信任"。判断是否可信,还要看签名者是谁、以及这个签名者本身是否可信(5-13 会讲到代码签名的这个边界)。
-
错误:扫描一张手写签名贴到文件上,就等于完成了数字签名。——纠正:这是"电子签名"和"数字签名"的混淆。贴一张图片,任何人复制粘贴就完成了"伪造",而且改内容也不会留下痕迹——它没有密码学上的任何保证。数字签名必须由密码学实现:摘要 + 私钥运算。这其中有实际的法律差别:法律上认可的"可靠电子签名"(比如我国《电子签名法》的语境)通常要求满足密码学验证、身份可确认、内容改动可发现这几条——一张图片签名给不了这几条保证。
-
错误:验证签名需要把我的公钥保密地交给对方。——纠正:恰恰相反,公钥就是要公开的。签名的验证设计成"任何人都能做"——这正是它能被用作证据的原因:不需要额外的信任前提,只要有你的公钥,谁都能验证。 需要保密的只有私钥(它决定谁能"签")。这也是公钥的分发问题(5-3)能靠"直接公开"解决的原因——公开的是验证能力,保密的是签发能力。
自测三问(点开对答案)
1. 为什么签名要"先哈希再签"?直接签原文有什么问题? —— **直接签原文的问题是成本和长度**。**签名运算是大数模幂,价格按"运算次数"算**——**签一份 1 GB 的文件,如果直接签全文,就要把 1 GB 数据全部卷进这个昂贵的运算里**。**先算哈希把内容压成 32 字节,签名成本就与内容长度彻底脱钩**——**签一句话和签一部电影,价格一样。** **第二个好处是固定长度**:**签名值的大小是确定的,便于存档、比对、以及放进证书这类有长度约束的结构里**。**代价是"签名的安全性从此依赖哈希的抗碰撞性"**——**这也是 MD5、SHA-1 倒台时,所有基于它们的签名一起失效的原因**(5-5)。 2. "加密"和"签名"用的是同一套数学,为什么要分成两件事? —— **因为它们要回答的问题不同,而且这两个问题经常只有一个需要解决**。**加密回答"能不能被看见"**(**用接收方的公钥加密,只有接收方能解**);**签名回答"是谁发的、有没有被改"**(**用自己的私钥签,谁都能验,但谁都不能伪造**)。**实际场景里这两件事的出现频率不一样**:**软件发布、代码、文档只需要签名**(内容本来就是公开的,不需要保密);**而传输敏感数据只需要加密**(双方身份已经通过其他方式确认)。**把两者当成一件事,会同时犯两种错**:**用加密代替签名(以为"看不见"就等于"不能伪造"),或者用签名代替加密(以为"签了名"内容就保密了)。** 3. 为什么说"私钥保管不好,签名的法律效力就没了"? —— **因为数字签名能当证据,全部建立在"私钥只有本人持有"这个前提上**。**验证签名的逻辑是"只有持有私钥的人能生成这个签名",所以"看到这个签名"就可以推断"是那个人做的"**。**如果私钥被复制给了别人、写在没有口令保护的设备上、或者被前员工带走**——**这个推断就断了**:**签名仍然能验通过,但"是谁签的"已经无法确定**。**所以工程上对私钥的每一层保护——口令、硬件模块、按人分发、可单独吊销、定期轮换——都不是"额外的好习惯",而是签名有效性的组成部分**(这也是 5-12 里 SSH 密钥管理那一套做法的意义)。- ☐ 下一节(5-7 共享密钥加密与公开密钥加密的组合运用)
相关笔记
- 解决密钥分发问题的密码 —— 上一篇:同一对钥匙,用法反过来
- 防止数据被篡改的技术 —— 签名签的那个东西,就是哈希
- 共享密钥加密与公开密钥加密的组合运用 —— 下一篇:两种加密在真实系统里怎么分工
- 为软件添加数字签名 —— 同一套签名,落到软件发布流程里
- 🛡️ 网络与信息安全 · 索引 —— 全课路线图