文章目录
在 Java 开发中使用国密算法(即中国国家密码管理局发布的商用密码标准算法,如 SM2、SM3、SM4 等)通常需要借助第三方库,因为标准的 Java Cryptography Extension (JCE) 并不直接支持这些算法。
下面是一些常用的实现方式和推荐库:
✅ 一、常用国密算法介绍
算法 | 类型 | 描述 |
---|---|---|
SM2 | 非对称加密 / 数字签名 | 基于椭圆曲线公钥密码,用于数字签名、密钥交换等。 |
SM3 | 哈希算法 | 输出长度为 256 位的哈希值,类似于 SHA-256。 |
SM4 | 对称加密 | 分组密码,128 位块大小,128 位密钥,ECB/CBC 模式。 |
✅ 二、Java 实现国密算法的推荐方式
方式 1:使用 Bouncy Castle
(最常见)
Bouncy Castle 是一个广泛使用的开源 Java 加密库,支持 SM2/SM3/SM4 等国密算法。
🔧 使用步骤:
- 添加依赖(Maven)
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>prov-jdk15on</artifactId>
<version>1.72</version> <!-- 可选最新版本 -->
</dependency>
- 注册 Bouncy Castle 提供者
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.Security;
static {
Security.addProvider(new BouncyCastleProvider());
}
- 示例:实现SM2包括生成密钥对、签名与验证、加密与解密
生成密钥对
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.ec.CustomNamedCurves;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECPoint;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.ECGenParameterSpec;
public class SM2Example {
public static KeyPair generateKeyPair() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPair/XMLSchemaDoc.createElement("KeyPairGenerator");
keyPairGenerator.initialize(new ECGenParameterSpec("sm2p256v1"));
return keyPairGenerator.generateKeyPair();
}
// 示例调用
public static void main(String[] args) throws Exception {
KeyPair keyPair = generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
System.out.println("Private Key: " + privateKey);
System.out.println("Public Key: " + publicKey);
}
}
签名和验证
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
import java.security.Signature;
public class SM2Example {
public static byte[] sign(PrivateKey privateKey, byte[] message) throws Exception {
Signature signature = Signature.getInstance("SM3withSM2", new BouncyCastleProvider());
signature.initSign(privateKey);
signature.update(message);
return signature.sign();
}
public static boolean verify(PublicKey publicKey, byte[] message, byte[] sign) throws Exception {
Signature signature = Signature.getInstance("SM3withSM2", new BouncyCastleProvider());
signature.initVerify(publicKey);
signature.update(message);
return signature.verify(sign);
}
public static void main(String[] args) throws Exception {
KeyPair keyPair = generateKeyPair();
String msg = "Hello World!";
byte[] sign = sign(keyPair.getPrivate(), msg.getBytes());
System.out.println("Signature: " + Hex.toHexString(sign));
boolean isVerify = verify(keyPair.getPublic(), msg.getBytes(), sign);
System.out.println("Verify result: " + isVerify);
}
}
加密和解密(可选)
对于 SM2 来说,通常更多地用于数字签名而不是加密。但是,如果需要进行加密操作,可以参考如下方式:
// 注意:这里的加密/解密可能需要根据具体需求调整,因为SM2标准主要针对签名和密钥交换。
// 下面只是一个简化的例子,实际应用中应考虑更多的细节如密钥格式转换等。
public static byte[] encrypt(PublicKey publicKey, byte[] data) throws Exception {
// 这里简化了加密过程,真实场景中需要处理更多细节
throw new UnsupportedOperationException("Encrypt operation for SM2 is not directly supported.");
}
public static byte[] decrypt(PrivateKey privateKey, byte[] encryptedData) throws Exception {
// 类似于加密,解密也需要特别处理
throw new UnsupportedOperationException("Decrypt operation for SM2 is not directly supported.");
}
- 示例:SM3 哈希计算
import org.bouncycastle.crypto.digests.SM3Digest;
public class SM3Example {
public static byte[] hash(byte[] input) {
SM3Digest digest = new SM3Digest();
digest.update(input, 0, input.length);
byte[] hash = new byte[digest.getDigestSize()];
digest.doFinal(hash, 0);
return hash;
}
public static void main(String[] args) {
String msg = "Hello,国密!";
byte[] hash = hash(msg.getBytes());
System.out.println(Hex.toHexString(hash));
}
}
- SM4 加解密示例
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.Security;
public class SM4Example {
static {
Security.addProvider(new BouncyCastleProvider());
}
public static byte[] encrypt(byte[] key, byte[] data) throws Exception {
Cipher cipher = Cipher.getInstance("SM4/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "SM4"));
return cipher.doFinal(data);
}
public static byte[] decrypt(byte[] key, byte[] cipherText) throws Exception {
Cipher cipher = Cipher.getInstance("SM4/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "SM4"));
return cipher.doFinal(cipherText);
}
public static void main(String[] args) throws Exception {
byte[] key = "1234567890abcdef".getBytes(); // 16 bytes
byte[] data = "Hello,SM4!".getBytes();
byte[] encrypted = encrypt(key, data);
System.out.println("Encrypted: " + Hex.toHexString(encrypted));
byte[] decrypted = decrypt(key, encrypted);
System.out.println("Decrypted: " + new String(decrypted));
}
}
方式 2:使用国产 SDK(如:江南天安、三未信安、卫士通等厂商提供的 HSM 或 SDK)
如果你在银行、金融或政务系统中开发,可能需要使用硬件安全模块(HSM)来执行国密算法,这类设备通常提供 Java SDK 接口。
方式 3:自研封装(适合定制化需求)
对于有特殊合规要求的场景,可基于国密标准文档自行实现 SM2/SM3/SM4,但需注意以下几点:
- 需要理解国密算法规范(GB/T 32918、GB/T 32905、GB/T 34957)
- 自行实现容易出错,建议仅用于学习或已有完整测试用例时使用
✅ 三、辅助工具类:Hex 编码转换
public class Hex {
private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray();
public static String toHexString(byte[] data) {
StringBuilder sb = new StringBuilder(data.length * 2);
for (byte b : data) {
sb.append(HEX_CHARS[(b >> 4) & 0x0f]);
sb.append(HEX_CHARS[b & 0x0f]);
}
return sb.toString();
}
}
✅ 四、注意事项
-
Bouncy Castle 的 Provider 名称问题
- 在 Android 中使用时需要注意兼容性,某些方法名或类名可能不同。
- 推荐使用
org.bouncycastle:crypto-ext
或SpongyCastle
(Android 适配版)。
-
算法模式
- SM4 支持 ECB、CBC 等模式,加密时需选择合适的填充方式(如 PKCS5Padding)。
-
证书与签名验证(SM2)
- SM2 不仅可用于加密,还可用于签名和验签,通常配合 X.509 证书使用。