4. 国密算法在接口中的角色:加密、签名、完整性校验归纳总结

我做了不少接口治理项目,跟国密算法打交道也有年头了。说实话,很多人刚开始接触国密时,容易把加密、签名、哈希混为一谈——总觉得它们都是“把数据变乱”,其实干的是完全不同的活儿。

国密算法在接口里,归根到底就三件事:保证数据不被偷看、保证数据没被篡改、证明数据是谁发的。下面我挨个拆开讲,最后再串起来看它们怎么配合的。

一句话先记住: 加密管机密性,签名管真实性和不可否认性,哈希(SM3)管完整性。三件事不能互相替代。
国密算法在接口中的三大角色 🔒 加密 SM2/SM4 保护机密性 防窃听 ✍️ 签名 SM2 防抵赖+防伪造 来源验证 🔍 完整性校验 SM3 防篡改 数据一致性 三者关系: 签名和完整性校验常配合使用,加密是独立选项 接口中常见组合:SM4加密 + SM2签名 + SM3摘要校验 国密算法体系(SM2/SM3/SM4)覆盖接口全部安全需求 实际落地时需根据接口敏感等级选择使用几项

4.1 加密——保护数据不被偷看

加密的目的很纯粹:让不该看的人看不懂。接口传输中,如果数据明着走,中间人抓个包什么都知道了——这肯定不行。

国密加密分两种:对称加密 SM4 和 非对称加密 SM2。它们的用法差别很大,我列个表对比一下。

对比项 SM4(对称) SM2(非对称)
密钥 双方共用一个密钥 一对密钥(公钥/私钥)
速度 快(硬件加速后可达Gbps) 慢(适合小数据量)
适用场景 大量业务数据加密 密钥交换、数字信封
典型用法 SM4-CBC/PKCS7Padding SM2公钥加密对称密钥

我个人习惯:能用对称加密的地方尽量不要用非对称去硬套。有一次我见过有人直接用 SM2 加密整个大报文,结果接口响应时间从 200ms 飙到 6 秒——你想想看,非对称加密每个分组只能加密少量数据,效率摆在那。

我的推荐做法: 用 SM2 公钥加密一个随机生成的 SM4 密钥(这叫数字信封),然后用 SM4 去加密真正的业务数据。这样既安全,又高效。

4.2 签名——证明是你干的

加密解决了“别人看不懂”,但没解决“对方到底是谁”。签名就是用来解决这个的。

SM2 签名算法本质是:发送方用私钥对摘要签名,接收方用公钥验签。只要验签通过,就能证明这条数据是私钥持有者发的,而且中途没被改过。

# Python 示例:SM2 签名与验签(使用 pysmx 库)
from pysmx.SM2 import generate_keypair, Sign, Verify

# 生成密钥对
private_key, public_key = generate_keypair()

# 签名(假设消息为字节串)
message = b"transfer=1000&to=alice"
signature = Sign(private_key, message)

# 验签
is_valid = Verify(public_key, message, signature)
print("验签结果:", is_valid)  # True or False

为什么要用签名而不是直接用加密来防伪造?

嗯,这里要区分清楚:加密是对数据本身做变换,验证方要么能解密看到原文(前提是有密钥),但无法判断数据是不是来自声称的发送者。签名则不同——它不需要隐藏数据,只需要证明“我承认这条数据是我发的”。这在实际业务中非常关键,比如金融转账接口,对方不能事后抵赖“我没发过这笔转账”。

我曾经踩过的坑: 签名之前一定要先哈希!很多初学者直接对明文签名,如果明文很大,SM2 签名的速度会慢到怀疑人生。正确的做法是先算 SM3 摘要,再对摘要签名。标准做法是 SM3withSM2。

4.3 完整性校验——数据动没动过?

完整性校验听起来跟签名有点像,但它不管“谁发的”,只管“有没有变过”。

国密里的完整性校验就用 SM3 哈希算法。哈希是一个单向函数,输入任意长度,输出固定 256 位的摘要。哪怕原文只改了一个比特,摘要都会完全不同。

特性 SM3 哈希
输出长度 256 位(32 字节)
抗碰撞性 强,安全性相当于 SHA-256
典型用途 校验数据完整性、签名前的摘要计算、HMAC-SM3

那什么时候只用 SM3 就够了?

举个例子:你向外提供某个公开的 SDK,里面有固件更新包。你可以在发布页公布该文件的 SM3 摘要值。用户下载后自己算一遍,跟公布的比对—如果一致,说明文件没被篡改。这个场景不需要签名,因为你是公开的,不需要证明“是你发的”,用户只关心文件本身有没有被动过。

但在接口通信中,SM3 通常是跟签名绑在一起的。我习惯的做法:先把请求体的所有字段按字典序拼接,算 SM3,然后把摘要放进签名内容里一起签名。接收方验签通过后,再自己算一遍 SM3 跟签名里的摘要比对,确保某些字段没有在中间被调包。

一个小技巧: 拼接字段做摘要时,一定要约定 key 的排序规则。我见过有的团队用 JSON 的序列化顺序,结果不同语言序列化出来的 key 顺序不一样,导致摘要对不上。我的做法是固定用字母升序拼接,字段之间加分隔符,放两个接口都用同一套规则。

4.4 三个角色如何协同?

一个完整的接口安全设计,通常不是只用其中一种。拿最常见的“请求加签+数据加密”场景来说:

  1. 发送方: 用 SM3 对请求体算出摘要,
  2. 用 SM2 私钥对摘要签名,
  3. 用 SM4 对称密钥加密整个请求体 + 签名,
  4. 用接收方的 SM2 公钥加密 SM4 密钥,一起发过去。
  5. 接收方: 先用自己 SM2 私钥解密得到 SM4 密钥,
  6. 再用 SM4 密钥解密得到原文和签名,
  7. 然后用发送方 SM2 公钥验签,
  8. 最后自己算一遍 SM3 比对摘要是否一致。

你看,加密、签名、哈希全用上了。这叫“层层防护”。

但也别觉得每个接口都得这么复杂。我根据接口敏感程度,一般分成三个等级:

等级一(低敏感): 只做 SM3 完整性校验 + 时间戳防重放。
等级二(中等敏感): SM3 + SM2 签名,数据明传。
等级三(高敏感): SM4 加密 + SM2 签名 + SM3 摘要,全套上。

拿我自己做过的支付接口来说,必须走等级三。因为资金数据一旦泄露或篡改,后果非常严重。而一些内部配置接口,等级一完全够用——没必要为了“国密”二字盲目堆砌所有算法,增加接口延迟和开发成本。

4.5 避坑清单

  • 签名和加密的顺序不能反。 应该先签名后加密。如果先加密再签名,别人拿到你的签名后并不知道原始数据是什么,但验证者需要先解密才能验签,逻辑上就拧巴了。
  • SM3 摘要不要直接当签名用。 你想想看,如果只传摘要,中间人截获后完全可以自己改数据、重算摘要,接收方根本无法判断谁改的。签名需要私钥参与,才具有不可否认性。
  • 密钥管理比算法本身更重要。 我曾经遇到过客户,SM4 密钥硬编码在代码里,还忘了切环境——测试和线上用同一个密钥。这等于锁没坏,但钥匙挂在门口。

总结一下:国密三件套——加密负责“藏”,签名负责“认”,哈希负责“查”。在接口治理中,理解它们的定位和配合原则,比死记硬背算法参数重要得多。

最后提醒: 做国密改造时别光想着替换算法,接口的密钥协商、证书管理、异常处理流程都要一并跟上。算法只是安全链条上的一环,环环相扣才靠得住。