关于密码学,国际算法和国密算法到底有啥区别? 公钥加密,私钥解密?私钥加密,公钥解密?哪个对? BJCA 数字信封和 BouncyCastle 签名格式,是个啥?
前面几篇文章把 SM2、SM4、数字信封、数字签名都聊过了,但每次提到 SM3,可能大家都有疑问:“这玩意到底有啥用?”“我用 SM2 私钥加密不就完了吗?”“数字信封不就能保护数据了,搞个 SM3 签名不是多此一举?”。今天专门开一篇,把这些疑问一次讲透。
一、SM3 是啥?一句话:绞肉机
SM3 是一种哈希算法(也叫摘要算法、散列算法),叫法很多,但干的事就一件:
不管你丢进去什么东西,它都给你搅成一坨固定大小的"肉馅"。
SM3("你好") → 32 字节的"肉馅"
SM3("这是一份 5000 字的病历") → 32 字节的"肉馅"
SM3("这是一份 50MB 的影像报告") → 32 字节的"肉馅"
SM3("随便塞多少进去") → 32 字节的"肉馅"
不管你往绞肉机里塞一头牛还是一根葱,出来的肉馅永远是 32 字节(256 位)。
而且这台绞肉机有三个特别牛的性质:
性质一:不可逆
你看到一坨肉馅,能还原出原来那块肉是啥样的吗?
不能。SM3 也一样,从摘要反推不出原文。
性质二:雪崩效应(防篡改)
SM3("Hello") → a1b2c3d4e5…
SM3("hello") → f9e8d7c6b5…
就改了一个字母 H→h,出来的摘要完全变了,没有一个字节是相同的。
就像你往绞肉机里多扔了一粒花椒,出来的味道完全不同。
性质三:抗碰撞
想找两块不同的肉,搅出来的肉馅一模一样?
理论上存在这种可能,但概率低到可以忽略(2的128次方分之一)。
实际工程中可以认为:不同的输入,不会产生相同的摘要。
所以 SM3 的外号叫数字指纹。就像人的指纹一样,每个人不同,且没法从指纹反推出长相。
二、SM3 到底用在哪?——它是签名的第一步
很多人以为签名就是"用私钥把数据加密一下",这个理解在 SM2 这里是不对的。
SM2 签名算法的标准流程(GM/T 0003 标准白纸黑字写着的):
步骤 1:e = SM3(原始数据) ← 第一步就是 SM3 摘要
步骤 2:选随机数 k
步骤 3:椭圆曲线点运算…
步骤 4–5:一堆数学运算
步骤 6:输出签名 (r, s)
SM3 是写死在 SM2 签名算法里的第一步,不是可选的,不是额外加的。
没有 SM3,SM2 签名算法连第一步都跑不起来。就好比你做红烧肉,第一步是"把肉切块",你说"我不想切,直接整块炖"——那后面就没法做了。
三、灵魂拷问:直接用 SM2 私钥"加密"原始数据当签名不行吗?
这个问题我听过不下二十次了。拆开来回答。
先说结论:SM2 压根没有"私钥加密"这个操作
大家应该都听过,RSA 的数学结构天然对称(加密和签名都是模幂运算),所以"私钥加密当签名"在 RSA 里表面上说得通。
但 SM2 不一样。SM2 基于椭圆曲线,它的加密算法和签名算法是两套完全不同的数学公式:
SM2 加密:点乘 + 密钥派生 + 异或 → 输出一串密文
SM2 签名:摘要 + 模逆 + 模乘 → 输出两个整数 (r, s)
公式不一样,步骤不一样,输入输出格式不一样。
根本不存在"把加密反过来用就是签名"这回事。
所以"用 SM2 私钥加密数据当签名"这个操作,在 SM2 的世界里根本不存在。
就算存在,也走不通
假设技术上能做到(其实做不到),咱们推演一下会怎样:
走不通的第一关:数据太大,塞不进去
SM2 一次能处理的数据量大概只有几十个字节。【非对称加密处理小数据,对称加密处理大数据】
一份电子处方 1~5KB → 塞不进去
一份住院病历 10~100KB → 更塞不进去
SM3 摘要后 → 固定 32 字节 → SM2 一下就签完了
走不通的第二关:慢得离谱
SM2 非对称运算(单次)→ 几毫秒
SM3 哈希(1MB 数据) → 几微秒
如果 SM2 能处理大数据,签一份 1MB 的病历需要几分钟。
SM3 + SM2 签名呢?几毫秒搞定。
差了几千倍,这个性能差距在医院这种高并发场景下是不能接受的。
走不通的第三关:不安全
这个是最要命的。直接对原始数据做签名(不经过哈希),数学上存在存在性伪造攻击:
简单说就是攻击者可以利用签名的数学性质,
构造出一个"你从没签过的数据"的合法签名。
经过 SM3 之后再签 → 切断了数据和签名之间的数学关联 → 伪造变得不可能。
所以 SM3 存在的理由总结下来就三条:
1. SM2 根本签不了大数据(容量限制)
2. 签大数据太慢(性能限制)
3. 直接签原始数据不安全(数学攻击)
四、SM3withSM2 到底是啥组合?
搞明白了 SM3 的作用,SM3withSM2 这个名字就很好理解了:
SM3withSM2 = 先用 SM3 做摘要,再用 SM2 对摘要做签名
就是一个"两步走"的组合套餐,起个名字方便调用。
密码学里的命名都是这个套路:
算法名 实际操作
──────────────────────────────────
SM3withSM2 SM3 摘要 + SM2 签名(国密)
SHA256withRSA SHA–256 摘要 + RSA 签名(国际)
SHA256withECDSA SHA–256 摘要 + ECDSA 签名(国际)
MD5withRSA MD5 摘要 + RSA 签名(已经不安全了)
规则就是:[摘要算法] with [签名算法]
在代码里,你只需要指定算法名,内部两步自动完成:
// 你只需要告诉它用 SM3withSM2,内部自动先 SM3 再 SM2
Signature sig = Signature.getInstance("SM3withSM2", "BC");
sig.initSign(privateKey);
sig.update(prescriptionData); // 原始处方数据直接扔进去
byte[] signature = sig.sign(); // 内部自动完成:SM3 摘要 → SM2 签名
验签也是一样:
Signature sig = Signature.getInstance("SM3withSM2", "BC");
sig.initVerify(publicKey);
sig.update(prescriptionData); // 原始处方数据扔进去
boolean ok = sig.verify(signature); // 内部自动:SM3 摘要 → SM2 验签
五、重头戏:加密和签名到底是不是一回事?
搞明白 SM3 的作用之后,必须把另一个更根本的误解也澄清了。
很多人把"加密/解密"和"签名/验签"搅在一起,觉得是一回事。其实差别大了去了。
加密 ≠ 签名,它们解决的问题完全不同
加密(数字信封)= 你把东西锁进保险箱
你:把处方放进保险箱,锁上,钥匙用对方公钥加密
对方:用自己私钥解开钥匙,打开保险箱,看到处方
解决的问题:处方在运输过程中,别人看不到
这叫保密性
签名(SM3+SM2)= 你在处方上按了手印
你:把处方内容算个指纹(SM3),用私钥对指纹盖章(SM2)
对方:重新算指纹,用公钥比对盖章上的指纹
解决的问题:
→ 这处方确实是你开的(认证性)
→ 处方一个字都没被改过(完整性)
→ 你事后赖不掉(不可否认性)
一个是"加锁防偷看",一个是"盖章防篡改"。
完全不同的事,解决完全不同的问题。
解密 ≠ 验签,它们的操作完全不同
| 目的 | 看到内容 | 确认身份 + 确认没被改过 |
| 回答的问题 | “里面写了啥?” | “这东西谁写的?有没有被改过?” |
| 用什么操作 | 私钥解密密文 | 公钥验证签名 |
| 结果 | 输出原始明文 | 输出 true 或 false |
| 失败意味着什么 | 密钥不对或数据损坏 | 数据被篡改或签名是伪造的 |
解密是"把锁打开看内容",验签是"对比指纹确认身份"。
两者的操作对象完全不同:
解密:操作的是密文 → 还原出明文
验签:操作的是签名 + 明文的摘要 → 对比两个摘要是否一致
那问题来了:光有加密够不够?
光有加密,没有签名:
药房收到加密的处方,用自己的私钥解开了。
但是:
❓ 这处方真的是张医生开的吗?
→ 不知道。谁都能用药房的公钥加密一份假处方发过来。
❓ 处方在传输过程中有没有被改过?
→ 不知道。加密只保证别人看不到,不保证内容没被换过。
❓ 以后张医生说"我没开过这个处方"怎么办?
→ 没办法反驳,因为没有他的签名。
光有签名,没有加密:
药房收到签名的处方,验签通过,确认是张医生签的,内容也没被改。
但是:
❓ 网络上所有人都能看到处方内容
→ 患者的隐私泄露了
所以两个都要有,各管各的,谁也替代不了谁。
那 SM3 在这里到底是干嘛的?
你可能会问:数字信封里已经用 SM2 加密 SM4 密钥了,SM4 加密处方数据了。那 SM3 摘要签名又是干嘛的?
答案很简单:
数字信封(SM2 + SM4)只负责"加密":
→ 保证处方在传输过程中不被别人看到
→ 但不保证处方是谁写的
→ 也不保证处方有没有被篡改
数字签名(SM3 + SM2)负责"认证+防篡改":
→ 用 SM3 给整个处方算一个指纹
→ 用医生的 SM2 私钥对指纹签名
→ 任何人拿到处方,都能验证:是这个医生签的,且没改过一个字
SM3 摘要的是整个处方的明文内容,不是 SM4 密钥。为什么?因为你要防篡改的是处方本身:
假设你只对 SM4 密钥做签名(不用 SM3 摘要整个处方):
签名 = SM2 签名(SM4 密钥)
攻击者在传输过程中:
偷偷把信封里的处方内容改了(比如把药量从 1 改成 10)
但 SM4 密钥没变 → 对密钥的签名依然有效 → 验签通过!
→ 处方被篡改了,但验签发现不了 ❌
正确做法:
签名 = SM2 签名(SM3(整个处方明文))
攻击者改了处方的任何一个字:
→ SM3 算出来的摘要完全不同
→ 签名验证失败
→ 药房立刻发现处方被篡改 → 拒绝接收 ✅
六、三个算法各管什么
┌─────────┬──────────────┬──────────────────────────────────┐
│ 算法 │ 类型 │ 管什么事 │
├─────────┼──────────────┼──────────────────────────────────┤
│ │ │ 给任意数据生成"指纹" │
│ SM3 │ 摘要算法 │ 签名之前必须先做这一步 │
│ │ (绞肉机) │ 本身不加密,不签名,只出指纹(防篡改)│
├─────────┼──────────────┼──────────────────────────────────┤
│ │ │ ① 签名验签:签名→盖章,验签→对指纹 │
│ SM2 │ 非对称算法 │ ② 加密小数据:锁住 SM4 密钥 │
│ │ (公私钥) │ 不能直接对大数据操作 │
├─────────┼──────────────┼──────────────────────────────────┤
│ │ │ 加密大数据(处方、病历等) │
│ SM4 │ 对称算法 │ 速度快,适合大量数据 │
│ │ (一把钥匙) │ 密钥本身靠 SM2 保护 │
└─────────┴──────────────┴──────────────────────────────────┘
一句话记住它们的关系:
SM3 负责"压缩出指纹(防篡改)"
SM2 负责"盖章保护指纹"和"锁住 SM4 的钥匙"
SM4 负责"加密大量数据"
SM3 让签名成为可能,SM2 让签名和密钥保护成为可能,SM4 让大数据加密成为可能。
三个配合起来,才是一套完整的安全体系。
说到底,密码学这些东西概念多,但核心就一句话:不同的工具解决不同的问题,搞清楚每个工具是干什么的,就不会混了。 加密和签名不是一回事,解密和验签也不是一回事。就像菜刀和砧板都是厨房工具,但你不能拿砧板切菜,也不能拿菜刀垫着剁肉。



