Browse Source

add ECKeyUtil

Looly 5 years ago
parent
commit
58b1cae320

+ 1 - 0
CHANGELOG.md

@@ -10,6 +10,7 @@
 * 【setting】     Setting增加store无参方法(issue#1072@Github)
 * 【setting】     StatementUtil增加null缓存(pr#1076@Github)
 * 【core   】     扩充Console功能,支持可变参数(issue#1077@Github)
+* 【crypto 】     增加ECKeyUtil(issue#I1UOF5@Gitee)
 
 ### Bug修复
 * 【core   】     修复Dict.of错误(issue#I1UUO5@Gitee)

+ 7 - 87
hutool-crypto/src/main/java/cn/hutool/crypto/BCUtil.java

@@ -172,7 +172,7 @@ public class BCUtil {
 	 * @return ECPrivateKeyParameters
 	 */
 	public static ECPrivateKeyParameters toParams(String dHex, ECDomainParameters domainParameters) {
-		return toParams(new BigInteger(dHex, 16), domainParameters);
+		return ECKeyUtil.toPrivateParams(dHex, domainParameters);
 	}
 
 	/**
@@ -193,7 +193,7 @@ public class BCUtil {
 	 * @return ECPrivateKeyParameters
 	 */
 	public static ECPrivateKeyParameters toParams(byte[] d, ECDomainParameters domainParameters) {
-		return toParams(new BigInteger(d), domainParameters);
+		return ECKeyUtil.toPrivateParams(d, domainParameters);
 	}
 
 	/**
@@ -214,10 +214,7 @@ public class BCUtil {
 	 * @return ECPrivateKeyParameters
 	 */
 	public static ECPrivateKeyParameters toParams(BigInteger d, ECDomainParameters domainParameters) {
-		if(null == d){
-			return null;
-		}
-		return new ECPrivateKeyParameters(d, domainParameters);
+		return ECKeyUtil.toPrivateParams(d, domainParameters);
 	}
 
 	/**
@@ -229,10 +226,7 @@ public class BCUtil {
 	 * @return ECPublicKeyParameters
 	 */
 	public static ECPublicKeyParameters toParams(BigInteger x, BigInteger y, ECDomainParameters domainParameters) {
-		if(null == x || null == y){
-			return null;
-		}
-		return toParams(x.toByteArray(), y.toByteArray(), domainParameters);
+		return ECKeyUtil.toPublicParams(x, y, domainParameters);
 	}
 
 	/**
@@ -278,13 +272,7 @@ public class BCUtil {
 	 * @return ECPublicKeyParameters
 	 */
 	public static ECPublicKeyParameters toParams(byte[] xBytes, byte[] yBytes, ECDomainParameters domainParameters) {
-		if(null == xBytes || null == yBytes){
-			return null;
-		}
-		final ECCurve curve = domainParameters.getCurve();
-		final int curveLength = getCurveLength(curve);
-		final byte[] encodedPubKey = encodePoint(xBytes, yBytes, curveLength);
-		return new ECPublicKeyParameters(curve.decodePoint(encodedPubKey), domainParameters);
+		return ECKeyUtil.toPublicParams(xBytes, yBytes, domainParameters);
 	}
 
 	/**
@@ -294,14 +282,7 @@ public class BCUtil {
 	 * @return {@link ECPublicKeyParameters}或null
 	 */
 	public static ECPublicKeyParameters toParams(PublicKey publicKey) {
-		if (null == publicKey) {
-			return null;
-		}
-		try {
-			return (ECPublicKeyParameters) ECUtil.generatePublicKeyParameter(publicKey);
-		} catch (InvalidKeyException e) {
-			throw new CryptoException(e);
-		}
+		return ECKeyUtil.toPublicParams(publicKey);
 	}
 
 	/**
@@ -311,14 +292,7 @@ public class BCUtil {
 	 * @return {@link ECPrivateKeyParameters}或null
 	 */
 	public static ECPrivateKeyParameters toParams(PrivateKey privateKey) {
-		if (null == privateKey) {
-			return null;
-		}
-		try {
-			return (ECPrivateKeyParameters) ECUtil.generatePrivateKeyParameter(privateKey);
-		} catch (InvalidKeyException e) {
-			throw new CryptoException(e);
-		}
+		return ECKeyUtil.toPrivateParams(privateKey);
 	}
 
 	/**
@@ -344,58 +318,4 @@ public class BCUtil {
 	public static PublicKey readPemPublicKey(InputStream pemStream) {
 		return PemUtil.readPemPublicKey(pemStream);
 	}
-
-	/**
-	 * 将X,Y曲线点编码为bytes
-	 *
-	 * @param xBytes      X坐标bytes
-	 * @param yBytes      Y坐标bytes
-	 * @param curveLength 曲线编码后的长度
-	 * @return 编码bytes
-	 */
-	private static byte[] encodePoint(byte[] xBytes, byte[] yBytes, int curveLength) {
-		xBytes = fixLength(curveLength, xBytes);
-		yBytes = fixLength(curveLength, yBytes);
-		final byte[] encodedPubKey = new byte[1 + xBytes.length + yBytes.length];
-
-		// 压缩类型:无压缩
-		encodedPubKey[0] = 0x04;
-		System.arraycopy(xBytes, 0, encodedPubKey, 1, xBytes.length);
-		System.arraycopy(yBytes, 0, encodedPubKey, 1 + xBytes.length, yBytes.length);
-
-		return encodedPubKey;
-	}
-
-	/**
-	 * 获取Curve长度
-	 *
-	 * @param curve {@link ECCurve}
-	 * @return Curve长度
-	 */
-	private static int getCurveLength(ECCurve curve) {
-		return (curve.getFieldSize() + 7) / 8;
-	}
-
-	/**
-	 * 修正长度
-	 *
-	 * @param curveLength 修正后的长度
-	 * @param src         bytes
-	 * @return 修正后的bytes
-	 */
-	private static byte[] fixLength(int curveLength, byte[] src) {
-		if (src.length == curveLength) {
-			return src;
-		}
-
-		byte[] result = new byte[curveLength];
-		if (src.length > curveLength) {
-			// 裁剪末尾的指定长度
-			System.arraycopy(src, src.length - result.length, result, 0, result.length);
-		} else {
-			// 放置于末尾
-			System.arraycopy(src, 0, result, result.length - src.length, src.length);
-		}
-		return result;
-	}
 }

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

@@ -0,0 +1,244 @@
+package cn.hutool.crypto;
+
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.util.BigIntegers;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * EC密钥参数相关工具类封装
+ *
+ * @author looly
+ * @since 5.4.3
+ */
+public class ECKeyUtil {
+
+	//--------------------------------------------------------------------------- Public Key
+	/**
+	 * 转换为 ECPublicKeyParameters
+	 *
+	 * @param q 公钥Q值
+	 * @return ECPublicKeyParameters
+	 */
+	public static ECPublicKeyParameters toSm2PublicParams(byte[] q) {
+		return toPublicParams(q, SmUtil.SM2_DOMAIN_PARAMS);
+	}
+
+	/**
+	 * 转换为 ECPublicKeyParameters
+	 *
+	 * @param q 公钥Q值
+	 * @return ECPublicKeyParameters
+	 */
+	public static ECPublicKeyParameters toSm2PublicParams(String q) {
+		return toPublicParams(q, SmUtil.SM2_DOMAIN_PARAMS);
+	}
+
+	/**
+	 * 转换为SM2的ECPublicKeyParameters
+	 *
+	 * @param x 公钥X
+	 * @param y 公钥Y
+	 * @return ECPublicKeyParameters
+	 */
+	public static ECPublicKeyParameters toSm2PublicParams(String x, String y) {
+		return toPublicParams(x, y, SmUtil.SM2_DOMAIN_PARAMS);
+	}
+
+	/**
+	 * 转换为SM2的ECPublicKeyParameters
+	 *
+	 * @param xBytes 公钥X
+	 * @param yBytes 公钥Y
+	 * @return ECPublicKeyParameters
+	 */
+	public static ECPublicKeyParameters toSm2PublicParams(byte[] xBytes, byte[] yBytes) {
+		return toPublicParams(xBytes, yBytes, SmUtil.SM2_DOMAIN_PARAMS);
+	}
+
+	/**
+	 * 转换为ECPublicKeyParameters
+	 *
+	 * @param x             公钥X
+	 * @param y             公钥Y
+	 * @param domainParameters ECDomainParameters
+	 * @return ECPublicKeyParameters
+	 */
+	public static ECPublicKeyParameters toPublicParams(String x, String y, ECDomainParameters domainParameters) {
+		return toPublicParams(SecureUtil.decode(x), SecureUtil.decode(y), domainParameters);
+	}
+
+	/**
+	 * 转换为ECPublicKeyParameters
+	 *
+	 * @param xBytes           公钥X
+	 * @param yBytes           公钥Y
+	 * @param domainParameters ECDomainParameters曲线参数
+	 * @return ECPublicKeyParameters
+	 */
+	public static ECPublicKeyParameters toPublicParams(byte[] xBytes, byte[] yBytes, ECDomainParameters domainParameters) {
+		return toPublicParams(BigIntegers.fromUnsignedByteArray(xBytes), BigIntegers.fromUnsignedByteArray(yBytes), domainParameters);
+	}
+
+	/**
+	 * 转换为ECPublicKeyParameters
+	 *
+	 * @param x                公钥X
+	 * @param y                公钥Y
+	 * @param domainParameters ECDomainParameters
+	 * @return ECPublicKeyParameters
+	 */
+	public static ECPublicKeyParameters toPublicParams(BigInteger x, BigInteger y, ECDomainParameters domainParameters) {
+		if (null == x || null == y) {
+			return null;
+		}
+		final ECCurve curve = domainParameters.getCurve();
+		return toPublicParams(curve.createPoint(x, y), domainParameters);
+	}
+
+	/**
+	 * 转换为ECPublicKeyParameters
+	 *
+	 * @param pointEncoded     被编码的曲线坐标点
+	 * @param domainParameters ECDomainParameters
+	 * @return ECPublicKeyParameters
+	 * @since 5.4.3
+	 */
+	public static ECPublicKeyParameters toPublicParams(String pointEncoded, ECDomainParameters domainParameters) {
+		final ECCurve curve = domainParameters.getCurve();
+		return toPublicParams(curve.decodePoint(SecureUtil.decode(pointEncoded)), domainParameters);
+	}
+
+	/**
+	 * 转换为ECPublicKeyParameters
+	 *
+	 * @param pointEncoded     被编码的曲线坐标点
+	 * @param domainParameters ECDomainParameters
+	 * @return ECPublicKeyParameters
+	 * @since 5.4.3
+	 */
+	public static ECPublicKeyParameters toPublicParams(byte[] pointEncoded, ECDomainParameters domainParameters) {
+		final ECCurve curve = domainParameters.getCurve();
+		return toPublicParams(curve.decodePoint(pointEncoded), domainParameters);
+	}
+
+	/**
+	 * 转换为ECPublicKeyParameters
+	 *
+	 * @param point            曲线坐标点
+	 * @param domainParameters ECDomainParameters
+	 * @return ECPublicKeyParameters
+	 * @since 5.4.3
+	 */
+	public static ECPublicKeyParameters toPublicParams(org.bouncycastle.math.ec.ECPoint point, ECDomainParameters domainParameters) {
+		return new ECPublicKeyParameters(point, domainParameters);
+	}
+
+	/**
+	 * 公钥转换为 {@link ECPublicKeyParameters}
+	 *
+	 * @param publicKey 公钥,传入null返回null
+	 * @return {@link ECPublicKeyParameters}或null
+	 */
+	public static ECPublicKeyParameters toPublicParams(PublicKey publicKey) {
+		if (null == publicKey) {
+			return null;
+		}
+		try {
+			return (ECPublicKeyParameters) ECUtil.generatePublicKeyParameter(publicKey);
+		} catch (InvalidKeyException e) {
+			throw new CryptoException(e);
+		}
+	}
+
+	//--------------------------------------------------------------------------- Private Key
+	/**
+	 * 转换为 ECPrivateKeyParameters
+	 *
+	 * @param d 私钥d值16进制字符串
+	 * @return ECPrivateKeyParameters
+	 */
+	public static ECPrivateKeyParameters toSm2PrivateParams(String d) {
+		return toPrivateParams(d, SmUtil.SM2_DOMAIN_PARAMS);
+	}
+
+	/**
+	 * 转换为 ECPrivateKeyParameters
+	 *
+	 * @param d 私钥d值
+	 * @return ECPrivateKeyParameters
+	 */
+	public static ECPrivateKeyParameters toSm2PrivateParams(byte[] d) {
+		return toPrivateParams(d, SmUtil.SM2_DOMAIN_PARAMS);
+	}
+
+	/**
+	 * 转换为 ECPrivateKeyParameters
+	 *
+	 * @param d 私钥d值
+	 * @return ECPrivateKeyParameters
+	 */
+	public static ECPrivateKeyParameters toSm2PrivateParams(BigInteger d) {
+		return toPrivateParams(d, SmUtil.SM2_DOMAIN_PARAMS);
+	}
+
+	/**
+	 * 转换为 ECPrivateKeyParameters
+	 *
+	 * @param d             私钥d值16进制字符串
+	 * @param domainParameters ECDomainParameters
+	 * @return ECPrivateKeyParameters
+	 */
+	public static ECPrivateKeyParameters toPrivateParams(String d, ECDomainParameters domainParameters) {
+		return toPrivateParams(BigIntegers.fromUnsignedByteArray(SecureUtil.decode(d)), domainParameters);
+	}
+
+	/**
+	 * 转换为 ECPrivateKeyParameters
+	 *
+	 * @param d                私钥d值
+	 * @param domainParameters ECDomainParameters
+	 * @return ECPrivateKeyParameters
+	 */
+	public static ECPrivateKeyParameters toPrivateParams(byte[] d, ECDomainParameters domainParameters) {
+		return toPrivateParams(BigIntegers.fromUnsignedByteArray(d), domainParameters);
+	}
+
+	/**
+	 * 转换为 ECPrivateKeyParameters
+	 *
+	 * @param d                私钥d值
+	 * @param domainParameters ECDomainParameters
+	 * @return ECPrivateKeyParameters
+	 */
+	public static ECPrivateKeyParameters toPrivateParams(BigInteger d, ECDomainParameters domainParameters) {
+		if (null == d) {
+			return null;
+		}
+		return new ECPrivateKeyParameters(d, domainParameters);
+	}
+
+	/**
+	 * 私钥转换为 {@link ECPrivateKeyParameters}
+	 *
+	 * @param privateKey 私钥,传入null返回null
+	 * @return {@link ECPrivateKeyParameters}或null
+	 */
+	public static ECPrivateKeyParameters toPrivateParams(PrivateKey privateKey) {
+		if (null == privateKey) {
+			return null;
+		}
+		try {
+			return (ECPrivateKeyParameters) ECUtil.generatePrivateKeyParameter(privateKey);
+		} catch (InvalidKeyException e) {
+			throw new CryptoException(e);
+		}
+	}
+}

+ 20 - 0
hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/SM2Test.java

@@ -4,12 +4,15 @@ import cn.hutool.core.codec.Base64;
 import cn.hutool.core.util.CharsetUtil;
 import cn.hutool.core.util.HexUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.ECKeyUtil;
 import cn.hutool.crypto.KeyUtil;
 import cn.hutool.crypto.SecureUtil;
 import cn.hutool.crypto.SmUtil;
 import cn.hutool.crypto.asymmetric.KeyType;
 import cn.hutool.crypto.asymmetric.SM2;
 import org.bouncycastle.crypto.engines.SM2Engine;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -205,4 +208,21 @@ public class SM2Test {
 		String sign = "DCA0E80A7F46C93714B51C3EFC55A922BCEF7ECF0FE9E62B53BA6A7438B543A76C145A452CA9036F3CB70D7E6C67D4D9D7FE114E5367A2F6F5A4D39F2B10F3D6";
 		Assert.assertTrue(sm2.verifyHex(data, sign));
 	}
+
+	@Test
+	public void sm2PlainWithPointTest2() {
+		String d = "4BD9A450D7E68A5D7E08EB7A0BFA468FD3EB32B71126246E66249A73A9E4D44A";
+		String q = "04970AB36C3B870FBC04041087DB1BC36FB4C6E125B5EA406DB0EC3E2F80F0A55D8AFF28357A0BB215ADC2928BE76F1AFF869BF4C0A3852A78F3B827812C650AD3";
+
+		String data = "123456";
+
+		final ECPublicKeyParameters ecPublicKeyParameters = ECKeyUtil.toSm2PublicParams(q);
+		final ECPrivateKeyParameters ecPrivateKeyParameters = ECKeyUtil.toSm2PrivateParams(d);
+
+		final SM2 sm2 = new SM2(ecPrivateKeyParameters, ecPublicKeyParameters);
+		final String encryptHex = sm2.encryptHex(data, KeyType.PublicKey);
+		final String decryptStr = sm2.decryptStr(encryptHex, KeyType.PrivateKey);
+
+		Assert.assertEquals(data, decryptStr);
+	}
 }