本节摘要:数字签名用私钥对消息摘要做单向变换,任何人可用对应公钥验证——它同时交付完整性、认证性与不可否认性,是证书、代码签名与区块链交易的地基。本节拆解"哈希再签"的闭环,对比它与 MAC 的分工,并用 ECDSA 的随机数血案说明:签名算法里最不起眼的一个随机数,足以让人一夜丢掉全部私钥。
手写签名的法律效力来自笔迹的唯一性,数字签名的安全效力来自一个更硬的事实:**只有私钥持有者才能算出合法签名,而任何人都能用公钥验证它。**流程分两步走:发送方先对消息算哈希(通常是 SHA-256 摘要),再用私钥对摘要做变换,得到签名值,随消息一起发出;接收方独立计算消息哈希,并用发送方公钥解验签名、比对两个摘要——一致则签名有效。
为什么签哈希而不直接签消息?两个现实原因:其一,签名算法(RSA、ECDSA)只能处理固定长度的小数据,哈希把任意长度的消息压成固定摘要;其二,先哈希后签让签名成本与消息长度解耦,签一部电影和签一句话成本相同。哈希的碰撞抵抗(第 5 章展开)在此处是安全前提——若能构造两份哈希相同的消息,就能让对 A 的签名"平移"给 B。

签名与 3.5 节的 MAC 都能验出"消息没被改、确实来自自己人",分界线在验证权:MAC 的验证需要同一把共享密钥,能验的人就能签——收发双方地位对称,谁也不能向第三方证明"这是你签的";签名则把"签"与"验"分离,公钥全网可取,任何第三方(法官、应用商店、全网节点)都能独立验证。于是三条安全属性在此闭环:完整性(摘要比对)、认证性(只有私钥能产出可验签名)、不可否认性(签名者无法辩称"验证公钥对应的私钥不在我手里")。这三条正是证书、软件分发与区块链交易的共同底座——比特币每笔交易就是一个 ECDSA 签名,验证不过全网不认。
现实部署的主流家族有三支:RSA-PSS(4.2 节的老将,签名方向配概率签名填充);ECDSA(下一代的紧凑选择,基于曲线群);EdDSA(Ed25519,伯恩斯坦家族的答案)。
ECDSA 有个致命的内部随机数 k(每次签名现场生成)。它的要害在于两条铁律——绝不能重复,绝不能泄露。数学上,两次签名的结果 s₁、s₂ 与同一个 k 满足线性关系,相减即可解出 k,再用任一签名公式反解出长期私钥。
历史教训不是思想实验。2010 年,索尼 PlayStation 3 的代码签名私钥被静态写死在固件里(不全是 k 的问题,但同属签名工程失误),导致任何人都能以官方身份给主机签代码;同年起研究者多次演示"k 重用即丢钥"的完整攻击。2013 年 8 月,安卓系统随机数发生器的缺陷让多个比特币钱包应用对同一交易签出了重复 k,攻击者数小时内从链上扫走若干地址的全部余额——每一起事故的数学剧本完全一致。标准化组织给出的根治方案有两条,本质上都是"把随机性从关键路径上赶出去":RFC 6979 规定 k 由私钥与消息哈希经 HMAC 确定性派生(同消息必同 k、不同消息必不同 k,且永不暴露);EdDSA 走得更彻底,从设计之初就把确定性 nonce 写进算法本体。
# 用小素域演示"k 重用泄露私钥"的核心代数(玩具参数,非真实 ECDSA) p = 10007 # 玩具素域 h1, h2 = 1234, 5678 # 两份消息的摘要 x = 4242 # 签名者的私钥(攻击者未知) k = 999 # 危险:两次签名共用同一个 k def toy_sign(h, k): s = (k - h * x) % p # 玩具签名式:s = k - h·x return s s1, s2 = toy_sign(h1, k), toy_sign(h2, k) # 攻击者视角:s1 - s2 = h2*x - h1*x = x*(h2 - h1),无需 k 即解出私钥 x_cracked = (s1 - s2) * pow(h2 - h1, -1, p) % p print(x_cracked) # -> 4242,私钥当场还原
这段玩具代码只用一行减法就完成屠杀——真实 ECDSA 的公式稍复杂,但漏洞的代数结构一模一样。
⚠️ 常见坑:自实现签名算法几乎必然栽在 nonce 上。正确的工程姿势只有一种:使用成熟库,并优先选择 EdDSA 或 RFC 6979 风格的确定性签名。
验签失败的常见原因,按出现频率排序:用错了公钥(密钥对配错,或换了钥匙忘了换证书);消息在传输中被规范化改变(换行符、编码、字段顺序的细微差异都会改变摘要,签名与验证双方必须对完全相同的字节序列负责);哈希算法不一致(一方 SHA-256 一方 SHA-1);证书链或有效期问题。排错的正确姿势是把双方算出的摘要直接打印对比,一步定位是"消息不同"还是"密钥不对"。
问答一:签名有法律效力吗?多数司法辖区已有电子签名立法,基于可靠数字证书的签名在指定场景具备与手写同等的效力。工程上还需要可信时间戳为签名加注时间,否则"不可否认"难以对抗"私钥早已泄露"的抗辩。
问答二:多人共签怎么办?多重签名结构(多把私钥各自签署同一文档)与门限签名(若干份私钥碎片合作产出一个签名)都已成熟,前者常见于合规审批流,后者是 6.5 节多方安全计算技术的直接应用。
RSA-PSS 配 SHA-256 是证书体系的老组合,兼容性最好;ECDSA(P-256 曲线)配 SHA-256 是证书与协议的紧凑之选;Ed25519 自带内部哈希(SHA-512),签名短、验签快且无随机数隐患,是新系统的默认推荐。搭配的原则只有一条:哈希输出长度要与签名安全强度匹配——256 位的哈希配 128 位强度的曲线刚好,配更弱的曲线则浪费。工程实现一律走标准库的组合常量,不自由拼接。
至此,公钥革命的两大遗产——协商与签名——全部就位。但签名验的是"这把公钥配这把私钥",还差一环:"这把公钥真的属于那个域名吗?"下一章的哈希与第六章的证书链将补完这最后一环。