Browse Source

add method

Looly 4 years ago
parent
commit
4c772ead35

+ 1 - 0
CHANGELOG.md

@@ -12,6 +12,7 @@
 * 【crypto 】     Sm2增加getD和getQ方法(issue#I37Z4C@Gitee)
 * 【cache  】     AbstractCache增加keySet方法(issue#I37Z4C@Gitee)
 * 【core   】     NumberWordFormatter增加formatSimple方法(pr#1436@Github)
+* 【crypto 】     增加读取openSSL生成的sm2私钥
 
 ### Bug修复
 * 【json   】     JSONUtil.isJson方法改变trim策略,解决特殊空白符导致判断失败问题

+ 22 - 0
hutool-crypto/src/main/java/cn/hutool/crypto/ECKeyUtil.java

@@ -1,5 +1,11 @@
 package cn.hutool.crypto;
 
+import cn.hutool.core.io.IORuntimeException;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.sec.ECPrivateKey;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
 import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
 import org.bouncycastle.crypto.params.ECDomainParameters;
 import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
@@ -8,6 +14,7 @@ import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
 import org.bouncycastle.math.ec.ECCurve;
 import org.bouncycastle.util.BigIntegers;
 
+import java.io.IOException;
 import java.math.BigInteger;
 import java.security.InvalidKeyException;
 import java.security.Key;
@@ -262,4 +269,19 @@ public class ECKeyUtil {
 			throw new CryptoException(e);
 		}
 	}
+
+	/**
+	 * 将SM2算法的{@link ECPrivateKey} 转换为 {@link PrivateKey}
+	 * @param privateKey {@link ECPrivateKey}
+	 * @return {@link PrivateKey}
+	 */
+	public static PrivateKey toSm2PrivateKey(ECPrivateKey privateKey){
+		try {
+			final PrivateKeyInfo info = new PrivateKeyInfo(
+					new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, SmUtil.ID_SM2_PUBLIC_KEY_PARAM), privateKey);
+			return KeyUtil.generatePrivateKey("SM2", info.getEncoded(ASN1Encoding.DER));
+		} catch (IOException e) {
+			throw new IORuntimeException(e);
+		}
+	}
 }

+ 12 - 0
hutool-crypto/src/main/java/cn/hutool/crypto/PemUtil.java

@@ -3,6 +3,7 @@ package cn.hutool.crypto;
 import cn.hutool.core.io.IORuntimeException;
 import cn.hutool.core.io.IoUtil;
 import cn.hutool.core.util.StrUtil;
+import org.bouncycastle.asn1.sec.ECPrivateKey;
 import org.bouncycastle.util.io.pem.PemObject;
 import org.bouncycastle.util.io.pem.PemObjectGenerator;
 import org.bouncycastle.util.io.pem.PemReader;
@@ -159,4 +160,15 @@ public class PemUtil {
 			IoUtil.close(writer);
 		}
 	}
+
+	/**
+	 * 读取OpenSSL生成的ANS1格式的Pem私钥文件
+	 *
+	 * @param keyStream 私钥pem流
+	 * @return {@link PrivateKey}
+	 */
+	public static PrivateKey readSm2PemPrivateKey(InputStream keyStream){
+		final ECPrivateKey ecPrivateKey = ECPrivateKey.getInstance(readPem(keyStream));
+		return ECKeyUtil.toSm2PrivateKey(ecPrivateKey);
+	}
 }

+ 7 - 7
hutool-crypto/src/main/java/cn/hutool/crypto/SmUtil.java

@@ -10,6 +10,7 @@ import cn.hutool.crypto.digest.mac.BCHMacEngine;
 import cn.hutool.crypto.digest.mac.MacEngine;
 import cn.hutool.crypto.symmetric.SM4;
 import cn.hutool.crypto.symmetric.SymmetricCrypto;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.gm.GMNamedCurves;
 import org.bouncycastle.crypto.digests.SM3Digest;
 import org.bouncycastle.crypto.params.ECDomainParameters;
@@ -31,6 +32,7 @@ import java.math.BigInteger;
  */
 public class SmUtil {
 
+	private final static int RS_LEN = 32;
 	/**
 	 * SM2默认曲线
 	 */
@@ -38,13 +40,11 @@ public class SmUtil {
 	/**
 	 * SM2推荐曲线参数(来自https://github.com/ZZMarquis/gmhelper)
 	 */
-	public static final ECDomainParameters SM2_DOMAIN_PARAMS;
-
-	private final static int RS_LEN = 32;
-
-	static {
-		SM2_DOMAIN_PARAMS = BCUtil.toDomainParams(GMNamedCurves.getByName(SM2_CURVE_NAME));
-	}
+	public static final ECDomainParameters SM2_DOMAIN_PARAMS = BCUtil.toDomainParams(GMNamedCurves.getByName(SM2_CURVE_NAME));
+	/**
+	 * SM2国密算法公钥参数的Oid标识
+ 	 */
+	public static final ASN1ObjectIdentifier ID_SM2_PUBLIC_KEY_PARAM = new ASN1ObjectIdentifier("1.2.156.10197.1.301");
 
 	/**
 	 * 创建SM2算法对象<br>

+ 12 - 4
hutool-crypto/src/test/java/cn/hutool/crypto/test/PemUtilTest.java

@@ -4,10 +4,11 @@ import cn.hutool.core.io.resource.ResourceUtil;
 import cn.hutool.crypto.PemUtil;
 import cn.hutool.crypto.asymmetric.KeyType;
 import cn.hutool.crypto.asymmetric.RSA;
+import cn.hutool.crypto.asymmetric.SM2;
 import org.junit.Assert;
-import org.junit.Ignore;
 import org.junit.Test;
 
+import java.nio.charset.StandardCharsets;
 import java.security.PrivateKey;
 import java.security.PublicKey;
 
@@ -45,9 +46,16 @@ public class PemUtilTest {
 	}
 
 	@Test
-	@Ignore
 	public void readECPrivateKeyTest() {
-		PrivateKey privateKey = PemUtil.readPemPrivateKey(ResourceUtil.getStream("test_ec_private_key.pem"));
-		Assert.assertNotNull(privateKey);
+		PrivateKey privateKey = PemUtil.readSm2PemPrivateKey(ResourceUtil.getStream("test_ec_private_key.pem"));
+		SM2 sm2 = new SM2(privateKey, null);
+		sm2.usePlainEncoding();
+
+		//需要签名的明文,得到明文对应的字节数组
+		byte[] dataBytes = "我是一段测试aaaa".getBytes(StandardCharsets.UTF_8);
+
+		byte[] sign = sm2.sign(dataBytes, null);
+		// 64位签名
+		Assert.assertEquals(64, sign.length);
 	}
 }