|
|
@@ -0,0 +1,180 @@
|
|
|
+package com.jzg.commons.util.sm;
|
|
|
+
|
|
|
+import org.bouncycastle.asn1.x9.X9ECParameters;
|
|
|
+import org.bouncycastle.crypto.ec.CustomNamedCurves;
|
|
|
+import org.bouncycastle.crypto.engines.SM2Engine;
|
|
|
+import org.bouncycastle.crypto.params.ECDomainParameters;
|
|
|
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
|
|
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
|
|
+import org.bouncycastle.crypto.params.ParametersWithRandom;
|
|
|
+import org.bouncycastle.crypto.signers.SM2Signer;
|
|
|
+import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
|
|
|
+import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
|
|
|
+import org.bouncycastle.jce.ECNamedCurveTable;
|
|
|
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
|
|
+import org.bouncycastle.jce.spec.ECParameterSpec;
|
|
|
+import org.bouncycastle.jce.spec.ECPrivateKeySpec;
|
|
|
+import org.bouncycastle.util.encoders.Hex;
|
|
|
+
|
|
|
+import java.math.BigInteger;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.security.*;
|
|
|
+import java.security.spec.ECGenParameterSpec;
|
|
|
+import java.security.spec.PKCS8EncodedKeySpec;
|
|
|
+
|
|
|
+public class Sm2Util {
|
|
|
+ static {
|
|
|
+ // 注册 Bouncy Castle 提供者
|
|
|
+ Security.addProvider(new BouncyCastleProvider());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成SM2密钥对
|
|
|
+ */
|
|
|
+ public static KeyPair generateSM2KeyPair() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
|
|
|
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC");
|
|
|
+ ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec("sm2p256v1");
|
|
|
+ keyPairGenerator.initialize(ecGenParameterSpec, new SecureRandom());
|
|
|
+ return keyPairGenerator.generateKeyPair();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 公钥加密
|
|
|
+ */
|
|
|
+ public static String encrypt(String data, PublicKey publicKey) throws Exception {
|
|
|
+ SM2Engine engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
|
|
|
+ BCECPublicKey ecPublicKey = (BCECPublicKey) publicKey;
|
|
|
+ ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(ecPublicKey.getQ(), getDomainParameters());
|
|
|
+ engine.init(true, new ParametersWithRandom(publicKeyParameters, new SecureRandom()));
|
|
|
+
|
|
|
+ byte[] encryptedData = engine.processBlock(data.getBytes(StandardCharsets.UTF_8), 0, data.getBytes().length);
|
|
|
+ return Hex.toHexString(encryptedData);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 私钥解密
|
|
|
+ */
|
|
|
+ public static String decrypt(String encryptedData, PrivateKey privateKey) throws Exception {
|
|
|
+ SM2Engine engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
|
|
|
+ BCECPrivateKey ecPrivateKey = (BCECPrivateKey) privateKey;
|
|
|
+ ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(ecPrivateKey.getD(), getDomainParameters());
|
|
|
+ engine.init(false, privateKeyParameters);
|
|
|
+
|
|
|
+ byte[] decryptedData = engine.processBlock(Hex.decode(encryptedData), 0, Hex.decode(encryptedData).length);
|
|
|
+
|
|
|
+ return new String(decryptedData, StandardCharsets.UTF_8);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 公钥转换为 HEX 字符串
|
|
|
+ public static PrivateKey convertPKCS8HexToPrivateKey(String hexPrivateKey) throws Exception {
|
|
|
+ byte[] keyBytes = Hex.decode(hexPrivateKey);
|
|
|
+
|
|
|
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
|
|
|
+ KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC"); // SM2 属于 EC
|
|
|
+ return keyFactory.generatePrivate(keySpec);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 私钥签名
|
|
|
+ */
|
|
|
+ public static String sign(String data, PrivateKey privateKey) throws Exception {
|
|
|
+ SM2Signer signer = new SM2Signer();
|
|
|
+ BCECPrivateKey ecPrivateKey = (BCECPrivateKey) privateKey;
|
|
|
+ ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(ecPrivateKey.getD(), getDomainParameters());
|
|
|
+
|
|
|
+ signer.init(true, privateKeyParameters);
|
|
|
+ signer.update(data.getBytes(StandardCharsets.UTF_8), 0, data.getBytes().length);
|
|
|
+ byte[] signature = signer.generateSignature();
|
|
|
+
|
|
|
+ return Hex.toHexString(signature);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 公钥验签
|
|
|
+ */
|
|
|
+ public static boolean verify(String data, String signature, PublicKey publicKey) throws Exception {
|
|
|
+ SM2Signer signer = new SM2Signer();
|
|
|
+ BCECPublicKey ecPublicKey = (BCECPublicKey) publicKey;
|
|
|
+ ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(ecPublicKey.getQ(), getDomainParameters());
|
|
|
+
|
|
|
+ signer.init(false, publicKeyParameters);
|
|
|
+ signer.update(data.getBytes(StandardCharsets.UTF_8), 0, data.getBytes().length);
|
|
|
+
|
|
|
+ return signer.verifySignature(Hex.decode(signature));
|
|
|
+ }
|
|
|
+
|
|
|
+ private static ECDomainParameters getDomainParameters() {
|
|
|
+ X9ECParameters ecParameters = CustomNamedCurves.getByName("sm2p256v1");
|
|
|
+ return new ECDomainParameters(ecParameters.getCurve(), ecParameters.getG(), ecParameters.getN());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 测试
|
|
|
+ */
|
|
|
+ public static void main(String[] args) throws Exception {
|
|
|
+// // 生成SM2密钥对
|
|
|
+// KeyPair keyPair = generateSM2KeyPair();
|
|
|
+// PublicKey publicKey = keyPair.getPublic();
|
|
|
+// PrivateKey privateKey = keyPair.getPrivate();
|
|
|
+//
|
|
|
+// System.out.println("公钥: " + Hex.toHexString(publicKey.getEncoded()));
|
|
|
+// System.out.println("私钥: " + Hex.toHexString(privateKey.getEncoded()));
|
|
|
+//
|
|
|
+// // 待加密数据
|
|
|
+// String data = "Hello, SM2!";
|
|
|
+// System.out.println("原始数据: " + data);
|
|
|
+//
|
|
|
+// // 加密 & 解密
|
|
|
+// String encryptedData = encrypt(data, publicKey);
|
|
|
+// System.out.println("加密后: " + encryptedData);
|
|
|
+//
|
|
|
+// PrivateKey privateKey1 = convertPKCS8HexToPrivateKey(Hex.toHexString(privateKey.getEncoded()));
|
|
|
+//
|
|
|
+// String decryptedData = decrypt(encryptedData, privateKey1);
|
|
|
+// System.out.println("解密后: " + decryptedData);
|
|
|
+//
|
|
|
+// // 签名 & 验签
|
|
|
+// String signature = sign(data, privateKey);
|
|
|
+// System.out.println("签名: " + signature);
|
|
|
+//
|
|
|
+// boolean isVerified = verify(data, signature, publicKey);
|
|
|
+// System.out.println("验签结果: " + isVerified);
|
|
|
+
|
|
|
+ // 添加 BouncyCastle 提供者
|
|
|
+ Security.addProvider(new BouncyCastleProvider());
|
|
|
+
|
|
|
+ // 假设这是你的私钥(需要与公钥配对)
|
|
|
+ String privateKeyHex = "308193020100301306072a8648ce3d020106082a811ccf5501822d047930770201010420c882022305a8e374fdd57d7e49ffb09187e8457a952ada2a25b03aa8834819e0a00a06082a811ccf5501822da14403420004704fb361c034bdf3ef03f8d3e95c797fdcecf34853d86e7ff01631d2a7f57c99d1ced5de038ae593cd176e587099029b3b6dc9f2e985c4e6071aad35604db327"; // 替换为你的私钥
|
|
|
+ BigInteger privateKeyD = new BigInteger(privateKeyHex, 16);
|
|
|
+
|
|
|
+ // 加密数据
|
|
|
+ String encryptedDataHex = "8326f09eaca513fd50b7c57dfb23f65729485e44003e10c7dfb68a6988c1a416314850d01114e48fd89c5d95501c7c835cd2ad4d9ae279eaf231615e25711caf3c70d5b9cb7c5acbe8218893a84e0c0cb1f864397a7f209cee95aad6954307543acd1c515ea20adc4d23a6afbbc9015fb6b8505c2028d54e5c410772205861f7";
|
|
|
+
|
|
|
+ // 获取 SM2 椭圆曲线参数
|
|
|
+ ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("sm2p256v1");
|
|
|
+
|
|
|
+ // 将 ECParameterSpec 转换为 ECDomainParameters
|
|
|
+ ECDomainParameters domainParameters = new ECDomainParameters(
|
|
|
+ ecSpec.getCurve(), // 椭圆曲线
|
|
|
+ ecSpec.getG(), // 基点 G
|
|
|
+ ecSpec.getN(), // 阶数 n
|
|
|
+ ecSpec.getH() // 余因子 h
|
|
|
+ );
|
|
|
+
|
|
|
+ // 创建 ECPrivateKeyParameters
|
|
|
+ ECPrivateKeyParameters privateKey = new ECPrivateKeyParameters(privateKeyD, domainParameters);
|
|
|
+
|
|
|
+ // 解析加密数据
|
|
|
+ byte[] encryptedData = Hex.decode(encryptedDataHex);
|
|
|
+
|
|
|
+ // 初始化 SM2 解密引擎
|
|
|
+ SM2Engine sm2Engine = new SM2Engine();
|
|
|
+ sm2Engine.init(false, privateKey);
|
|
|
+
|
|
|
+ // 解密
|
|
|
+ byte[] decryptedData = sm2Engine.processBlock(encryptedData, 0, encryptedData.length);
|
|
|
+
|
|
|
+ // 输出解密结果
|
|
|
+ System.out.println("Decrypted Data: " + Hex.toHexString(decryptedData));
|
|
|
+ }
|
|
|
+}
|