后量子密码|前置基础 03|数字签名运行逻辑:签名签发、核验原理与实际业务应用

后量子密码|前置基础 03|数字签名运行逻辑:签名签发、核验原理与实际业务应用

专栏说明 :《后量子密码》专栏,本专栏面向零基础读者,循序渐进讲解后量子密码理论、NIST标准算法、攻击分析、工程落地与迁移实践。

https://blog.csdn.net/r_feynman_/category_13197405.html


前言

加密和签名经常同时出现在协议中,但目标不同:加密保护机密性,签名保护完整性并证明签发者身份。

数字签名通常不是"用私钥加密、用公钥解密"。更准确的理解是:签名者利用私钥构造一个只有自己能生成、但任何持有公钥的人都能检查的数学证明。

通俗区分:加密藏内容;签名盖防伪公章,不隐藏原文


一、数字签名的基本接口

1.1 生成密钥

( p k , s k ) ← K e y G e n ( 1 λ ) (pk,sk)\leftarrow KeyGen(1^\lambda) (pk,sk)←KeyGen(1λ)

K e y G e n KeyGen KeyGen:密钥生成算法

1 λ 1^\lambda 1λ:安全参数,λ越大破解难度越高

← \leftarrow ←:算法输出赋值

公钥 p k pk pk 可以公开,私钥 s k sk sk 必须保密。


1.2 签名与验证

签名者执行:

σ ← S i g n ( s k , M ) \sigma\leftarrow Sign(sk,M) σ←Sign(sk,M)

S i g n Sign Sign:签名函数; M M M:待签名原始消息

σ \sigma σ:最终生成的签名串(电子公章)

验证者执行:

V e r i f y ( p k , M , σ ) → { 0 , 1 } Verify(pk,M,\sigma)\rightarrow\{0,1\} Verify(pk,M,σ)→{0,1}

V e r i f y Verify Verify:校验函数;输出1=合法通过,0=篡改/伪造失败

如果消息被修改为 M ′ M' M′,通常应满足:

V e r i f y ( p k , M ′ , σ ) = 0 Verify(pk,M',\sigma)=0 Verify(pk,M′,σ)=0

实际系统中,签名算法通常先计算带域分离的摘要:

μ = H ( domain ∥ M ) \mu=H(\text{domain}\|M) μ=H(domain∥M)

再对 μ \mu μ 生成签名。域分离用于防止同一摘要在不同协议和不同用途之间混用。

domain \text{domain} domain:业务域标识,规避跨场景冒用攻击

μ \mu μ:消息哈希摘要,实际签名对象


二、格签名的抽象运行逻辑

2.1 公开关系

用一个简化的格签名关系表示:

t = A s 1 + s 2 ( m o d q ) \mathbf t=\mathbf A\mathbf s_1+\mathbf s_2\pmod q t=As1+s2(modq)

s 1 、 s 2 \mathbf s_1、\mathbf s_2 s1、s2:私钥核心秘密短向量

t \mathbf t t:公钥公开参数

真实算法会使用多项式模块和标准参数,但这条关系足以说明签名的逻辑。


2.2 生成承诺

签名者随机选择一个短向量:

y ← D y \mathbf y\leftarrow D_y y←Dy

y \mathbf y y:单次签名全新随机向量; D y D_y Dy:随机取值分布

并计算承诺:

w = A y \mathbf w=\mathbf A\mathbf y w=Ay

w \mathbf w w:承诺值,本次签名临时凭证

然后将消息和承诺哈希为挑战:

c = H ( M ∥ w ) \mathbf c=H(M\|\mathbf w) c=H(M∥w)

c \mathbf c c:挑战值,绑定消息与本次签名

最后计算响应:

z = y + c s 1 \mathbf z=\mathbf y+\mathbf c\mathbf s_1 z=y+cs1

z \mathbf z z:签名响应,依靠私钥才能算出

签名可以抽象成:

σ = ( z , c , 辅助信息 ) \sigma=(\mathbf z,\mathbf c,\text{辅助信息}) σ=(z,c,辅助信息)


2.3 验证者如何检查

验证者利用公钥计算:

w ′ = A z − c t \mathbf w'=\mathbf A\mathbf z-\mathbf c\mathbf t w′=Az−ct

w ′ \mathbf w' w′:验证端反向重构出的承诺

将:

t = A s 1 + s 2 ( m o d q ) \mathbf t=\mathbf A\mathbf s_1+\mathbf s_2\pmod q t=As1+s2(modq)

代入:

w ′ = A ( y + c s 1 ) − c ( A s 1 + s 2 ) = A y − c s 2 \begin{aligned} \mathbf w' &=\mathbf A(\mathbf y+\mathbf c\mathbf s_1)-\mathbf c(\mathbf A\mathbf s_1+\mathbf s_2)\\ &=\mathbf A\mathbf y-\mathbf c\mathbf s_2 \end{aligned} w′=A(y+cs1)−c(As1+s2)=Ay−cs2

验证者再根据标准规定的舍入、提示和压缩规则恢复承诺信息,并检查:

c = ? H ( M ∥ w ′ ) \mathbf c\stackrel?=H(M\|\mathbf w') c=?H(M∥w′)

= ? \stackrel?= =?:校验比对符号

等式成立=签名合法;不相等=消息篡改或签名伪造

如果签名者确实掌握合法的小秘密,重新构造出的挑战应当与签名中的挑战一致。


三、为什么要拒绝采样

如果总是公开:

z = y + c s 1 \mathbf z=\mathbf y+\mathbf c\mathbf s_1 z=y+cs1

而随机向量 y \mathbf y y 的分布较窄,响应 z \mathbf z z 的统计特征可能与秘密 s 1 \mathbf s_1 s1 相关。

直接输出z会泄露私钥的统计规律,攻击者可提取私钥

拒绝采样的做法是:

  1. 生成候选 y \mathbf y y;
  2. 计算 z \mathbf z z;
  3. 检查响应是否落入安全范围;
  4. 不符合条件就丢弃,重新采样。

这样可以减少签名分布对秘密的依赖。代价是签名操作可能需要多次尝试,参数和实现都必须经过严格设计。


四、签名与业务数据

4.1 软件发布

发布者对软件包摘要签名:

σ = S i g n ( s k , H ( package ) ) \sigma=Sign(sk,H(\text{package})) σ=Sign(sk,H(package))

用户使用发布者公钥验证:

V e r i f y ( p k , H ( package ) , σ ) = 1 Verify(pk,H(\text{package}),\sigma)=1 Verify(pk,H(package),σ)=1

如果安装包被替换,摘要发生变化,验证失败。

但公钥本身也需要建立信任,不能只下载一个陌生公钥就相信它属于官方。


4.2 API 请求签名

请求签名应覆盖真正影响业务结果的字段,例如:

M = method ∥ path ∥ timestamp ∥ nonce ∥ H ( body ) M=\text{method}\|\text{path}\|\text{timestamp}\|\text{nonce}\|H(\text{body}) M=method∥path∥timestamp∥nonce∥H(body)

timestamp时间戳、nonce随机串:用于抵御重放攻击

然后:

σ = S i g n ( s k , H ( M ) ) \sigma=Sign(sk,H(M)) σ=Sign(sk,H(M))

服务端除验证签名外,还要检查时间戳、nonce、权限和请求路径。签名本身不能自动防止重放,必须把防重放字段纳入签名范围。


4.3 证书体系

CA 可以对证书主体签名:

σ C A = S i g n ( s k C A , H ( certificate_body ) ) \sigma_{CA}=Sign(sk_{CA},H(\text{certificate\_body})) σCA=Sign(skCA,H(certificate_body))

验证者用 CA 公钥检查签名,再结合有效期、用途、吊销状态和信任链决定是否接受。

后量子迁移时,需要同时考虑证书签名、握手密钥交换和终端验证逻辑,不能只替换某一个算法名称。


五、常见误区

5.1 签名了摘要,不等于签名了所有业务语义

如果业务关心用户、金额和收款账户,签名内容必须覆盖三者:

M = user ∥ amount ∥ account M=\text{user}\|\text{amount}\|\text{account} M=user∥amount∥account

只签金额,攻击者可能替换账户而不影响签名验证。


5.2 序列化必须规范

同一 JSON 对象如果字段顺序、空格、编码方式不同,可能得到不同摘要。因此签名协议必须规定规范化序列化方法。


5.3 验证通过不等于授权通过

V e r i f y ( p k , M , σ ) = 1 Verify(pk,M,\sigma)=1 Verify(pk,M,σ)=1

只能说明签名关系成立,不能单独说明签发者有权执行这项业务。身份、权限、有效期和防重放仍需由协议和业务逻辑检查。


六、本文小结

数字签名的核心流程是:

( p k , s k ) ← K e y G e n (pk,sk)\leftarrow KeyGen (pk,sk)←KeyGen

σ ← S i g n ( s k , M ) \sigma\leftarrow Sign(sk,M) σ←Sign(sk,M)

V e r i f y ( p k , M , σ ) → { 0 , 1 } Verify(pk,M,\sigma)\rightarrow\{0,1\} Verify(pk,M,σ)→{0,1}

格签名的基本思想可以概括为:签名者用私钥生成响应,验证者用公钥重构承诺并重新计算挑战。

下一篇将进入安全模型,解释为什么签名需要 EUF-CMA,KEM 又为什么必须考虑 CCA 攻击。

相关推荐
DBA小马哥1 小时前
向量数据库入门到进阶:Embedding、ANN算法与RAG落地的关键术语
数据库·算法·embedding
Luhui Dev2 小时前
如何在 WorkBuddy 中使用大角几何:从 MCP 接入到 AI 几何作图
人工智能·数学·算法·agent·luhuidev
Smilecoc2 小时前
决策树(五):决策树回归
算法·决策树·回归
小龙报2 小时前
【优选算法】1.搜索插入位置 2.x的平方根
java·c语言·数据结构·c++·python·算法·蓝桥杯
Hi李耶2 小时前
【LeetCode】15.三数之和
java·算法·leetcode
rannn_1113 小时前
【力扣hot100】链表专题|21、2、19、24、92、25
java·数据结构·算法·leetcode·链表·开发
SNAKEpc121383 小时前
OpenGL(十五)- 着色器语言GLSL
c语言·c++·线性代数·算法·矩阵·图形渲染·着色器
AI服务老曹3 小时前
AI视频分析API完整流程:设备、算法与告警接口接入指南
人工智能·算法·音视频
鹿角片ljp3 小时前
LeetCode 21. 合并两个有序链表
算法·leetcode·链表