mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
support x,y for sm2
This commit is contained in:
parent
f37c1d529a
commit
f6585adec4
@ -22,6 +22,7 @@
|
||||
* 【crypto】 增加PemUtil工具类
|
||||
* 【dfa 】 WordTree增加Filter,支持自定义特殊字符过滤器
|
||||
* 【poi 】 对于POI依赖升级到4.1.2
|
||||
* 【crypto】 增加国密SM2验签密钥格式支持(issue#686@Github)
|
||||
|
||||
### Bug修复
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cn.hutool.core.util;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
@ -198,6 +199,7 @@ public class HexUtil {
|
||||
if (StrUtil.isEmpty(hexStr)) {
|
||||
return null;
|
||||
}
|
||||
hexStr = StrUtil.removeAll(hexStr, ' ');
|
||||
return decodeHex(hexStr.toCharArray());
|
||||
}
|
||||
|
||||
@ -338,6 +340,19 @@ public class HexUtil {
|
||||
builder.append(toDigits[low]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hex(16进制)字符串转为BigInteger
|
||||
* @param hexStr Hex(16进制字符串)
|
||||
* @return {@link BigInteger}
|
||||
* @since 5.2.0
|
||||
*/
|
||||
public static BigInteger toBigInteger(String hexStr){
|
||||
if(null == hexStr){
|
||||
return null;
|
||||
}
|
||||
return new BigInteger(hexStr, 16);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------- Private method start
|
||||
|
||||
/**
|
||||
|
@ -38,4 +38,11 @@ public class HexUtilTest {
|
||||
boolean isHex = HexUtil.isHexNumber(a);
|
||||
Assert.assertTrue(isHex);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decodeTest(){
|
||||
String str = "e8c670380cb220095268f40221fc748fa6ac39d6e930e63c30da68bad97f885d";
|
||||
Assert.assertArrayEquals(HexUtil.decodeHex(str),
|
||||
HexUtil.decodeHex(str.toUpperCase()));
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +1,27 @@
|
||||
package cn.hutool.crypto;
|
||||
|
||||
import cn.hutool.core.util.HexUtil;
|
||||
import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
|
||||
import org.bouncycastle.crypto.params.ECDomainParameters;
|
||||
import org.bouncycastle.crypto.params.ECKeyParameters;
|
||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||
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.ECPointUtil;
|
||||
import org.bouncycastle.jce.interfaces.ECKey;
|
||||
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
|
||||
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
|
||||
import org.bouncycastle.jce.spec.ECParameterSpec;
|
||||
import org.bouncycastle.math.ec.ECCurve;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.ECFieldFp;
|
||||
import java.security.spec.ECPoint;
|
||||
import java.security.spec.ECPublicKeySpec;
|
||||
import java.security.spec.EllipticCurve;
|
||||
|
||||
/**
|
||||
* Bouncy Castle相关工具类封装
|
||||
@ -70,68 +68,99 @@ public class BCUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 解码恢复EC压缩公钥,支持Base64和Hex编码,(基于BouncyCastle)<br>
|
||||
* 见:https://www.cnblogs.com/xinzhao/p/8963724.html
|
||||
* 解码恢复EC压缩公钥,支持Base64和Hex编码,(基于BouncyCastle)
|
||||
*
|
||||
* @param encodeByte 压缩公钥
|
||||
* @param curveName EC曲线名,例如{@link KeyUtil#SM2_DEFAULT_CURVE}
|
||||
* @param curveName EC曲线名,例如{@link SmUtil#SM2_DOMAIN_PARAMS}
|
||||
* @return 公钥
|
||||
* @since 4.4.4
|
||||
*/
|
||||
public static PublicKey decodeECPoint(byte[] encodeByte, String curveName) {
|
||||
final ECNamedCurveParameterSpec namedSpec = ECNamedCurveTable.getParameterSpec(curveName);
|
||||
final ECCurve curve = namedSpec.getCurve();
|
||||
final EllipticCurve ecCurve = new EllipticCurve(//
|
||||
new ECFieldFp(curve.getField().getCharacteristic()), //
|
||||
curve.getA().toBigInteger(), //
|
||||
curve.getB().toBigInteger());
|
||||
// 根据X恢复点Y
|
||||
final ECPoint point = ECPointUtil.decodePoint(ecCurve, encodeByte);
|
||||
final X9ECParameters x9ECParameters = ECUtil.getNamedCurveByName(curveName);
|
||||
final ECCurve curve = x9ECParameters.getCurve();
|
||||
final ECPoint point = EC5Util.convertPoint(curve.decodePoint(encodeByte));
|
||||
|
||||
// 根据曲线恢复公钥格式
|
||||
ECNamedCurveSpec ecSpec = new ECNamedCurveSpec(curveName, curve, namedSpec.getG(), namedSpec.getN());
|
||||
final ECNamedCurveSpec ecSpec = new ECNamedCurveSpec(curveName, curve, x9ECParameters.getG(), x9ECParameters.getN());
|
||||
|
||||
final KeyFactory PubKeyGen = KeyUtil.getKeyFactory("EC");
|
||||
try {
|
||||
return PubKeyGen.generatePublic(new ECPublicKeySpec(point, ecSpec));
|
||||
return KeyUtil.getKeyFactory("EC").generatePublic(new ECPublicKeySpec(point, ecSpec));
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new CryptoException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ECKey转换为ECKeyParameters
|
||||
* 构建ECDomainParameters对象
|
||||
*
|
||||
* @param ecKey BCECPrivateKey或者BCECPublicKey
|
||||
* @return ECPrivateKeyParameters或者ECPublicKeyParameters
|
||||
* @since 5.1.6
|
||||
* @param parameterSpec ECParameterSpec
|
||||
* @return {@link ECDomainParameters}
|
||||
* @since 5.2.0
|
||||
*/
|
||||
public static ECKeyParameters toParams(ECKey ecKey) {
|
||||
final ECParameterSpec parameterSpec = ecKey.getParameters();
|
||||
final ECDomainParameters ecDomainParameters = toDomainParameters(parameterSpec);
|
||||
public static ECDomainParameters toDomainParams(ECParameterSpec parameterSpec) {
|
||||
return new ECDomainParameters(
|
||||
parameterSpec.getCurve(),
|
||||
parameterSpec.getG(),
|
||||
parameterSpec.getN(),
|
||||
parameterSpec.getH());
|
||||
}
|
||||
|
||||
if (ecKey instanceof BCECPrivateKey) {
|
||||
return new ECPrivateKeyParameters(((BCECPrivateKey) ecKey).getD(), ecDomainParameters);
|
||||
} else if (ecKey instanceof BCECPublicKey) {
|
||||
return new ECPublicKeyParameters(((BCECPublicKey) ecKey).getQ(), ecDomainParameters);
|
||||
/**
|
||||
* 构建ECDomainParameters对象
|
||||
*
|
||||
* @param curveName Curve名称
|
||||
* @return {@link ECDomainParameters}
|
||||
* @since 5.2.0
|
||||
*/
|
||||
public static ECDomainParameters toDomainParams(String curveName) {
|
||||
return toDomainParams(ECUtil.getNamedCurveByName(curveName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建ECDomainParameters对象
|
||||
*
|
||||
* @param x9ECParameters {@link X9ECParameters}
|
||||
* @return {@link ECDomainParameters}
|
||||
* @since 5.2.0
|
||||
*/
|
||||
public static ECDomainParameters toDomainParams(X9ECParameters x9ECParameters) {
|
||||
return new ECDomainParameters(
|
||||
x9ECParameters.getCurve(),
|
||||
x9ECParameters.getG(),
|
||||
x9ECParameters.getN(),
|
||||
x9ECParameters.getH()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 密钥转换为AsymmetricKeyParameter
|
||||
*
|
||||
* @param key PrivateKey或者PublicKey
|
||||
* @return ECPrivateKeyParameters或者ECPublicKeyParameters
|
||||
* @since 5.2.0
|
||||
*/
|
||||
public static AsymmetricKeyParameter toParams(Key key) {
|
||||
try {
|
||||
if (key instanceof PrivateKey) {
|
||||
return ECUtil.generatePrivateKeyParameter((PrivateKey) key);
|
||||
} else if (key instanceof PublicKey) {
|
||||
return ECUtil.generatePublicKeyParameter((PublicKey) key);
|
||||
}
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new CryptoException(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建ECDomainParameters对象
|
||||
* 转换为 ECPrivateKeyParameters
|
||||
*
|
||||
* @param parameterSpec ECParameterSpec
|
||||
* @return ECDomainParameters
|
||||
* @since 5.1.6
|
||||
* @param dHex 私钥d值16进制字符串
|
||||
* @return ECPrivateKeyParameters
|
||||
*/
|
||||
public static ECDomainParameters toDomainParameters(ECParameterSpec parameterSpec) {
|
||||
return new ECDomainParameters(
|
||||
parameterSpec.getCurve(),
|
||||
parameterSpec.getG(),
|
||||
parameterSpec.getN(),
|
||||
parameterSpec.getH());
|
||||
public static ECPrivateKeyParameters toSm2Params(String dHex) {
|
||||
return toSm2Params(HexUtil.toBigInteger(dHex));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,7 +171,38 @@ public class BCUtil {
|
||||
* @return ECPrivateKeyParameters
|
||||
*/
|
||||
public static ECPrivateKeyParameters toParams(String dHex, ECDomainParameters domainParameters) {
|
||||
return new ECPrivateKeyParameters(new BigInteger(dHex, 16), domainParameters);
|
||||
return toParams(new BigInteger(dHex, 16), domainParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为 ECPrivateKeyParameters
|
||||
*
|
||||
* @param d 私钥d值
|
||||
* @return ECPrivateKeyParameters
|
||||
*/
|
||||
public static ECPrivateKeyParameters toSm2Params(byte[] d) {
|
||||
return toSm2Params(new BigInteger(d));
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为 ECPrivateKeyParameters
|
||||
*
|
||||
* @param d 私钥d值
|
||||
* @param domainParameters ECDomainParameters
|
||||
* @return ECPrivateKeyParameters
|
||||
*/
|
||||
public static ECPrivateKeyParameters toParams(byte[] d, ECDomainParameters domainParameters) {
|
||||
return toParams(new BigInteger(d), domainParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为 ECPrivateKeyParameters
|
||||
*
|
||||
* @param d 私钥d值
|
||||
* @return ECPrivateKeyParameters
|
||||
*/
|
||||
public static ECPrivateKeyParameters toSm2Params(BigInteger d) {
|
||||
return toParams(d, SmUtil.SM2_DOMAIN_PARAMS);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -153,6 +213,9 @@ public class BCUtil {
|
||||
* @return ECPrivateKeyParameters
|
||||
*/
|
||||
public static ECPrivateKeyParameters toParams(BigInteger d, ECDomainParameters domainParameters) {
|
||||
if(null == d){
|
||||
return null;
|
||||
}
|
||||
return new ECPrivateKeyParameters(d, domainParameters);
|
||||
}
|
||||
|
||||
@ -161,12 +224,25 @@ public class BCUtil {
|
||||
*
|
||||
* @param x 公钥X
|
||||
* @param y 公钥Y
|
||||
* @param curve ECCurve
|
||||
* @param domainParameters ECDomainParameters
|
||||
* @return ECPublicKeyParameters
|
||||
*/
|
||||
public static ECPublicKeyParameters toParams(BigInteger x, BigInteger y, ECCurve curve, ECDomainParameters domainParameters) {
|
||||
return toParams(x.toByteArray(), y.toByteArray(), curve, domainParameters);
|
||||
public static ECPublicKeyParameters toParams(BigInteger x, BigInteger y, ECDomainParameters domainParameters) {
|
||||
if(null == x || null == y){
|
||||
return null;
|
||||
}
|
||||
return toParams(x.toByteArray(), y.toByteArray(), domainParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为SM2的ECPublicKeyParameters
|
||||
*
|
||||
* @param xHex 公钥X
|
||||
* @param yHex 公钥Y
|
||||
* @return ECPublicKeyParameters
|
||||
*/
|
||||
public static ECPublicKeyParameters toSm2Params(String xHex, String yHex) {
|
||||
return toParams(xHex, yHex, SmUtil.SM2_DOMAIN_PARAMS);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -174,13 +250,22 @@ public class BCUtil {
|
||||
*
|
||||
* @param xHex 公钥X
|
||||
* @param yHex 公钥Y
|
||||
* @param curve ECCurve
|
||||
* @param domainParameters ECDomainParameters
|
||||
* @return ECPublicKeyParameters
|
||||
*/
|
||||
public static ECPublicKeyParameters toParams(String xHex, String yHex, ECCurve curve, ECDomainParameters domainParameters) {
|
||||
return toParams(HexUtil.decodeHex(xHex), HexUtil.decodeHex(yHex),
|
||||
curve, domainParameters);
|
||||
public static ECPublicKeyParameters toParams(String xHex, String yHex, ECDomainParameters domainParameters) {
|
||||
return toParams(HexUtil.decodeHex(xHex), HexUtil.decodeHex(yHex), domainParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为SM2的ECPublicKeyParameters
|
||||
*
|
||||
* @param xBytes 公钥X
|
||||
* @param yBytes 公钥Y
|
||||
* @return ECPublicKeyParameters
|
||||
*/
|
||||
public static ECPublicKeyParameters toSm2Params(byte[] xBytes, byte[] yBytes) {
|
||||
return toParams(xBytes, yBytes, SmUtil.SM2_DOMAIN_PARAMS);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -188,47 +273,89 @@ public class BCUtil {
|
||||
*
|
||||
* @param xBytes 公钥X
|
||||
* @param yBytes 公钥Y
|
||||
* @param curve ECCurve
|
||||
* @param domainParameters ECDomainParameters
|
||||
* @return ECPublicKeyParameters
|
||||
*/
|
||||
public static ECPublicKeyParameters toParams(byte[] xBytes, byte[] yBytes, ECCurve curve, ECDomainParameters domainParameters) {
|
||||
final byte uncompressedFlag = 0x04;
|
||||
int curveLength = getCurveLength(domainParameters);
|
||||
xBytes = fixLength(curveLength, xBytes);
|
||||
yBytes = fixLength(curveLength, yBytes);
|
||||
byte[] encodedPubKey = new byte[1 + xBytes.length + yBytes.length];
|
||||
encodedPubKey[0] = uncompressedFlag;
|
||||
System.arraycopy(xBytes, 0, encodedPubKey, 1, xBytes.length);
|
||||
System.arraycopy(yBytes, 0, encodedPubKey, 1 + xBytes.length, yBytes.length);
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Curve长度
|
||||
* 公钥转换为 {@link ECPublicKeyParameters}
|
||||
*
|
||||
* @param ecKey Curve
|
||||
* @return Curve长度
|
||||
* @param publicKey 公钥,传入null返回null
|
||||
* @return {@link ECPublicKeyParameters}或null
|
||||
*/
|
||||
public static int getCurveLength(ECKeyParameters ecKey) {
|
||||
return getCurveLength(ecKey.getParameters());
|
||||
public static ECPublicKeyParameters toParams(PublicKey publicKey) {
|
||||
if (null == publicKey) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return (ECPublicKeyParameters) ECUtil.generatePublicKeyParameter(publicKey);
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new CryptoException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 私钥转换为 {@link ECPrivateKeyParameters}
|
||||
*
|
||||
* @param privateKey 私钥,传入null返回null
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将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 domainParams ECDomainParameters
|
||||
* @param curve {@link ECCurve}
|
||||
* @return Curve长度
|
||||
*/
|
||||
public static int getCurveLength(ECDomainParameters domainParams) {
|
||||
return (domainParams.getCurve().getFieldSize() + 7) / 8;
|
||||
private static int getCurveLength(ECCurve curve) {
|
||||
return (curve.getFieldSize() + 7) / 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修正长度
|
||||
*
|
||||
* @param curveLength 修正后的长度
|
||||
* @param src bytes
|
||||
* @param src bytes
|
||||
* @return 修正后的bytes
|
||||
*/
|
||||
private static byte[] fixLength(int curveLength, byte[] src) {
|
||||
|
@ -93,7 +93,7 @@ public class KeyUtil {
|
||||
* Default SM2 curve
|
||||
* </pre>
|
||||
*/
|
||||
public static final String SM2_DEFAULT_CURVE = "sm2p256v1";
|
||||
public static final String SM2_DEFAULT_CURVE = SmUtil.SM2_CURVE_NAME;
|
||||
|
||||
/**
|
||||
* 生成 {@link SecretKey},仅用于对称加密和摘要算法密钥生成
|
||||
|
@ -13,10 +13,9 @@ import org.bouncycastle.asn1.ASN1EncodableVector;
|
||||
import org.bouncycastle.asn1.ASN1Integer;
|
||||
import org.bouncycastle.asn1.ASN1Sequence;
|
||||
import org.bouncycastle.asn1.DERSequence;
|
||||
import org.bouncycastle.asn1.gm.GMNamedCurves;
|
||||
import org.bouncycastle.crypto.digests.SM3Digest;
|
||||
import org.bouncycastle.crypto.params.ECDomainParameters;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.bouncycastle.math.ec.custom.gm.SM2P256V1Curve;
|
||||
import org.bouncycastle.util.Arrays;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
|
||||
@ -28,30 +27,31 @@ import java.math.BigInteger;
|
||||
/**
|
||||
* SM国密算法工具类<br>
|
||||
* 此工具类依赖org.bouncycastle:bcpkix-jdk15on
|
||||
*
|
||||
*
|
||||
* @author looly
|
||||
* @since 4.3.2
|
||||
*/
|
||||
public class SmUtil {
|
||||
|
||||
/*
|
||||
/**
|
||||
* SM2默认曲线
|
||||
*/
|
||||
public static final String SM2_CURVE_NAME = "sm2p256v1";
|
||||
/**
|
||||
* SM2推荐曲线参数(来自https://github.com/ZZMarquis/gmhelper)
|
||||
*/
|
||||
public static final SM2P256V1Curve CURVE = new SM2P256V1Curve();
|
||||
public final static BigInteger SM2_ECC_GX = new BigInteger(
|
||||
"32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16);
|
||||
public final static BigInteger SM2_ECC_GY = new BigInteger(
|
||||
"BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16);
|
||||
public static final ECPoint G_POINT = CURVE.createPoint(SM2_ECC_GX, SM2_ECC_GY);
|
||||
public static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters(CURVE, G_POINT,
|
||||
CURVE.getOrder(), CURVE.getCofactor());
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建SM2算法对象<br>
|
||||
* 生成新的私钥公钥对
|
||||
*
|
||||
*
|
||||
* @return {@link SM2}
|
||||
*/
|
||||
public static SM2 sm2() {
|
||||
@ -62,9 +62,9 @@ public class SmUtil {
|
||||
* 创建SM2算法对象<br>
|
||||
* 私钥和公钥同时为空时生成一对新的私钥和公钥<br>
|
||||
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
|
||||
*
|
||||
*
|
||||
* @param privateKeyStr 私钥Hex或Base64表示
|
||||
* @param publicKeyStr 公钥Hex或Base64表示
|
||||
* @param publicKeyStr 公钥Hex或Base64表示
|
||||
* @return {@link SM2}
|
||||
*/
|
||||
public static SM2 sm2(String privateKeyStr, String publicKeyStr) {
|
||||
@ -75,9 +75,9 @@ public class SmUtil {
|
||||
* 创建SM2算法对象<br>
|
||||
* 私钥和公钥同时为空时生成一对新的私钥和公钥<br>
|
||||
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
|
||||
*
|
||||
*
|
||||
* @param privateKey 私钥
|
||||
* @param publicKey 公钥
|
||||
* @param publicKey 公钥
|
||||
* @return {@link SM2}
|
||||
*/
|
||||
public static SM2 sm2(byte[] privateKey, byte[] publicKey) {
|
||||
@ -89,7 +89,7 @@ public class SmUtil {
|
||||
* 例:<br>
|
||||
* SM3加密:sm3().digest(data)<br>
|
||||
* SM3加密并转为16进制字符串:sm3().digestHex(data)<br>
|
||||
*
|
||||
*
|
||||
* @return {@link SM3}
|
||||
*/
|
||||
public static SM3 sm3() {
|
||||
@ -98,7 +98,7 @@ public class SmUtil {
|
||||
|
||||
/**
|
||||
* SM3加密,生成16进制SM3字符串<br>
|
||||
*
|
||||
*
|
||||
* @param data 数据
|
||||
* @return SM3字符串
|
||||
*/
|
||||
@ -108,7 +108,7 @@ public class SmUtil {
|
||||
|
||||
/**
|
||||
* SM3加密,生成16进制SM3字符串<br>
|
||||
*
|
||||
*
|
||||
* @param data 数据
|
||||
* @return SM3字符串
|
||||
*/
|
||||
@ -118,7 +118,7 @@ public class SmUtil {
|
||||
|
||||
/**
|
||||
* SM3加密文件,生成16进制SM3字符串<br>
|
||||
*
|
||||
*
|
||||
* @param dataFile 被加密文件
|
||||
* @return SM3字符串
|
||||
*/
|
||||
@ -129,12 +129,12 @@ public class SmUtil {
|
||||
/**
|
||||
* SM4加密,生成随机KEY。注意解密时必须使用相同 {@link SymmetricCrypto}对象或者使用相同KEY<br>
|
||||
* 例:
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* SM4加密:sm4().encrypt(data)
|
||||
* SM4解密:sm4().decrypt(data)
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @return {@link SymmetricCrypto}
|
||||
*/
|
||||
public static SM4 sm4() {
|
||||
@ -144,12 +144,12 @@ public class SmUtil {
|
||||
/**
|
||||
* SM4加密<br>
|
||||
* 例:
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* SM4加密:sm4(key).encrypt(data)
|
||||
* SM4解密:sm4(key).decrypt(data)
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return {@link SymmetricCrypto}
|
||||
*/
|
||||
@ -159,8 +159,8 @@ public class SmUtil {
|
||||
|
||||
/**
|
||||
* bc加解密使用旧标c1||c2||c3,此方法在加密后调用,将结果转化为c1||c3||c2
|
||||
*
|
||||
* @param c1c2c3 加密后的bytes,顺序为C1C2C3
|
||||
*
|
||||
* @param c1c2c3 加密后的bytes,顺序为C1C2C3
|
||||
* @param ecDomainParameters {@link ECDomainParameters}
|
||||
* @return 加密后的bytes,顺序为C1C3C2
|
||||
*/
|
||||
@ -177,8 +177,8 @@ public class SmUtil {
|
||||
|
||||
/**
|
||||
* bc加解密使用旧标c1||c3||c2,此方法在解密前调用,将密文转化为c1||c2||c3再去解密
|
||||
*
|
||||
* @param c1c3c2 加密后的bytes,顺序为C1C3C2
|
||||
*
|
||||
* @param c1c3c2 加密后的bytes,顺序为C1C3C2
|
||||
* @param ecDomainParameters {@link ECDomainParameters}
|
||||
* @return c1c2c3 加密后的bytes,顺序为C1C2C3
|
||||
*/
|
||||
@ -196,7 +196,7 @@ public class SmUtil {
|
||||
/**
|
||||
* BC的SM3withSM2签名得到的结果的rs是asn1格式的,这个方法转化成直接拼接r||s<br>
|
||||
* 来自:https://blog.csdn.net/pridas/article/details/86118774
|
||||
*
|
||||
*
|
||||
* @param rsDer rs in asn1 format
|
||||
* @return sign result in plain byte array
|
||||
* @since 4.5.0
|
||||
@ -208,13 +208,14 @@ public class SmUtil {
|
||||
byte[] result = new byte[RS_LEN * 2];
|
||||
System.arraycopy(r, 0, result, 0, r.length);
|
||||
System.arraycopy(s, 0, result, RS_LEN, s.length);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* BC的SM3withSM2验签需要的rs是asn1格式的,这个方法将直接拼接r||s的字节数组转化成asn1格式<br>
|
||||
* 来自:https://blog.csdn.net/pridas/article/details/86118774
|
||||
*
|
||||
*
|
||||
* @param sign in plain byte array
|
||||
* @return rs result in asn1 format
|
||||
* @since 4.5.0
|
||||
@ -237,7 +238,7 @@ public class SmUtil {
|
||||
|
||||
/**
|
||||
* 创建HmacSM3算法的{@link MacEngine}
|
||||
*
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return {@link MacEngine}
|
||||
* @since 4.5.13
|
||||
@ -248,7 +249,7 @@ public class SmUtil {
|
||||
|
||||
/**
|
||||
* HmacSM3算法实现
|
||||
*
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return {@link HMac} 对象,调用digestXXX即可
|
||||
* @since 4.5.13
|
||||
@ -258,9 +259,10 @@ public class SmUtil {
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------- Private method start
|
||||
|
||||
/**
|
||||
* BigInteger转固定长度bytes
|
||||
*
|
||||
*
|
||||
* @param rOrS {@link BigInteger}
|
||||
* @return 固定长度bytes
|
||||
* @since 4.5.0
|
||||
|
@ -1,5 +1,10 @@
|
||||
package cn.hutool.crypto.asymmetric;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.crypto.CryptoException;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
|
||||
import java.security.Key;
|
||||
import java.security.KeyPair;
|
||||
import java.security.PrivateKey;
|
||||
@ -7,37 +12,42 @@ import java.security.PublicKey;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.crypto.CryptoException;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
|
||||
/**
|
||||
* 非对称基础,提供锁、私钥和公钥的持有
|
||||
*
|
||||
*
|
||||
* @author Looly
|
||||
* @since 3.3.0
|
||||
*/
|
||||
public class BaseAsymmetric<T extends BaseAsymmetric<T>>{
|
||||
public class BaseAsymmetric<T extends BaseAsymmetric<T>> {
|
||||
|
||||
/** 算法 */
|
||||
/**
|
||||
* 算法
|
||||
*/
|
||||
protected String algorithm;
|
||||
/** 公钥 */
|
||||
/**
|
||||
* 公钥
|
||||
*/
|
||||
protected PublicKey publicKey;
|
||||
/** 私钥 */
|
||||
/**
|
||||
* 私钥
|
||||
*/
|
||||
protected PrivateKey privateKey;
|
||||
/** 锁 */
|
||||
/**
|
||||
* 锁
|
||||
*/
|
||||
protected final Lock lock = new ReentrantLock();
|
||||
|
||||
// ------------------------------------------------------------------ Constructor start
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* <p>
|
||||
* 私钥和公钥同时为空时生成一对新的私钥和公钥<br>
|
||||
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
|
||||
*
|
||||
* @param algorithm 算法
|
||||
*
|
||||
* @param algorithm 算法
|
||||
* @param privateKey 私钥
|
||||
* @param publicKey 公钥
|
||||
* @param publicKey 公钥
|
||||
* @since 3.1.1
|
||||
*/
|
||||
public BaseAsymmetric(String algorithm, PrivateKey privateKey, PublicKey publicKey) {
|
||||
@ -49,10 +59,10 @@ public class BaseAsymmetric<T extends BaseAsymmetric<T>>{
|
||||
* 初始化<br>
|
||||
* 私钥和公钥同时为空时生成一对新的私钥和公钥<br>
|
||||
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密(签名)或者解密(校验)
|
||||
*
|
||||
* @param algorithm 算法
|
||||
*
|
||||
* @param algorithm 算法
|
||||
* @param privateKey 私钥
|
||||
* @param publicKey 公钥
|
||||
* @param publicKey 公钥
|
||||
* @return this
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -74,7 +84,7 @@ public class BaseAsymmetric<T extends BaseAsymmetric<T>>{
|
||||
|
||||
/**
|
||||
* 生成公钥和私钥
|
||||
*
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -86,9 +96,10 @@ public class BaseAsymmetric<T extends BaseAsymmetric<T>>{
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------- Getters and Setters
|
||||
|
||||
/**
|
||||
* 获得公钥
|
||||
*
|
||||
*
|
||||
* @return 获得公钥
|
||||
*/
|
||||
public PublicKey getPublicKey() {
|
||||
@ -97,7 +108,7 @@ public class BaseAsymmetric<T extends BaseAsymmetric<T>>{
|
||||
|
||||
/**
|
||||
* 获得公钥
|
||||
*
|
||||
*
|
||||
* @return 获得公钥
|
||||
*/
|
||||
public String getPublicKeyBase64() {
|
||||
@ -107,7 +118,7 @@ public class BaseAsymmetric<T extends BaseAsymmetric<T>>{
|
||||
|
||||
/**
|
||||
* 设置公钥
|
||||
*
|
||||
*
|
||||
* @param publicKey 公钥
|
||||
* @return this
|
||||
*/
|
||||
@ -119,7 +130,7 @@ public class BaseAsymmetric<T extends BaseAsymmetric<T>>{
|
||||
|
||||
/**
|
||||
* 获得私钥
|
||||
*
|
||||
*
|
||||
* @return 获得私钥
|
||||
*/
|
||||
public PrivateKey getPrivateKey() {
|
||||
@ -128,7 +139,7 @@ public class BaseAsymmetric<T extends BaseAsymmetric<T>>{
|
||||
|
||||
/**
|
||||
* 获得私钥
|
||||
*
|
||||
*
|
||||
* @return 获得私钥
|
||||
*/
|
||||
public String getPrivateKeyBase64() {
|
||||
@ -137,7 +148,7 @@ public class BaseAsymmetric<T extends BaseAsymmetric<T>>{
|
||||
|
||||
/**
|
||||
* 设置私钥
|
||||
*
|
||||
*
|
||||
* @param privateKey 私钥
|
||||
* @return this
|
||||
*/
|
||||
@ -147,24 +158,42 @@ public class BaseAsymmetric<T extends BaseAsymmetric<T>>{
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置密钥,可以是公钥{@link PublicKey}或者私钥{@link PrivateKey}
|
||||
*
|
||||
* @param key 密钥,可以是公钥{@link PublicKey}或者私钥{@link PrivateKey}
|
||||
* @return this
|
||||
* @since 5.2.0
|
||||
*/
|
||||
public T setKey(Key key) {
|
||||
Assert.notNull(key, "key must be not null !");
|
||||
|
||||
if (key instanceof PublicKey) {
|
||||
return setPublicKey((PublicKey) key);
|
||||
} else if (key instanceof PrivateKey) {
|
||||
return setPrivateKey((PrivateKey) key);
|
||||
}
|
||||
throw new CryptoException("Unsupported key type: {}", key.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据密钥类型获得相应密钥
|
||||
*
|
||||
*
|
||||
* @param type 类型 {@link KeyType}
|
||||
* @return {@link Key}
|
||||
*/
|
||||
protected Key getKeyByType(KeyType type) {
|
||||
switch (type) {
|
||||
case PrivateKey:
|
||||
if (null == this.privateKey) {
|
||||
throw new NullPointerException("Private key must not null when use it !");
|
||||
}
|
||||
return this.privateKey;
|
||||
case PublicKey:
|
||||
if (null == this.publicKey) {
|
||||
throw new NullPointerException("Public key must not null when use it !");
|
||||
}
|
||||
return this.publicKey;
|
||||
case PrivateKey:
|
||||
if (null == this.privateKey) {
|
||||
throw new NullPointerException("Private key must not null when use it !");
|
||||
}
|
||||
return this.privateKey;
|
||||
case PublicKey:
|
||||
if (null == this.publicKey) {
|
||||
throw new NullPointerException("Public key must not null when use it !");
|
||||
}
|
||||
return this.publicKey;
|
||||
}
|
||||
throw new CryptoException("Uknown key type: " + type);
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
package cn.hutool.crypto.asymmetric;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.HexUtil;
|
||||
import cn.hutool.crypto.BCUtil;
|
||||
import cn.hutool.crypto.CryptoException;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import org.bouncycastle.crypto.CipherParameters;
|
||||
@ -10,9 +13,7 @@ import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.bouncycastle.crypto.params.ParametersWithID;
|
||||
import org.bouncycastle.crypto.params.ParametersWithRandom;
|
||||
import org.bouncycastle.crypto.signers.SM2Signer;
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
|
||||
@ -83,7 +84,56 @@ public class SM2 extends AbstractAsymmetricCrypto<SM2> {
|
||||
* @param publicKey 公钥
|
||||
*/
|
||||
public SM2(PrivateKey privateKey, PublicKey publicKey) {
|
||||
super(ALGORITHM_SM2, privateKey, publicKey);
|
||||
this(BCUtil.toParams(privateKey), BCUtil.toParams(publicKey));
|
||||
if (null != privateKey) {
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
if (null != publicKey) {
|
||||
this.publicKey = publicKey;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造 <br>
|
||||
* 私钥和公钥同时为空时生成一对新的私钥和公钥<br>
|
||||
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
|
||||
*
|
||||
* @param privateKeyHex 私钥16进制
|
||||
* @param publicKeyPointXHex 公钥X16进制
|
||||
* @param publicKeyPointYHex 公钥Y16进制
|
||||
* @since 5.2.0
|
||||
*/
|
||||
public SM2(String privateKeyHex, String publicKeyPointXHex, String publicKeyPointYHex) {
|
||||
this(BCUtil.toSm2Params(privateKeyHex), BCUtil.toSm2Params(publicKeyPointXHex, publicKeyPointYHex));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造 <br>
|
||||
* 私钥和公钥同时为空时生成一对新的私钥和公钥<br>
|
||||
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
|
||||
*
|
||||
* @param privateKey 私钥
|
||||
* @param publicKeyPointX 公钥X
|
||||
* @param publicKeyPointY 公钥Y
|
||||
* @since 5.2.0
|
||||
*/
|
||||
public SM2(byte[] privateKey, byte[] publicKeyPointX, byte[] publicKeyPointY) {
|
||||
this(BCUtil.toSm2Params(privateKey), BCUtil.toSm2Params(publicKeyPointX, publicKeyPointY));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造 <br>
|
||||
* 私钥和公钥同时为空时生成一对新的私钥和公钥<br>
|
||||
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
|
||||
*
|
||||
* @param privateKeyParams 私钥
|
||||
* @param publicKeyParams 公钥
|
||||
*/
|
||||
public SM2(ECPrivateKeyParameters privateKeyParams, ECPublicKeyParameters publicKeyParams) {
|
||||
super(ALGORITHM_SM2, null, null);
|
||||
this.privateKeyParams = privateKeyParams;
|
||||
this.publicKeyParams = publicKeyParams;
|
||||
this.init();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------ Constructor end
|
||||
@ -93,18 +143,22 @@ public class SM2 extends AbstractAsymmetricCrypto<SM2> {
|
||||
* 私钥和公钥同时为空时生成一对新的私钥和公钥<br>
|
||||
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密(签名)或者解密(校验)
|
||||
*
|
||||
* @param privateKey 私钥
|
||||
* @param publicKey 公钥
|
||||
* @return this
|
||||
*/
|
||||
public SM2 init(PrivateKey privateKey, PublicKey publicKey) {
|
||||
return this.init(ALGORITHM_SM2, privateKey, publicKey);
|
||||
public SM2 init() {
|
||||
if (null == this.privateKeyParams && null == this.publicKeyParams) {
|
||||
super.initKeys();
|
||||
this.privateKeyParams = BCUtil.toParams(this.privateKey);
|
||||
this.publicKeyParams = BCUtil.toParams(this.publicKey);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SM2 init(String algorithm, PrivateKey privateKey, PublicKey publicKey) {
|
||||
super.init(algorithm, privateKey, publicKey);
|
||||
return initCipherParams();
|
||||
public SM2 initKeys() {
|
||||
// 阻断父类中自动生成密钥对的操作,此操作由本类中进行。
|
||||
// 由于用户可能传入Params而非key,因此此时key必定为null,故此不再生成
|
||||
return this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------- Encrypt
|
||||
@ -202,6 +256,16 @@ public class SM2 extends AbstractAsymmetricCrypto<SM2> {
|
||||
}
|
||||
// --------------------------------------------------------------------------------- Sign and Verify
|
||||
|
||||
/**
|
||||
* 用私钥对信息生成数字签名
|
||||
*
|
||||
* @param dataHex 被签名的数据数据
|
||||
* @return 签名
|
||||
*/
|
||||
public String signHex(String dataHex) {
|
||||
return signHex(dataHex, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用私钥对信息生成数字签名
|
||||
*
|
||||
@ -215,7 +279,18 @@ public class SM2 extends AbstractAsymmetricCrypto<SM2> {
|
||||
/**
|
||||
* 用私钥对信息生成数字签名
|
||||
*
|
||||
* @param data 加密数据
|
||||
* @param dataHex 被签名的数据数据
|
||||
* @param idHex 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes()
|
||||
* @return 签名
|
||||
*/
|
||||
public String signHex(String dataHex, String idHex) {
|
||||
return HexUtil.encodeHexStr(sign(HexUtil.decodeHex(dataHex), HexUtil.decodeHex(idHex)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 用私钥对信息生成数字签名
|
||||
*
|
||||
* @param data 被签名的数据数据
|
||||
* @param id 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes()
|
||||
* @return 签名
|
||||
*/
|
||||
@ -230,7 +305,7 @@ public class SM2 extends AbstractAsymmetricCrypto<SM2> {
|
||||
signer.init(true, param);
|
||||
signer.update(data, 0, data.length);
|
||||
return signer.generateSignature();
|
||||
} catch (Exception e) {
|
||||
} catch (org.bouncycastle.crypto.CryptoException e) {
|
||||
throw new CryptoException(e);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
@ -240,7 +315,19 @@ public class SM2 extends AbstractAsymmetricCrypto<SM2> {
|
||||
/**
|
||||
* 用公钥检验数字签名的合法性
|
||||
*
|
||||
* @param data 数据
|
||||
* @param dataHex 数据签名后的数据
|
||||
* @param signHex 签名
|
||||
* @return 是否验证通过
|
||||
* @since 5.2.0
|
||||
*/
|
||||
public boolean verifyHex(String dataHex, String signHex) {
|
||||
return verifyHex(dataHex, signHex, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用公钥检验数字签名的合法性
|
||||
*
|
||||
* @param data 签名后的数据
|
||||
* @param sign 签名
|
||||
* @return 是否验证通过
|
||||
*/
|
||||
@ -251,7 +338,20 @@ public class SM2 extends AbstractAsymmetricCrypto<SM2> {
|
||||
/**
|
||||
* 用公钥检验数字签名的合法性
|
||||
*
|
||||
* @param data 数据
|
||||
* @param dataHex 数据签名后的数据的Hex值
|
||||
* @param signHex 签名的Hex值
|
||||
* @param idHex ID的Hex值
|
||||
* @return 是否验证通过
|
||||
* @since 5.2.0
|
||||
*/
|
||||
public boolean verifyHex(String dataHex, String signHex, String idHex) {
|
||||
return verify(HexUtil.decodeHex(dataHex), HexUtil.decodeHex(signHex), HexUtil.decodeHex(idHex));
|
||||
}
|
||||
|
||||
/**
|
||||
* 用公钥检验数字签名的合法性
|
||||
*
|
||||
* @param data 数据签名后的数据
|
||||
* @param sign 签名
|
||||
* @param id 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes()
|
||||
* @return 是否验证通过
|
||||
@ -267,8 +367,6 @@ public class SM2 extends AbstractAsymmetricCrypto<SM2> {
|
||||
signer.init(false, param);
|
||||
signer.update(data, 0, data.length);
|
||||
return signer.verifySignature(sign);
|
||||
} catch (Exception e) {
|
||||
throw new CryptoException(e);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
@ -279,23 +377,44 @@ public class SM2 extends AbstractAsymmetricCrypto<SM2> {
|
||||
super.setPrivateKey(privateKey);
|
||||
|
||||
// 重新初始化密钥参数,防止重新设置密钥时导致密钥无法更新
|
||||
this.privateKeyParams = null;
|
||||
initCipherParams();
|
||||
this.privateKeyParams = BCUtil.toParams(privateKey);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置私钥参数
|
||||
*
|
||||
* @param privateKeyParams 私钥参数
|
||||
* @return this
|
||||
* @since 5.2.0
|
||||
*/
|
||||
public SM2 setPrivateKeyParams(ECPrivateKeyParameters privateKeyParams) {
|
||||
this.privateKeyParams = privateKeyParams;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SM2 setPublicKey(PublicKey publicKey) {
|
||||
super.setPublicKey(publicKey);
|
||||
|
||||
// 重新初始化密钥参数,防止重新设置密钥时导致密钥无法更新
|
||||
this.publicKeyParams = null;
|
||||
initCipherParams();
|
||||
this.publicKeyParams = BCUtil.toParams(publicKey);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置公钥参数
|
||||
*
|
||||
* @param publicKeyParams 公钥参数
|
||||
* @return this
|
||||
*/
|
||||
public SM2 setPublicKeyParams(ECPublicKeyParameters publicKeyParams) {
|
||||
this.publicKeyParams = publicKeyParams;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置加密类型
|
||||
*
|
||||
@ -312,26 +431,6 @@ public class SM2 extends AbstractAsymmetricCrypto<SM2> {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------------------- Private method start
|
||||
|
||||
/**
|
||||
* 初始化加密解密参数(包括私钥和公钥参数)
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
private SM2 initCipherParams() {
|
||||
try {
|
||||
if (null != this.publicKey) {
|
||||
this.publicKeyParams = (ECPublicKeyParameters) ECUtil.generatePublicKeyParameter(this.publicKey);
|
||||
}
|
||||
if (null != privateKey) {
|
||||
this.privateKeyParams = (ECPrivateKeyParameters) ECUtil.generatePrivateKeyParameter(this.privateKey);
|
||||
}
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new CryptoException(e);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取密钥类型对应的加密参数对象{@link CipherParameters}
|
||||
*
|
||||
@ -341,8 +440,10 @@ public class SM2 extends AbstractAsymmetricCrypto<SM2> {
|
||||
private CipherParameters getCipherParameters(KeyType keyType) {
|
||||
switch (keyType) {
|
||||
case PublicKey:
|
||||
Assert.notNull(this.publicKeyParams, "PublicKey must be not null !");
|
||||
return this.publicKeyParams;
|
||||
case PrivateKey:
|
||||
Assert.notNull(this.privateKeyParams, "PrivateKey must be not null !");
|
||||
return this.privateKeyParams;
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ public class Sign extends BaseAsymmetric<Sign> {
|
||||
* @param algorithm {@link SignAlgorithm}
|
||||
*/
|
||||
public Sign(SignAlgorithm algorithm) {
|
||||
this(algorithm, (byte[]) null, (byte[]) null);
|
||||
this(algorithm, null, (byte[]) null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -43,7 +43,7 @@ public class Sign extends BaseAsymmetric<Sign> {
|
||||
* @param algorithm 算法
|
||||
*/
|
||||
public Sign(String algorithm) {
|
||||
this(algorithm, (byte[]) null, (byte[]) null);
|
||||
this(algorithm, null, (byte[]) null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,13 +2,17 @@ package cn.hutool.crypto.test;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.crypto.BCUtil;
|
||||
import cn.hutool.crypto.SmUtil;
|
||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.junit.Test;
|
||||
|
||||
public class BCUtilTest {
|
||||
|
||||
@Test
|
||||
public void decodeECPointTest(){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 密钥生成来自:https://i.goto327.top/CryptTools/SM2.aspx?tdsourcetag=s_pctim_aiomsg
|
||||
*/
|
||||
@ -17,7 +21,7 @@ public class BCUtilTest {
|
||||
String x = "706AD9DAA3E5CEAC3DA59F583429E8043BAFC576BE10092C4EA4D8E19846CA62";
|
||||
String y = "F7E938B02EED7280277493B8556E5B01CB436E018A562DFDC53342BF41FDF728";
|
||||
|
||||
final ECPublicKeyParameters keyParameters = BCUtil.toParams(x, y, SmUtil.CURVE, SmUtil.DOMAIN_PARAMS);
|
||||
final ECPublicKeyParameters keyParameters = BCUtil.toSm2Params(x, y);
|
||||
Assert.notNull(keyParameters);
|
||||
}
|
||||
|
||||
@ -25,7 +29,7 @@ public class BCUtilTest {
|
||||
public void createECPrivateKeyParametersTest() {
|
||||
String privateKeyHex = "5F6CA5BB044C40ED2355F0372BF72A5B3AE6943712F9FDB7C1FFBAECC06F3829";
|
||||
|
||||
final ECPrivateKeyParameters keyParameters = BCUtil.toParams(privateKeyHex, SmUtil.DOMAIN_PARAMS);
|
||||
final ECPrivateKeyParameters keyParameters = BCUtil.toSm2Params(privateKeyHex);
|
||||
Assert.notNull(keyParameters);
|
||||
}
|
||||
}
|
||||
|
@ -121,6 +121,17 @@ public class SM2Test {
|
||||
Assert.assertTrue(verify);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sm2SignAndVerifyHexTest() {
|
||||
String content = "我是Hanley.";
|
||||
|
||||
final SM2 sm2 = SmUtil.sm2();
|
||||
|
||||
String sign = sm2.signHex(HexUtil.encodeHexStr(content));
|
||||
boolean verify = sm2.verifyHex(HexUtil.encodeHexStr(content), sign);
|
||||
Assert.assertTrue(verify);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sm2SignAndVerifyUseKeyTest() {
|
||||
String content = "我是Hanley.";
|
||||
@ -149,4 +160,20 @@ public class SM2Test {
|
||||
Assert.assertEquals(HexUtil.encodeHexStr(publicKey.getEncoded()), HexUtil.encodeHexStr(Hexdecode.getEncoded()));
|
||||
Assert.assertEquals(HexUtil.encodeHexStr(publicKey.getEncoded()), HexUtil.encodeHexStr(B64decode.getEncoded()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sm2WithPointTest(){
|
||||
String d = "FAB8BBE670FAE338C9E9382B9FB6485225C11A3ECB84C938F10F20A93B6215F0";
|
||||
String x = "9EF573019D9A03B16B0BE44FC8A5B4E8E098F56034C97B312282DD0B4810AFC3";
|
||||
String y = "CC759673ED0FC9B9DC7E6FA38F0E2B121E02654BF37EA6B63FAF2A0D6013EADF";
|
||||
|
||||
String data = "434477813974bf58f94bcf760833c2b40f77a5fc360485b0b9ed1bd9682edb45";
|
||||
String id = "31323334353637383132333435363738";
|
||||
|
||||
final SM2 sm2 = new SM2(d, x, y);
|
||||
|
||||
final String sign = sm2.signHex(data, id);
|
||||
|
||||
Assert.assertTrue(sm2.verifyHex(data, sign));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user