跳到主要内容
约 11 分钟5 张卡

密码学基础

密码学为数据提供机密性、完整性和来源验证等保护,但这些目标需要不同机制。加密让没有密钥的人难以读懂内容,摘要计算内容的指纹,MAC 和数字签名则把校验与密钥联系起来。把它们都叫作“加密”,会误判一个接口究竟防住了什么。

面试中的对称与非对称比较、HTTPS 握手、签名校验和密钥使用,都建立在这些区别之上。理解时应先说明保护目标,再解释算法怎样组合,最后检查密钥、随机数和重放等边界。

1. 面试核心​

先记住这几条,再读正文
  • 对称加密由双方持有共享秘密;非对称机制使用公私钥对,分别支持加密、签名或密钥协商等不同操作,不能把所有公钥算法都理解为“用公钥加密”。卡 · 对称加密与公钥机制
  • 摘要不带秘密密钥,攻击者也能为篡改后的内容重新计算摘要。校验摘要只有在预期摘要可信时,才能帮助判断内容是否被改动。卡 · 摘要不带来源证明
  • MAC 使用共享密钥,签名使用私钥生成、公钥验证。能验证 MAC 的一方通常也能生成 MAC;签名验证者不需要持有签名私钥。卡 · 签名允许公开验证
  • AEAD 同时加密和验证完整性,但必须正确使用密钥和 nonce。同一 AES-GCM 密钥下不能重复使用加密 nonce,验证失败不能继续处理输出。卡 · AEAD、nonce 与附加认证数据
  • 混合方案用公钥机制建立或保护会话秘密,再用对称密码处理大量数据。TLS 1.3 的证书握手不等于用证书公钥加密一个会话密钥。
  • 性能比较要固定算法、密钥长度、消息大小、具体操作与硬件条件。没有通用的“非对称比对称慢多少倍”或“哈希一定比加密快”结论。卡 · 保护目标与基本机制

2. 保护目标与基本机制​

机密性限制谁能读懂内容;完整性用于检测数据是否被未授权地改变;来源验证用于确认数据与某个受信密钥持有者之间的关系。验证了一个密钥,并不自动知道它属于谁,这还需要证书、预先配置的信任关系等机制。

以一条转账请求为例:加密可以隐藏金额,认证标签可以帮助检测金额被修改,但收到一份昨天合法的请求时,标签依然可能有效。是否允许重复执行,需要额外的防重放和业务去重规则。

机制输入中的秘密主要结果单独不能解决什么
Base64 编码无把字节表示成便于传输的字符保密、来源验证
SHA-256 摘要无固定长度的内容摘要对抗攻击者同时替换内容和摘要
HMAC-SHA-256共享密钥消息认证码保密、区分共享同一密钥的不同持有者
数字签名签名私钥可用对应公钥验证的签名保密、未经绑定的公钥身份、自动防重放
AEAD 加密共享密钥密文与认证标签应用权限、业务去重、隐藏所有元数据

这些机制不是互相替代的等级关系。例如,把密文做 Base64 编码便于传输没有问题,但把明文做 Base64 编码后就认为已经保密,是混淆了表示形式与安全机制。

3. 对称加密与公钥机制​

对称加密使用共享的秘密密钥完成加密和解密。AES 是对称分组密码;实际保护消息时,还需要按协议选择工作方式、处理完整性等要求,不能只说“用了 AES”就认为方案完整。

非对称密码使用相互关联的公钥和私钥。公钥可以分发给别人,私钥由持有者保管,但两把钥匙能做什么,取决于具体算法和协议:

  • 公钥加密中,发送者用接收者的公钥加密,接收者用自己的私钥解密,例如 RSA-OAEP。
  • 数字签名中,签名者用私钥生成签名,其他人用对应公钥验证,例如 Ed25519。
  • 密钥协商中,双方交换公开参数,再结合各自的私有信息计算共享秘密,例如临时 ECDH。它不是把自己的私钥发给对方。

RSA 的基础运算涉及大整数模幂;椭圆曲线机制使用曲线上的运算。面试里可以说明这些数学工具承担的角色,但应用代码应调用经过维护的密码库,不自行拼接裸 RSA 运算、填充或签名格式。

公钥不需要保密,不代表可以不验证来源。如果攻击者把“服务器的公钥”替换成自己的公钥,客户端可能与攻击者建立加密通信。证书链和目标名称校验用于建立身份与公钥之间的信任关系,具体见 TLS。

4. 摘要、MAC 与数字签名​

4.1 摘要不带来源证明​

密码学哈希把输入映射为固定长度的摘要,例如 SHA-256 输出 256 位,也就是 32 字节。它不提供一个持有密钥就能还原原文的解密操作。摘要空间有限,碰撞必然存在;密码学要求的是在给定安全条件下,找到所需碰撞或原像在计算上困难,而不是“绝对不会重复”。

假设文件旁边放着一个 SHA-256 值。若文件和摘要都来自可被攻击者修改的同一个渠道,攻击者可以替换文件,再重新计算摘要。只有预期摘要通过可信渠道取得,或者由受信签名保护,比较才有相应的安全意义。

摘要不可直接解密,也不代表低熵内容无法猜测。若输入只有几个可能值,攻击者可以逐个计算摘要并比较。不能把手机号等可枚举数据简单哈希后,就自动视为无法识别。

4.2 MAC 把校验绑定到共享密钥​

消息认证码(Message Authentication Code,MAC)根据秘密密钥和消息计算标签。发送者生成标签,接收者用同一密钥重新计算并比较;不知道密钥的人不能只靠公开算法,为任意篡改消息生成有效标签。

HMAC 是基于哈希函数构造 MAC 的标准方式,例如 HMAC-SHA-256。不要自行用“密钥与消息拼接后做一次哈希”代替它。Go 标准库用 hmac.New(sha256.New, key) 计算,验证时用 hmac.Equal 比较标签,避免普通比较带来的时序侧信道问题。

HMAC 不加密消息,旁观者仍能读到明文;它也不区分所有共享同一密钥的服务,因为这些服务都具备生成标签的能力。MAC 能证明消息与这组密钥持有者有关,不能仅凭标签断定具体是哪一个成员生成的。

4.3 签名允许公开验证​

数字签名由签名者使用私钥生成,验证者使用对应公钥检查消息与签名是否匹配。以 Ed25519 为例,签名和验签是专门的算法,没有“拿公钥解密签名,就得到原文”的流程。

签名不是“私钥加密”。这种说法混淆了目标,也不适用于所有算法。签名保护消息的可验证性,消息本身可以完全公开;只有加密机制才负责隐藏内容。

签名通过之后,还要知道公钥是否可信、签名究竟覆盖了哪些字节,以及消息是否适用于当前场景。签名一个请求体,但不覆盖关键的路径或用途标识,可能让同一内容被放到错误的上下文里。算法不能代替协议对消息范围和身份的约束。

5. AEAD、nonce 与附加认证数据​

AEAD(Authenticated Encryption with Associated Data)是同时保护机密性与完整性的加密方式。它接收密钥、nonce、明文和附加认证数据,输出密文与认证标签;解密时也检查标签,检查失败就拒绝。

nonce 是一次加密操作使用的值。对于 AES-GCM,同一密钥下不同加密操作的 nonce 必须不同;它通常不需要保密,可以随密文一起发送。重复使用可能同时破坏机密性与完整性,并非只是让密文看起来有规律。

附加认证数据(AAD)参与完整性校验,但不被加密。例如,消息头里的租户标识 tenant:7 可以保持可读,同时与密文绑定。接收者要把自己期望的上下文传给解密函数,不能无条件相信攻击者随请求提供的任意标识。

下面用 Go 1.22 标准库演示一次 AES-GCM 加密、解密与篡改检测。示例每次运行生成一把新密钥,仅加密一条消息:

package main

import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
)

func main() {
key := make([]byte, 32)
if _, err := rand.Read(key); err != nil {
panic(err)
}
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
aead, err := cipher.NewGCM(block)
if err != nil {
panic(err)
}
nonce := make([]byte, aead.NonceSize())
if _, err := rand.Read(nonce); err != nil {
panic(err)
}
aad := []byte("tenant:7")
ciphertext := aead.Seal(nil, nonce, []byte("amount=100"), aad)
plaintext, err := aead.Open(nil, nonce, ciphertext, aad)
if err != nil {
panic(err)
}
fmt.Println(string(plaintext))

damaged := append([]byte(nil), ciphertext...)
damaged[len(damaged)-1] ^= 1
_, err = aead.Open(nil, nonce, damaged, aad)
fmt.Println("tamper rejected:", err != nil)
_, err = aead.Open(nil, nonce, ciphertext, []byte("tenant:8"))
fmt.Println("wrong context rejected:", err != nil)
}

输出依次是 amount=100、tamper rejected: true 和 wrong context rejected: true。Seal 的输出包含认证标签;修改密文或换用不同的 AAD,都使 Open 拒绝。代码不会在验证失败后继续使用返回值。

本例的 nonce 长度是 12 字节,认证标签带来 16 字节开销。nonce 若也随消息传输,还需另外计算它的开销。示例没有实现密钥保存、消息封装或轮换,不能直接当成完整通信协议。

5.1 随机生成 nonce 就没有重复风险了吗?​

没有这种保证。随机数空间有限,使用次数增加时会积累碰撞风险。Go 1.22 的 GCM 示例明确限制:同一密钥下不要使用超过 2^32 个随机 nonce。这是为了限制重复风险,不表示在边界之前重复概率为零,也不表示其他协议的所有使用限额都相同。

如果用计数器分配 nonce,需要保证同一密钥的所有发送实例不会分配重复值,进程重启也不能把计数器清零后继续使用旧密钥。密钥本身应由密码学安全随机源生成,例如 crypto/rand,不能用时间戳或普通伪随机序列替代。

5.2 AEAD 验证通过,是否说明请求没有被重放?​

不是。攻击者原样复制一份合法的 nonce、密文和 AAD,解密验证仍可能通过,因为这些字节确实曾由合法密钥生成。禁止加密端重复使用 nonce,与接收端识别已经处理过的请求,是两件事。

协议需要用请求序号、有效期与已用标识等约束处理重放;带副作用的业务还要设计去重和恢复,见分布式流程恢复。

6. 混合方案与性能比较​

混合加密方案把公钥机制与对称加密组合起来:先建立或保护短的会话秘密,再由对称密钥处理大量内容。对称算法适合持续处理数据;公钥机制承担身份验证、密钥协商或短秘密传输等职责,不必对每一段业务内容都执行昂贵的公钥运算。

公钥加密还有消息长度约束。例如,RSA-OAEP 的输入长度取决于模数大小和哈希输出长度:使用 2048 位 RSA 与 SHA-256 时,单次最多加密 256 - 2 × 32 - 2 = 190 字节。这个例子用于说明算法接口边界,不能把大文件切成许多段后就当成完整安全协议。

TLS 1.3 的完整证书握手使用临时密钥交换派生共享秘密,用证书对应的私钥签名证明身份,最后由对称 AEAD 保护应用数据。它没有采用“客户端生成会话密钥,再用服务器证书公钥加密发送”的静态 RSA 密钥传输流程。详细握手见 TLS。

比较开销时,至少需要说明以下条件:

条件为什么影响结果
具体操作RSA 加密与解密、签名与验签的成本可能不同;密钥生成又是另一种操作
算法与参数AES-GCM、SHA-256、HMAC-SHA-256 和公钥算法的职责、处理步骤不同
数据大小短消息容易受调用和初始化开销影响,大消息更关注吞吐
硬件与实现AES、哈希指令加速以及库实现都会影响结果
系统范围握手的网络往返、证书验证、随机数生成不能与纯算法耗时混为一谈

所以,不能回答一个脱离条件的“慢多少指数级”,也不能为了降低开销,用 SHA-256 替代需要保密的加密操作。先满足安全职责,再在相同环境和目标负载下测量对应操作;本文不提供跨算法通用的性能倍数。

密钥泄露后,算法再正确也无法维持原有信任。密钥应按用途分离,并控制存储、访问、轮换和撤销,相关流程见密钥、证书、审计与供应链安全。

7 · 面试题卡片​

本页题目与参考回答

7.1 对称与非对称密码怎样分工,为什么业务数据通常用对称加密?​

考察重点:共享密钥与公私钥、加密和密钥协商的区别,以及混合方案的成本与边界。

相关内容:对称加密与公钥机制、混合方案与性能比较。

参考回答

**对称加密适合处理大量业务数据,公钥机制用于身份验证、密钥协商或保护短的会话秘密,两者可以组合使用。**对称方式要求双方持有共享密钥,公钥机制则通过公私钥分配不同能力。

公钥运算成本和输入约束都与具体算法有关,不能给出通用速度倍数。以 TLS 1.3 证书握手为例,临时密钥交换派生密钥,证书私钥用于签名证明身份,随后用对称 AEAD 保护数据;它不是用证书公钥直接加密所有业务内容。

7.2 加密和哈希的开销怎样比较?​

考察重点:安全目标、算法参数、消息大小与测量范围。

相关内容:保护目标与基本机制、混合方案与性能比较。

参考回答

**不能按名称给出固定快慢,也不能用哈希替代保密所需的加密。**哈希生成摘要,不提供持钥解密;加密需要让合法接收者恢复内容,职责不同。

比较时固定算法、参数、消息长度、硬件和库实现,分别测量初始化、处理耗时与吞吐。若讨论 HTTPS 总开销,还要考虑握手、证书验证和网络往返,不能只比较一个哈希调用和一次完整连接。

7.3 消息附带 SHA-256 摘要,为什么仍可能被攻击者篡改?​

考察重点:无密钥摘要与带密钥认证的区别,预期摘要的可信来源。

相关内容:摘要不带来源证明、MAC 把校验绑定到共享密钥。

参考回答

**攻击者若能同时替换消息和摘要,就能为篡改后的消息重新计算 SHA-256。**摘要本身不含秘密,不能证明是谁生成的。

可以通过可信渠道取得预期摘要,或使用受信签名、基于共享秘密的 MAC 保护消息。HMAC 的接收者用共享密钥验证,标签比较应使用相应的安全接口;它仍不负责隐藏消息内容。

7.4 数字签名为什么不能简单称为“私钥加密”?​

考察重点:签名与保密的职责、公钥信任,以及公开验证与共享密钥验证的差别。

相关内容:签名允许公开验证、MAC 把校验绑定到共享密钥。

参考回答

**签名用于生成可公开验证的证明,不负责隐藏消息;签名和加密也不是所有算法中互相反转的操作。**例如 Ed25519 用私钥签名、公钥验签,没有通过“公钥解密”恢复原文的步骤。

验证者还要信任公钥与身份的绑定,并检查签名覆盖的消息和使用场景。与 HMAC 相比,持有公钥的验证者不需要获得生成签名的私钥。

7.5 AES-GCM 为什么不能重复使用加密 nonce,认证通过又为什么不等于防重放?​

考察重点:同一密钥下的 nonce 唯一性、认证标签与应用请求历史。

相关内容:AEAD、nonce 与附加认证数据、认证与重放的区别。

参考回答

**同一 AES-GCM 密钥下重复使用加密 nonce 会破坏安全前提,而重放是再次提交已经合法生成的完整消息。**前者需要加密端管理 nonce,跨实例和重启都不能发生重复;随机生成也需要限制同一密钥的使用次数。

后者可能仍通过认证,因为密文没有被修改。接收端需要结合请求序号、已用标识和业务去重判断是否再次执行;验证失败时则必须拒绝,不能继续处理输出。

8. 参考资料​

来源:Coding 101 原文 · 免费阅读,引用请保留出处。内容使用说明