SM4 密钥长度
16 字节 固定 128 位,即 16 字节:写成 32 位十六进制或 16 个 ASCII 字符。SM4 没有 192 位或 256 位密钥。
SM4在线加密解密:解密失败自动排查模式、填充、IV 和编码哪项不对,一键套用;浏览器本地计算,不上传。支持国密 SM4 的 ECB、CBC、CTR、CFB、OFB 模式,PKCS#7(PKCS5Padding)、ZeroPadding、NoPadding 填充,密钥和 IV 可用 Hex、文本或 Base64,附 GB/T 32907 标准测试向量。
ECB 会把相同的明文分组加密成相同的密文,暴露数据规律——只在对接要求 ECB 的系统时使用。
CTR、CFB、OFB 是流模式:不需要填充,密文与明文等长。
自动排查
—
需要 OpenSSL 3。命令中包含你输入的密钥。
| 密钥 | 0123456789abcdeffedcba9876543210 |
|---|---|
| 明文 | 0123456789abcdeffedcba9876543210 |
| 密文(加密 1 次) | 681edf34d206965e86b3e94f536e4246 |
| 密文(连续加密 1,000,000 次) | 595298c7c6fd271f0402f804c33d3f66 |
由构建加密工具的开发者撰写并审核。本页引用的每个密文和字节数都由工具引擎实算,并由测试逐项核对。
16 字节 固定 128 位,即 16 字节:写成 32 位十六进制或 16 个 ASCII 字符。SM4 没有 192 位或 256 位密钥。
681edf34d206965e86b3e94f536e4246 密钥和明文都是 0123456789abcdeffedcba9876543210 时,SM4 加密一次得到 681edf34d206965e86b3e94f536e4246。
32 轮 分组 16 字节(128 位),加密 32 轮。
前 16 个字节 不会。只有前 16 个字节解错,最后一个分组里的填充照样校验通过。
SM4 是中国商用密码标准中的分组密码算法:先以 GM/T 0002-2012 发布,随后成为国家标准 GB/T 32907-2016(2017 年 3 月 1 日起实施),2021 年又通过修正案纳入国际标准 ISO/IEC 18033-3。它是对称密码:加密和解密用同一个 128 位密钥,每次处理 128 位(16 字节)的分组——分组长度与 AES 相同。
在算法内部,每个分组被拆成四个 32 位的字,经过 32 轮迭代。每一轮把其中三个字与轮密钥混合,经过一个 8 位 S 盒和一次线性变换,再并入第四个字。32 个轮密钥由原始密钥和两组固定常数扩展而来;解密与加密是同一套运算,只是轮密钥的顺序倒过来。
分组算法本身一次只能处理正好 16 个字节,所以实际数据总要套一种工作模式。本工具提供五种经典模式:ECB 和 CBC 按整个分组处理,需要填充;CTR、CFB 和 OFB 把 SM4 变成流密码,完全不需要填充。绝大多数「SM4 解密失败」都和 SM4 算法本身无关,而是加解密两端在模式、填充、IV、明文编码或「密钥字符串怎么变成字节」上没有对齐——各个库连单写一个「SM4」指的是哪种模式都不一致。
浏览器内置的 Web Crypto API 不包含 SM4,因此本页自带一份 SM4 实现并在本地运行。它已通过 GB/T 32907 的两个测试向量,并在每种模式下都与 OpenSSL 3 交叉校验过。
// SM4-CBC with PKCS#7 padding using Node.js and its bundled OpenSSL 3.
// Key and IV are both exactly 16 bytes (32 hex digits).
const crypto = require('node:crypto');
const key = Buffer.from('0123456789abcdeffedcba9876543210', 'hex');
const iv = Buffer.from('fedcba98765432100123456789abcdef', 'hex');
const cipher = crypto.createCipheriv('sm4-cbc', key, iv);
const ciphertext = Buffer.concat([cipher.update('hello', 'utf8'), cipher.final()]);
console.log(ciphertext.toString('base64')); // fUQPRg2HAXHGz5ZslzCpSQ==
const decipher = crypto.createDecipheriv('sm4-cbc', key, iv);
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
console.log(plaintext.toString('utf8')); // hello 解密失败时,页面会把密文编码、密钥格式、模式、IV、填充和明文编码逐一重试,直接给出能解出可读文本的那组参数。
OpenSSL、Hutool、sm-crypto、gm-crypt、tjfoc/gmsm 的默认参数点一下就对齐——这些库连单写「SM4」是 ECB 还是 CBC 都不一致。
ECB、CBC、CTR、CFB、OFB,搭配 PKCS#7、ZeroPadding 或 NoPadding。明文支持 UTF-8 和 GBK——后者是老 Java 代码在中文 Windows 上的默认编码。暂不支持 GCM。
一键随机生成 16 字节的密钥或 IV,也可以按代码里的写法填写;实时字节数先确认你手上正好是 16 字节,免得在别处白找原因。
附录 A 的两个结果印在表格里,点一下就能载入,拿来核对任何 SM4 实现是否符合国标。
每个结果都附带能复现它的 openssl enc 命令,可以在终端里确认,也方便直接发给同事。
SM4 引擎在本地执行,密钥和数据不会离开页面,断网也能用。
openssl enc)-sm4 即 CBC -sm4 是 -sm4-cbc 的别名。-K 和 -iv 用十六进制,默认 PKCS#7 填充,加 -nopad 才关闭;默认输出原始字节,要 Base64 得加 -base64 -A。-K 长度不对时会被截断或补零,只打印一句警告。
SmUtil.sm4(key)Hutool 只传一个裸的 SM4,由 BouncyCastle 按 ECB + PKCS#7 执行(JCE 里叫 PKCS5Padding)。字符串方法按 UTF-8 编码,encryptHex 输出小写十六进制。要用 CBC 请写 new SM4(Mode.CBC, Padding.PKCS5Padding, key, iv)。
Cipher.getInstance("SM4")需要 IV 的模式没给 IV 时,加密会悄悄生成一个随机 IV,解密则抛出 no IV set when one expected——如果那个随机 IV 没有随密文保存,任何一端都解不开。
sm4.encrypt(data, key) 默认 ECB + PKCS#7,密钥要 32 位十六进制字符串,输出小写十六进制。只有 mode: 'cbc' 能切换模式,写其他值会静默按 ECB 处理。sm-crypto-v2 行为相同,但 CBC 不传 iv 时会用全零 IV。
默认 CBC,密钥和 IV 都是 16 个字符的 UTF-8 字符串,输出 Base64。字节不是合法 UTF-8 的密钥根本传不进去。
CryptSM4模式由调用 crypt_ecb 还是 crypt_cbc 决定。set_key 只读前 16 个字节,更长的密钥会被悄悄截断;用错密钥时通常返回空字节串,而不是报错。
sm4Sm4Cbc 使用包级 IV,调用 SetIV 之前一直是全零;连 CFB、OFB 也会做 PKCS#7 填充;解填充出错时直接丢弃错误——用错密钥返回 nil,也不报错。
密钥 0123456789abcdeffedcba9876543210,明文(Hex)0123456789abcdeffedcba9876543210
681edf34d206965e86b3e94f536e4246
这是 GB/T 32907-2016 附录 A 的示例 1:密钥和明文是同一个 128 位的值,SM4 加密一次得到 681edf34d206965e86b3e94f536e4246。把输出继续加密,累计一百万次得到 595298c7c6fd271f0402f804c33d3f66。两个值都印在本页的测试向量表里,由你正在使用的同一份引擎算出。点 国标测试向量 按钮会载入第一组。
密钥 0123456789abcdeffedcba9876543210,IV fedcba98765432100123456789abcdef,明文:国密 SM4 联调测试:订单号 20260911-0042
9VIqdBnH9fiUiytTtZ5AzKLXFKdRvAuzmRI+ep/Yq88rOYRCktyEKHrREAfKKyYtuvG+CaDVjAlp4LvSpqtkaw==
这段明文按 UTF-8 编码是 49 字节,每个汉字占 3 字节。PKCS#7 把它填充到 64 字节,也就是 4 个分组,写成 Base64 是 88 个字符。点 加载示例 会填入完全相同的参数,OpenSSL 面板里给出的命令在终端里能复现同一串 Base64。
用上面的密文,把 IV 换成 00000000000000000000000000000000 再解密
开头是乱码,后面照常解出「测试:订单号 20260911-0042」
CBC 只把 IV 混进第一个分组,而 PKCS#7 填充在最后一个分组里,所以填充校验照样通过,OpenSSL 不会报任何错。本页会注意到第一个分组解不出可读文本,告诉你密钥和模式是对的、问题出在 IV——或者密文开头 16 个字节本身就是 IV。中文明文里,被切开的那个汉字也会一起显示成乱码。
知道对端用的是哪个库,就在「按对端库的默认参数」里直接选它。否则先选「加密」或「解密」,再按对端系统选模式和填充。CTR、CFB、OFB 是流模式,不需要填充,填充下拉框会自动禁用。
两者都必须正好 16 字节。选择这串字符的格式——Hex、文本或 Base64——字节数变绿即表示长度正确。「随机生成」按钮可以生成新的值。
加密时输入文本(UTF-8 或 GBK)或粘贴十六进制字节;解密(解码)时粘贴密文,并选择它是 Base64 还是 Hex。结果随输入实时更新。
复制输出,或点「用这段密文去解密」,带着同样的密钥和 IV 切到解密页签验证往返。OpenSSL 面板给出能复现结果的命令。
自动排查会列出能让你的输入解出可读文本的参数组合,点一下即可套用。如果只有开头 16 个字节解不出来,提示会指向 IV。
32 个字符的十六进制串只有按十六进制解码才是 16 字节。按文本读是 32 字节,SM4 会直接拒绝——遇到会悄悄截断或补齐密钥的代码,就变成了另一个密钥。
密钥(文本):0123456789abcdeffedcba9876543210 -> 32 字节,被拒绝
密钥(Hex): 0123456789abcdeffedcba9876543210 -> 16 字节
加解密两端必须用同一种模式。CBC 密文按 ECB 解密,每个分组都是乱码,而且通常在最后的填充校验上失败。
加密:SM4/CBC/PKCS5Padding 解密:SM4/ECB/PKCS5Padding -> 解密失败(bad decrypt)
加密:SM4/CBC/PKCS5Padding 解密:SM4/CBC/PKCS5Padding,IV 相同
CBC 模式下 IV 填错不会报错:开头 16 个字节是乱码,其余部分正常解出。如果只有明文开头坏了,先核对两边的 IV。
解密 IV 00000000000000000000000000000000 -> 开头乱码 + 「测试:订单号 20260911-0042」
解密 IV fedcba98765432100123456789abcdef -> 「国密 SM4 联调测试:订单号 20260911-0042」
Base64 和十六进制是同一串字节的两种写法。按错误的格式读取,从一开始交给算法的就是错误的输入。
9VIqdBnH9fiUiytTtZ5AzKLXFKdRvAuzmRI+ep/Yq88rOYRCktyEKHrREAfKKyYtuvG+CaDVjAlp4LvSpqtkaw== 按 Hex 读 -> 不是合法的十六进制
9VIqdBnH9fiUiytTtZ5AzKLXFKdRvAuzmRI+ep/Yq88rOYRCktyEKHrREAfKKyYtuvG+CaDVjAlp4LvSpqtkaw== 按 Base64 读 -> 64 字节
ZeroPadding 分不清哪些零是填充、哪些是数据,明文如果本来就以 0x00 结尾,这些字节会丢失。不是纯文本的数据请用 PKCS#7。
ZeroPadding:61 62 00 -> 解密得到 61 62
PKCS#7: 61 62 00 -> 解密得到 61 62 00
OpenSSL 把 sm4 当作 CBC;BouncyCastle——也就是 Hutool SmUtil.sm4(key) 的底层——把 SM4 当作 ECB + PKCS#7。两个系统都说「就用 SM4」,模式却可能不一样。
Java: Cipher.getInstance("SM4") -> ECB + PKCS#7
OpenSSL:openssl enc -sm4 -> CBC Java: Cipher.getInstance("SM4/CBC/PKCS5Padding")
OpenSSL:openssl enc -sm4-cbc Java 的 getBytes() 不指定字符集时使用平台默认编码,JDK 17 及以前在中文 Windows 上就是 GBK。同一段中文因此加密出不同的密文,另一端解出来就是乱码。
"国密SM4 test".getBytes() // 中文 Windows、JDK <= 17:GBK -> ECB 密文 3188d06cf28db70092f8753cbd5ee518
"国密SM4 test".getBytes(StandardCharsets.UTF_8) -> ECB 密文 d830308b0ae4fa7b9a2b5d59f7f65ca5
pay=100.00 变成 pay=900.00,解密照样成功。对 IV 和密文计算 MAC,解密前先校验,例如用 HMAC 生成器。0123456789abcdeffedcba9876543210 按十六进制读是 16 字节,按文本读却是 32 字节,会被直接拒绝。密钥框旁边的格式下拉框和字节数就是为此设计的。 PKCS5Padding 就是同一种填充——BouncyCastle 把这两个名字接到同一段代码上。ZeroPadding 只在不足一个分组时补 0x00;解密时 Hutool 和 BouncyCastle 会去掉末尾所有的 0x00,连数据里真正的零字节也一起去掉,而 Python 的 gmssl 只去掉一个。NoPadding 要求输入正好是 16 字节的整数倍。CTR、CFB、OFB 是流模式,从不填充。解密结果末尾多出空格、方框或换行,通常是填充没有去掉:PKCS#7 填充的数据按 NoPadding 解密,末尾会留下 n 个值为 n 的字节(0x09、0x0A、0x0D 会显示成制表符和换行);把输出切到 Hex,看最后一组就能认出来。 getBytes() 得到的是 GBK——以及结果怎么输出:Base64、小写十六进制还是大写十六进制。参数完全一致、IV 固定时,两个正确的实现输出必然相同。如果怀疑其中一个工具有问题,先用 GB/T 32907 标准测试向量把两边都验一遍。 0123456789abcdeffedcba9876543210 时,加密一次必须得到 681edf34d206965e86b3e94f536e4246,连续加密一百万次得到 595298c7c6fd271f0402f804c33d3f66。这两个向量只检验分组算法本身,所以接着再用固定的密钥和 IV 以 CBC 模式加密一段文本,和本页或本页给出的 OpenSSL 命令对比。本页背后的引擎已经对这两个向量做了断言,并在五种模式下与 OpenSSL 3 交叉校验。 openssl enc -sm4-cbc -K <32 位十六进制> -iv <32 位十六进制>:-K 直接接收十六进制的原始密钥,不经过口令派生;-nopad 关闭 PKCS#7 填充;-base64 -A 读写单行 Base64。有两处要当心:只写 -sm4 就是 CBC;-K 长度不对时会被截断或补零,只打印一句警告。本页的 OpenSSL 面板会按当前参数生成命令;openssl enc 不支持 ZeroPadding,这时面板会直接说明,而不是给出一条对不上的命令。 SmUtil.sm4(key) 只传算法名 SM4,由 BouncyCastle 补成 ECB + PKCS#7(Java 里叫 PKCS5Padding);只有写成 SM4/CBC/PKCS5Padding 这样的完整算法串才是 CBC。JavaScript 的 sm-crypto 默认也是 ECB,密钥是 32 位十六进制字符串,密文输出小写十六进制;gm-crypt 默认 CBC,密钥是 16 个字符的文本,输出 Base64。再确认明文字符集:Hutool 的字符串接口固定用 UTF-8,而直接调用 getBytes() 在 JDK 17 及更早的中文 Windows 上可能是 GBK,密文会不同。在 按对端库的默认参数 里选中对应的库可以一键对齐,也可以手动填写;有一项拿不准,照样把密文粘进来,自动排查会把模式、填充、IV 和编码的组合试一遍。 安全工具
在线解密 AES —— 支持 GCM/CBC/CTR、口令或原始密钥,自动识别 OpenSSL 与 CryptoJS 的 "U2FsdGVkX1" 格式。100% 浏览器本地运行,密钥永不离开页面。
安全工具
免费在线 AES 加密工具 — 支持 AES-128/192/256、GCM/CBC/CTR 模式,可用口令(PBKDF2)或原始密钥。100% 浏览器本地运行,不上传任何数据。
安全工具
在线生成并验证 bcrypt 密码哈希——可调成本因子,支持 $2b$/$2a$/$2y$ 前缀。100% 在浏览器中运行,密码绝不上传。
安全工具
CRC校验在线计算:粘贴十六进制或文本,一次算出 CRC-8/16/32 共 63 个变体,含 CRC16 Modbus。设备返回的值对不上时填进反查框,直接告诉你是哪个变体——MODBUS、CCITT-FALSE、XMODEM、KERMIT。全程浏览器本地计算。
安全工具
免费在线 HMAC 生成与校验工具。支持文本、Hex 或 Base64 密钥计算 HMAC-SHA256/SHA1/SHA384/SHA512,输出 Hex/Base64/Base64URL。100% 在浏览器中运行 —— 密钥永不离开页面。
安全工具
免费 JWT 解码器,在线即时解码 JWT 令牌。查看头部、载荷、签名以及过期时间、算法和声明详情。100% 浏览器本地运行——令牌绝不离开你的设备。无需注册、无跟踪。