add ECKeyUtil

This commit is contained in:
Looly 2020-09-13 03:43:33 +08:00
parent ac5728d410
commit 58b1cae320
4 changed files with 272 additions and 87 deletions

View File

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

View File

@ -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);
}
/**
* 将XY曲线点编码为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;
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}