AES换成SM4就够了吗?国密算法迁移踩坑实录,附SM4/SM2完整代码和等保自查清单
等保2.0测评中"仍在使用国际算法"是最常见的扣分项之一。但把AES换成SM4就真的合规了吗?密钥管理怎么办?签名算法怎么选?本文从等保条款出发,梳理国密算法完整迁移路径,提供可直接使用的 SM4/SM2 Java代码和合规自查清单。
一、等保2.0密码要求:条款解读
1.1 核心条款
等保2.0三级系统中,与密码直接相关的条款集中在安全计算环境和安全通信网络两大类:
| 控制点 | 条款摘要 | 密码技术要求 |
|---|---|---|
| 身份鉴别 | 应采用两种以上鉴别技术 | 密码技术实现双因素认证 |
| 通信传输 | 传输数据完整性/保密性 | 国密算法加密传输通道 |
| 数据存储 | 存储数据完整性/保密性 | SM4加密敏感数据 |
| 日志审计 | 审计记录完整性保护 | SM3哈希 + HMAC |
| 密钥管理 | 密钥生命周期管理 | HSM/密钥管理平台支撑 |
1.2 密码法对金融行业的约束
《中华人民共和国密码法》2020年实施后,金融行业面临明确合规要求:
- 关键信息基础设施必须使用商用密码进行保护
- 涉及个人金融信息的加密存储,测评时优先检查是否采用国密算法
- 密码产品需通过国家密码管理局认证
1.3 金融机构常见的密码合规扣分项
TOP 1: 数据加密仍使用 AES-128/256,未迁移至 SM4 TOP 2: 数字签名使用 RSA-2048,未替换为 SM2 TOP 3: 哈希校验使用 SHA-256,未替换为 SM3 TOP 4: 密钥明文存储在配置文件中,无 HSM/密钥管理平台 TOP 5: SSL/TLS 证书使用国际算法,未切换国密双证书二、国密算法速查:SM1/SM2/SM3/SM4
| 算法 | 类型 | 密钥长度 | 等价国际算法 | 典型使用场景 |
|---|---|---|---|---|
| SM1 | 对称加密 | 128bit | AES-128 | 硬件加密机内部,不公开 |
| SM2 | 非对称加密 | 256bit | ECC-256/RSA-3072 | 数字签名、密钥交换、身份认证 |
| SM3 | 哈希算法 | 256bit | SHA-256 | 数据完整性校验、数字签名 |
| SM4 | 对称加密 | 128bit | AES-128 | 数据加密传输与存储 |
| SM9 | 标识密码 | — | IBC | 基于身份的加密(特定场景) |
选型决策原则
数据加密存储/传输 → SM4(对标 AES) 数字签名/验签 → SM2(对标 ECDSA/RSA) 完整性校验 → SM3(对标 SHA-256) 密钥协商 → SM2(对标 ECDH)三、AES → SM4 迁移实战:Java代码
3.1 原有 AES 加密代码(改造前)
// 传统的 AES-128-CBC 加密(不合规)publicclassAesEncryptor{privatestaticfinalStringALGO="AES/CBC/PKCS5Padding";privatefinalSecretKeykey;publicAesEncryptor(byte[]keyBytes){this.key=newSecretKeySpec(keyBytes,"AES");}publicbyte[]encrypt(byte[]plaintext)throwsException{Ciphercipher=Cipher.getInstance(ALGO);cipher.init(Cipher.ENCRYPT_MODE,key,newIvParameterSpec(newbyte[16]));returncipher.doFinal(plaintext);}publicbyte[]decrypt(byte[]ciphertext)throwsException{Ciphercipher=Cipher.getInstance(ALGO);cipher.init(Cipher.DECRYPT_MODE,key,newIvParameterSpec(newbyte[16]));returncipher.doFinal(ciphertext);}}3.2 替换为 SM4-CBC(改造后)
引入 BouncyCastle 国密支持:
Maven 依赖:
<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk18on</artifactId><version>1.78.1</version></dependency>SM4 加解密工具类:
importorg.bouncycastle.crypto.engines.SM4Engine;importorg.bouncycastle.crypto.modes.CBCBlockCipher;importorg.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;importorg.bouncycastle.crypto.params.KeyParameter;importorg.bouncycastle.crypto.params.ParametersWithIV;importorg.bouncycastle.util.encoders.Hex;importjavax.crypto.KeyGenerator;importjavax.crypto.SecretKey;importjava.security.SecureRandom;/** * SM4-CBC 加解密工具 * 替换原有的 AES-128-CBC 实现,满足等保2.0密码合规要求 */publicclassSM4Encryptor{privatestaticfinalintKEY_SIZE=128;// SM4 固定 128 位密钥privatestaticfinalintIV_SIZE=16;// SM4 块大小 16 字节privatefinalbyte[]key;privatefinalSecureRandomrandom=newSecureRandom();/** * 构造器:传入 16 字节(128位)密钥 */publicSM4Encryptor(byte[]key){if(key.length!=16){thrownewIllegalArgumentException("SM4 密钥长度必须为 16 字节");}this.key=key.clone();}/** * 生成随机 SM4 密钥 */publicstaticbyte[]generateKey()throwsException{KeyGeneratorkg=KeyGenerator.getInstance("SM4");kg.init(KEY_SIZE,newSecureRandom());returnkg.generateKey().getEncoded();}/** * SM4-CBC 加密 * @param plaintext 明文 * @return IV(16字节) + 密文 */publicbyte[]encrypt(byte[]plaintext){// 生成随机 IVbyte[]iv=newbyte[IV_SIZE];random.nextBytes(iv);PaddedBufferedBlockCiphercipher=newPaddedBufferedBlockCipher(newCBCBlockCipher(newSM4Engine()));cipher.init(true,newParametersWithIV(newKeyParameter(key),iv));byte[]output=newbyte[cipher.getOutputSize(plaintext.length)];intlen=cipher.processBytes(plaintext,0,plaintext.length,output,0);cipher.doFinal(output,len);// 拼接 IV + 密文,方便解密时提取byte[]result=newbyte[iv.length+output.length];System.arraycopy(iv,0,result,0,iv.length);System.arraycopy(output,0,result,iv.length,output.length);returnresult;}/** * SM4-CBC 解密 * @param ciphertext IV(16字节) + 密文 * @return 明文 */publicbyte[]decrypt(byte[]ciphertext){// 提取 IV 和密文byte[]iv=newbyte[IV_SIZE];byte[]encrypted=newbyte[ciphertext.length-IV_SIZE];System.arraycopy(ciphertext,0,iv,0,IV_SIZE);System.arraycopy(ciphertext,IV_SIZE,encrypted,0,encrypted.length);PaddedBufferedBlockCiphercipher=newPaddedBufferedBlockCipher(newCBCBlockCipher(newSM4Engine()));cipher.init(false,newParametersWithIV(newKeyParameter(key),iv));byte[]output=newbyte[cipher.getOutputSize(encrypted.length)];intlen=cipher.processBytes(encrypted,0,encrypted.length,output,0);cipher.doFinal(output,len);returnoutput;}/** * 加密并返回 Hex 编码字符串 */publicStringencryptToHex(StringplainText){byte[]encrypted=encrypt(plainText.getBytes());returnHex.toHexString(encrypted);}/** * 从 Hex 编码字符串解密 */publicStringdecryptFromHex(StringhexCipherText){byte[]ciphertext=Hex.decode(hexCipherText);returnnewString(decrypt(ciphertext));}// ===== 使用示例 =====publicstaticvoidmain(String[]args)throwsException{// 1. 生成密钥(生产环境应从 HSM 或密钥管理平台获取)byte[]key=generateKey();System.out.println("SM4 密钥: "+Hex.toHexString(key));SM4Encryptorencryptor=newSM4Encryptor(key);// 2. 加密敏感数据(如银行卡号、身份证号)StringsensitiveData="6222021234567890123";Stringencrypted=encryptor.encryptToHex(sensitiveData);System.out.println("密文: "+encrypted);// 3. 解密Stringdecrypted=encryptor.decryptFromHex(encrypted);System.out.println("解密: "+decrypted);System.out.println("验证: "+sensitiveData.equals(decrypted));}}3.3 迁移注意事项
| 迁移项 | AES 方案 | SM4 方案 | 注意事项 |
|---|---|---|---|
| 密钥长度 | 128/192/256 bit | 固定128 bit | SM4 只有 128 位 |
| 块大小 | 16 字节 | 16 字节 | 相同,兼容性好 |
| 填充模式 | PKCS5Padding | PKCS7Padding | 本质相同 |
| IV 长度 | 16 字节 | 16 字节 | 必须使用随机 IV |
| 性能 | AES-NI 硬件加速 | 国产 CPU 指令集 | 鲲鹏/飞腾有 SM4 加速 |
生产环境建议:SM4 密钥应通过硬件加密机(HSM)或密钥管理平台统一生成和管理,严禁硬编码在配置文件中。
四、SM2 数字签名替换 RSA
等保测评中另一高频扣分项:数字签名仍在使用 RSA。以下是 SM2 替换 RSA 的核心代码:
importorg.bouncycastle.crypto.digests.SM3Digest;importorg.bouncycastle.crypto.params.ECPrivateKeyParameters;importorg.bouncycastle.crypto.params.ECPublicKeyParameters;importorg.bouncycastle.crypto.signers.SM2Signer;importorg.bouncycastle.jce.ECNamedCurveTable;importorg.bouncycastle.jce.spec.ECNamedCurveParameterSpec;importjava.security.*;/** * SM2 数字签名工具(替换 RSA 签名) * SM2 签名速度约为 RSA-2048 的 3 倍,签名更短 */publicclassSM2SignerUtil{privatestaticfinalStringCURVE_NAME="sm2p256v1";/** * 生成 SM2 密钥对 */publicstaticKeyPairgenerateKeyPair()throwsException{ECNamedCurveParameterSpecspec=ECNamedCurveTable.getParameterSpec(CURVE_NAME);KeyPairGeneratorgen=KeyPairGenerator.getInstance("EC");gen.initialize(newjava.security.spec.ECGenParameterSpec(CURVE_NAME),newSecureRandom());returngen.generateKeyPair();}/** * SM2 签名(对标 RSA.sign) * 返回 r || s 格式的签名值 */publicstaticbyte[]sign(byte[]data,PrivateKeyprivateKey)throwsException{SM2Signersigner=newSM2Signer();ECPrivateKeyParametersprivParams=newECPrivateKeyParameters(((java.security.interfaces.ECPrivateKey)privateKey).getS(),ECNamedCurveTable.getParameterSpec(CURVE_NAME));signer.init(true,privParams);signer.update(data,0,data.length);returnsigner.generateSignature();}/** * SM2 验签 */publicstaticbooleanverify(byte[]data,byte[]signature,PublicKeypublicKey)throwsException{SM2Signersigner=newSM2Signer();ECPublicKeyParameterspubParams=newECPublicKeyParameters(((java.security.interfaces.ECPublicKey)publicKey).getQ(),ECNamedCurveTable.getParameterSpec(CURVE_NAME));signer.init(false,pubParams);signer.update(data,0,data.length);returnsigner.verifySignature(signature);}publicstaticvoidmain(String[]args)throwsException{KeyPairkeyPair=generateKeyPair();Stringmessage="转账指令:账户A向账户B转账10000元";byte[]signature=sign(message.getBytes(),keyPair.getPrivate());System.out.println("SM2 签名值: "+Hex.toHexString(signature));booleanvalid=verify(message.getBytes(),signature,keyPair.getPublic());System.out.println("验签结果: "+valid);}}五、密码产品合规自查清单
以下清单可直接用于等保测评前的自查。对照每一项打勾,确保合规:
5.1 算法合规自查
- 数据加密存储:敏感数据使用 SM4(非 AES)加密
- 数据加密传输:TLS 通道使用国密双证书(SM2 证书 + SM4 对称加密)
- 数字签名:使用 SM2 签名(非 RSA),如转账指令、电子合同
- 完整性校验:使用 SM3 哈希(非 SHA-256),如日志防篡改
- 密钥协商:使用 SM2 密钥交换(非 ECDH/RSA)
- MAC 计算:使用 SM3-HMAC(非 HMAC-SHA256)
5.2 密钥管理自查
- 密钥生成:由硬件加密机(HSM)生成,非应用层生成
- 密钥存储:密钥不在配置文件、代码、数据库中明文存储
- 密钥分发:通过安全通道或密钥管理平台分发
- 密钥轮换:定期轮换,支持在线轮换不影响业务
- 密钥销毁:已废弃密钥安全销毁,不可恢复
- 密钥备份:密钥备份采用密钥分拆/信封加密
5.3 密码产品认证自查
- 加密机:已获得《商用密码产品认证证书》
- 密钥管理系统:符合 GM/T 0018-2012 等国密标准
- 签名验签服务器:通过国密局检测认证
- SSL VPN 网关:支持国密 SM2/SM4 双证书
- 身份认证系统:支持动态口令/数字证书等多因素认证
5.4 密码应用合规自查
- 密码应用安全性评估(密评)已完成或已排期
- 密码模块安全检测报告在有效期内
- 国密算法改造进度覆盖所有核心系统
- 等保三级测评中密码相关项无扣分
六、总结
等保2.0对密码算法的要求已经从"建议"变为"强制",金融机构在进行系统改造时需要重点关注:
- 明确算法对标关系:SM4→AES、SM2→RSA/ECC、SM3→SHA-256
- 优先改造高风险项:数据加密存储和数字签名是最常见的扣分项
- 密钥管理是基础:不建密钥管理平台,算法替换等于白做——密钥明文放在配置文件里,换什么算法都不安全
- 代码改造不复杂:BouncyCastle 提供了完整的 SM2/SM3/SM4 实现,迁移成本可控
对于已有大量存量 AES 加密数据的系统,建议采用双密钥并行期方案:新数据用 SM4 加密,旧数据逐步解密重加密,通过版本标记区分算法类型,平滑过渡。
