diff --git a/CHANGELOG.md b/CHANGELOG.md index c0934450c..b990978c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------------------------------------- -## 5.1.6 +## 5.2.0 ### 新特性 * 【core 】 NumberUtil.decimalFormat增加Object对象参数支持 @@ -18,6 +18,8 @@ * 【all 】 log、template、tokenizer使用SPI机制代替硬编码 * 【poi 】 Word07Writer增加addPicture * 【crypto】 RSA算法中,BlockSize长度策略调整(issue#721@Github) +* 【crypto】 删除SM2Engine,使用BC库中的对象替代 +* 【crypto】 增加PemUtil工具类 ### Bug修复 diff --git a/README.md b/README.md index 8398ffdb7..986ef43dc 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ -- 主页:https://hutool.cn/ | https://www.hutool.club/ --
- -- QQ群③:555368316 -- + -- QQ群③:555368316 -- -- QQ群④:718802356 --
@@ -116,21 +116,21 @@ Hutool的存在就是为了减少代码搜索成本,避免网络上参差不+ * PEM一般为文本格式,以 -----BEGIN... 开头,以 -----END... 结尾,中间的内容是 BASE64 编码。 + *
+ * 这种格式可以保存证书和私钥,有时我们也把PEM格式的私钥的后缀改为 .key 以区别证书与私钥。
+ *
+ * @author looly
+ * @since 5.1.6
+ */
+public class PemUtil {
+
+ /**
+ * 读取PEM格式的私钥
+ *
+ * @param pemStream pem流
+ * @return {@link PrivateKey}
+ * @since 4.5.2
+ */
+ public static PrivateKey readPemPrivateKey(InputStream pemStream) {
+ return (PrivateKey) PemUtil.readPemKey(pemStream);
+ }
+
+ /**
+ * 读取PEM格式的公钥
+ *
+ * @param pemStream pem流
+ * @return {@link PublicKey}
+ * @since 4.5.2
+ */
+ public static PublicKey readPemPublicKey(InputStream pemStream) {
+ return (PublicKey) PemUtil.readPemKey(pemStream);
+ }
+
+ /**
+ * 从pem文件中读取公钥或私钥
+ * 根据类型返回 {@link PublicKey} 或者 {@link PrivateKey}
+ *
+ * @param keyStream pem流
+ * @return {@link Key},null表示无法识别的密钥类型
+ * @since 5.1.6
+ */
+ public static Key readPemKey(InputStream keyStream) {
+ final PemObject object = readPemObject(keyStream);
+ final String type = object.getType();
+ if (StrUtil.isNotBlank(type)) {
+ if (type.endsWith("PRIVATE KEY")) {
+ return KeyUtil.generateRSAPrivateKey(object.getContent());
+ } else if (type.endsWith("PUBLIC KEY")) {
+ return KeyUtil.generateRSAPublicKey(object.getContent());
+ } else if (type.endsWith("CERTIFICATE")) {
+ return KeyUtil.readPublicKeyFromCert(IoUtil.toStream(object.getContent()));
+ }
+ }
+
+ //表示无法识别的密钥类型
+ return null;
+ }
+
+ /**
+ * 从pem流中读取公钥或私钥
+ *
+ * @param keyStream pem流
+ * @return 密钥bytes
+ * @since 5.1.6
+ */
+ public static byte[] readPem(InputStream keyStream) {
+ PemObject pemObject = readPemObject(keyStream);
+ if (null != pemObject) {
+ return pemObject.getContent();
+ }
+ return null;
+ }
+
+ /**
+ * 读取pem文件中的信息,包括类型、头信息和密钥内容
+ *
+ * @param keyStream pem流
+ * @return {@link PemObject}
+ * @since 4.5.2
+ */
+ public static PemObject readPemObject(InputStream keyStream) {
+ return readPemObject(IoUtil.getUtf8Reader(keyStream));
+ }
+
+ /**
+ * 读取pem文件中的信息,包括类型、头信息和密钥内容
+ *
+ * @param reader pem Reader
+ * @return {@link PemObject}
+ * @since 5.1.6
+ */
+ public static PemObject readPemObject(Reader reader) {
+ PemReader pemReader = null;
+ try {
+ pemReader = new PemReader(reader);
+ return pemReader.readPemObject();
+ } catch (IOException e) {
+ throw new IORuntimeException(e);
+ } finally {
+ IoUtil.close(pemReader);
+ }
+ }
+
+ /**
+ * 写出pem密钥(私钥、公钥、证书)
+ *
+ * @param type 密钥类型(私钥、公钥、证书)
+ * @param content 密钥内容
+ * @param keyStream pem流
+ * @since 5.1.6
+ */
+ public static void writePemObject(String type, byte[] content, OutputStream keyStream) {
+ writePemObject(new PemObject(type, content), keyStream);
+ }
+
+ /**
+ * 写出pem密钥(私钥、公钥、证书)
+ *
+ * @param pemObject pem对象,包括密钥和密钥类型等信息
+ * @param keyStream pem流
+ * @since 5.1.6
+ */
+ public static void writePemObject(PemObjectGenerator pemObject, OutputStream keyStream) {
+ PemWriter writer = null;
+ try {
+ writer = new PemWriter(IoUtil.getUtf8Writer(keyStream));
+ writer.writeObject(pemObject);
+ } catch (IOException e) {
+ throw new IORuntimeException(e);
+ } finally {
+ IoUtil.close(writer);
+ }
+ }
+}
diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/SM2.java b/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/SM2.java
index 3dc10d01c..da3a1b213 100644
--- a/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/SM2.java
+++ b/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/SM2.java
@@ -2,8 +2,9 @@ package cn.hutool.crypto.asymmetric;
import cn.hutool.crypto.CryptoException;
import cn.hutool.crypto.SecureUtil;
-import cn.hutool.crypto.asymmetric.SM2Engine.SM2Mode;
import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithID;
@@ -19,23 +20,26 @@ import java.security.PublicKey;
* 国密SM2算法实现,基于BC库
* SM2算法只支持公钥加密,私钥解密
* 参考:https://blog.csdn.net/pridas/article/details/86118774
- *
+ *
* @author looly
* @since 4.3.2
*/
public class SM2 extends AbstractAsymmetricCrypto
* 私钥和公钥同时为空时生成一对新的私钥和公钥
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
- *
+ *
* @param privateKeyStr 私钥Hex或Base64表示
- * @param publicKeyStr 公钥Hex或Base64表示
+ * @param publicKeyStr 公钥Hex或Base64表示
*/
public SM2(String privateKeyStr, String publicKeyStr) {
this(SecureUtil.decode(privateKeyStr), SecureUtil.decode(publicKeyStr));
@@ -59,9 +63,9 @@ public class SM2 extends AbstractAsymmetricCrypto
* 私钥和公钥同时为空时生成一对新的私钥和公钥
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
- *
+ *
* @param privateKey 私钥
- * @param publicKey 公钥
+ * @param publicKey 公钥
*/
public SM2(byte[] privateKey, byte[] publicKey) {
this(//
@@ -74,9 +78,9 @@ public class SM2 extends AbstractAsymmetricCrypto
* 私钥和公钥同时为空时生成一对新的私钥和公钥
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
- *
+ *
* @param privateKey 私钥
- * @param publicKey 公钥
+ * @param publicKey 公钥
*/
public SM2(PrivateKey privateKey, PublicKey publicKey) {
super(ALGORITHM_SM2, privateKey, publicKey);
@@ -87,9 +91,9 @@ public class SM2 extends AbstractAsymmetricCrypto
* 私钥和公钥同时为空时生成一对新的私钥和公钥
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密(签名)或者解密(校验)
- *
+ *
* @param privateKey 私钥
- * @param publicKey 公钥
+ * @param publicKey 公钥
* @return this
*/
public SM2 init(PrivateKey privateKey, PublicKey publicKey) {
@@ -103,16 +107,17 @@ public class SM2 extends AbstractAsymmetricCrypto
* C1 生成随机数的计算出的椭圆曲线点
* C2 密文数据
* C3 SM3的摘要值
*
- *
- * @param data 被加密的bytes
+ *
+ * @param data 被加密的bytes
* @param keyType 私钥或公钥 {@link KeyType}
* @return 加密后的bytes
* @throws CryptoException 包括InvalidKeyException和InvalidCipherTextException的包装异常
@@ -123,22 +128,43 @@ public class SM2 extends AbstractAsymmetricCrypto
+ * C1 生成随机数的计算出的椭圆曲线点
+ * C2 密文数据
+ * C3 SM3的摘要值
+ *
+ *
+ * @param data 被加密的bytes
+ * @param pubKeyParameters 公钥参数
+ * @return 加密后的bytes
+ * @throws CryptoException 包括InvalidKeyException和InvalidCipherTextException的包装异常
+ * @since 5.1.6
+ */
+ public byte[] encrypt(byte[] data, CipherParameters pubKeyParameters) throws CryptoException {
lock.lock();
final SM2Engine engine = getEngine();
try {
- engine.init(true, new ParametersWithRandom(getCipherParameters(keyType)));
+ engine.init(true, pubKeyParameters);
return engine.processBlock(data, 0, data.length);
+ } catch (InvalidCipherTextException e) {
+ throw new CryptoException(e);
} finally {
lock.unlock();
}
}
// --------------------------------------------------------------------------------- Decrypt
+
/**
* 解密
- *
- * @param data SM2密文,实际包含三部分:ECC公钥、真正的密文、公钥和原文的SM3-HASH值
+ *
+ * @param data SM2密文,实际包含三部分:ECC公钥、真正的密文、公钥和原文的SM3-HASH值
* @param keyType 私钥或公钥 {@link KeyType}
* @return 加密后的bytes
* @throws CryptoException 包括InvalidKeyException和InvalidCipherTextException的包装异常
@@ -149,21 +175,35 @@ public class SM2 extends AbstractAsymmetricCrypto
- * SM2加密后的数据格式为(两种模式):
- *
- *
- * curve(C1) | data(C2) | digest(C3)
- * curve(C1) | digest(C3) | data(C2)
- *
- *
- * @author looly, bouncycastle
- * @since 4.5.0
- */
-public class SM2Engine {
-
- private final Digest digest;
-
- private boolean forEncryption;
- private ECKeyParameters ecKey;
- private ECDomainParameters ecParams;
- private int curveLength;
- private Random random;
- /** 加密解密模式 */
- private SM2Mode mode;
-
- /**
- * 构造
- */
- public SM2Engine() {
- this(new SM3Digest());
- }
-
- /**
- * 构造
- *
- * @param mode SM2密钥生成模式,可选C1C2C3和C1C3C2
- */
- public SM2Engine(SM2Mode mode) {
- this(new SM3Digest(), mode);
- }
-
- /**
- * 构造
- *
- * @param digest 摘要算法啊
- */
- public SM2Engine(Digest digest) {
- this(digest, null);
- }
-
- /**
- * 构造
- *
- * @param digest 摘要算法啊
- * @param mode SM2密钥生成模式,可选C1C2C3和C1C3C2
- */
- public SM2Engine(Digest digest, SM2Mode mode) {
- this.digest = digest;
- this.mode = ObjectUtil.defaultIfNull(mode, SM2Mode.C1C3C2);
- }
-
- /**
- * 初始化引擎
- *
- * @param forEncryption 是否为加密模式
- * @param param {@link CipherParameters},此处应为{@link ParametersWithRandom}(加密时)或{@link ECKeyParameters}(解密时)
- */
- public void init(boolean forEncryption, CipherParameters param) {
- this.forEncryption = forEncryption;
-
- if (param instanceof ParametersWithRandom) {
- final ParametersWithRandom rParam = (ParametersWithRandom) param;
- this.ecKey = (ECKeyParameters) rParam.getParameters();
- this.random = rParam.getRandom();
- } else {
- this.ecKey = (ECKeyParameters) param;
- }
- this.ecParams = this.ecKey.getParameters();
-
- if (forEncryption) {
- // 检查曲线点
- final ECPoint ecPoint = ((ECPublicKeyParameters) ecKey).getQ().multiply(ecParams.getH());
- if (ecPoint.isInfinity()) {
- throw new IllegalArgumentException("invalid key: [h]Q at infinity");
- }
-
- // 检查随机参数
- if (null == this.random) {
- this.random = CryptoServicesRegistrar.getSecureRandom();
- }
- }
-
- // 曲线位长度
- this.curveLength = (this.ecParams.getCurve().getFieldSize() + 7) / 8;
- }
-
- /**
- * 处理块,包括加密和解密
- *
- * @param in 数据
- * @param inOff 数据开始位置
- * @param inLen 数据长度
- * @return 结果
- */
- public byte[] processBlock(byte[] in, int inOff, int inLen) {
- if (forEncryption) {
- return encrypt(in, inOff, inLen);
- } else {
- return decrypt(in, inOff, inLen);
- }
- }
-
- /**
- * 设置加密类型
- *
- * @param mode {@link SM2Mode}
- * @return this
- */
- public SM2Engine setMode(SM2Mode mode) {
- this.mode = mode;
- return this;
- }
-
- /**
- * SM2算法模式
- * 在SM2算法中,C1C2C3为旧标准模式,C1C3C2为新标准模式
- *
- * @author looly
- *
- */
- public enum SM2Mode {
- C1C2C3, C1C3C2
- }
-
- protected ECMultiplier createBasePointMultiplier() {
- return new FixedPointCombMultiplier();
- }
-
- // --------------------------------------------------------------------------------------------------- Private method start
- /**
- * 加密
- *
- * @param in 数据
- * @param inOff 位置
- * @param inLen 长度
- * @return 密文
- */
- private byte[] encrypt(byte[] in, int inOff, int inLen) {
- // 加密数据
- byte[] c2 = new byte[inLen];
- System.arraycopy(in, inOff, c2, 0, c2.length);
-
- final ECMultiplier multiplier = createBasePointMultiplier();
-
- byte[] c1;
- ECPoint kPB;
- BigInteger k;
- do {
- k = nextK();
- // 产生随机数计算出曲线点C1
- c1 = multiplier.multiply(ecParams.getG(), k).normalize().getEncoded(false);
- kPB = ((ECPublicKeyParameters) ecKey).getQ().multiply(k).normalize();
- kdf(kPB, c2);
- } while (notEncrypted(c2, in, inOff));
-
- // 杂凑值,效验数据
- byte[] c3 = new byte[digest.getDigestSize()];
-
- addFieldElement(kPB.getAffineXCoord());
- this.digest.update(in, inOff, inLen);
- addFieldElement(kPB.getAffineYCoord());
-
- this.digest.doFinal(c3, 0);
-
- // 按照对应模式输出结果
- if (mode == SM2Mode.C1C3C2) {
- return Arrays.concatenate(c1, c3, c2);
- }
- return Arrays.concatenate(c1, c2, c3);
- }
-
- /**
- * 解密,只支持私钥解密
- *
- * @param in 密文
- * @param inOff 位置
- * @param inLen 长度
- * @return 解密后的内容
- */
- private byte[] decrypt(byte[] in, int inOff, int inLen) {
- // 获取曲线点
- final byte[] c1 = new byte[this.curveLength * 2 + 1];
- System.arraycopy(in, inOff, c1, 0, c1.length);
-
- ECPoint c1P = this.ecParams.getCurve().decodePoint(c1);
- if (c1P.multiply(this.ecParams.getH()).isInfinity()) {
- throw new CryptoException("[h]C1 at infinity");
- }
- c1P = c1P.multiply(((ECPrivateKeyParameters) ecKey).getD()).normalize();
-
- final int digestSize = this.digest.getDigestSize();
-
- // 解密C2数据
- final byte[] c2 = new byte[inLen - c1.length - digestSize];
-
- if (SM2Mode.C1C3C2 == this.mode) {
- // C2位于第三部分
- System.arraycopy(in, inOff + c1.length + digestSize, c2, 0, c2.length);
- } else {
- // C2位于第二部分
- System.arraycopy(in, inOff + c1.length, c2, 0, c2.length);
- }
- kdf(c1P, c2);
-
- // 使用摘要验证C2数据
- final byte[] c3 = new byte[digestSize];
-
- addFieldElement(c1P.getAffineXCoord());
- this.digest.update(c2, 0, c2.length);
- addFieldElement(c1P.getAffineYCoord());
- this.digest.doFinal(c3, 0);
-
- int check = 0;
- for (int i = 0; i != c3.length; i++) {
- check |= c3[i] ^ in[inOff + c1.length + ((SM2Mode.C1C3C2 == this.mode) ? 0 : c2.length) + i];
- }
-
- Arrays.fill(c1, (byte) 0);
- Arrays.fill(c3, (byte) 0);
-
- if (check != 0) {
- Arrays.fill(c2, (byte) 0);
- throw new CryptoException("invalid cipher text");
- }
-
- return c2;
- }
-
- private boolean notEncrypted(byte[] encData, byte[] in, int inOff) {
- for (int i = 0; i != encData.length; i++) {
- if (encData[i] != in[inOff + i]) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * 解密数据
- *
- * @param c1 c1点
- * @param encData 密文
- */
- private void kdf(ECPoint c1, byte[] encData) {
- final Digest digest = this.digest;
- int digestSize = digest.getDigestSize();
- byte[] buf = new byte[Math.max(4, digestSize)];
- int off = 0;
-
- Memoable memo = null;
- Memoable copy = null;
-
- if (digest instanceof Memoable) {
- addFieldElement(c1.getAffineXCoord());
- addFieldElement(c1.getAffineYCoord());
- memo = (Memoable) digest;
- copy = memo.copy();
- }
-
- int ct = 0;
-
- while (off < encData.length) {
- if (memo != null) {
- memo.reset(copy);
- } else {
- addFieldElement(c1.getAffineXCoord());
- addFieldElement(c1.getAffineYCoord());
- }
-
- Pack.intToBigEndian(++ct, buf, 0);
- digest.update(buf, 0, 4);
- digest.doFinal(buf, 0);
-
- int xorLen = Math.min(digestSize, encData.length - off);
- xor(encData, buf, off, xorLen);
- off += xorLen;
- }
- }
-
- /**
- * 异或
- *
- * @param data 数据
- * @param kdfOut kdf输出值
- * @param dOff d偏移
- * @param dRemaining d剩余
- */
- private void xor(byte[] data, byte[] kdfOut, int dOff, int dRemaining) {
- for (int i = 0; i != dRemaining; i++) {
- data[dOff + i] ^= kdfOut[i];
- }
- }
-
- /**
- * 下一个K值
- *
- * @return K值
- */
- private BigInteger nextK() {
- final int qBitLength = this.ecParams.getN().bitLength();
-
- BigInteger k;
- do {
- k = new BigInteger(qBitLength, this.random);
- } while (k.equals(ECConstants.ZERO) || k.compareTo(this.ecParams.getN()) >= 0);
-
- return k;
- }
-
- /**
- * 增加字段节点
- *
- * @param v 节点
- */
- private void addFieldElement(ECFieldElement v) {
- final byte[] p = BigIntegers.asUnsignedByteArray(this.curveLength, v.toBigInteger());
- this.digest.update(p, 0, p.length);
- }
- // --------------------------------------------------------------------------------------------------- Private method start
-}
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/BCUtilTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/test/PemUtilTest.java
similarity index 58%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/BCUtilTest.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/test/PemUtilTest.java
index 9b8ab803a..7db403b1b 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/BCUtilTest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/test/PemUtilTest.java
@@ -1,40 +1,39 @@
package cn.hutool.crypto.test;
+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 org.junit.Assert;
+import org.junit.Test;
+
import java.security.PrivateKey;
import java.security.PublicKey;
-import org.junit.Assert;
-import org.junit.Test;
+public class PemUtilTest {
-import cn.hutool.core.io.resource.ResourceUtil;
-import cn.hutool.crypto.BCUtil;
-import cn.hutool.crypto.asymmetric.KeyType;
-import cn.hutool.crypto.asymmetric.RSA;
-
-public class BCUtilTest {
-
@Test
public void readPrivateKeyTest() {
- PrivateKey privateKey = BCUtil.readPrivateKey(ResourceUtil.getStream("test_private_key.pem"));
+ PrivateKey privateKey = PemUtil.readPemPrivateKey(ResourceUtil.getStream("test_private_key.pem"));
Assert.assertNotNull(privateKey);
}
@Test
public void readPublicKeyTest() {
- PublicKey publicKey = BCUtil.readPublicKey(ResourceUtil.getStream("test_public_key.csr"));
+ PublicKey publicKey = PemUtil.readPemPublicKey(ResourceUtil.getStream("test_public_key.csr"));
Assert.assertNotNull(publicKey);
}
@Test
public void readPemKeyTest() {
- PublicKey publicKey = (PublicKey) BCUtil.readPemKey(ResourceUtil.getStream("test_public_key.csr"));
+ PublicKey publicKey = (PublicKey) PemUtil.readPemKey(ResourceUtil.getStream("test_public_key.csr"));
Assert.assertNotNull(publicKey);
}
@Test
public void validateKey() {
- PrivateKey privateKey = BCUtil.readPrivateKey(ResourceUtil.getStream("test_private_key.pem"));
- PublicKey publicKey = BCUtil.readPublicKey(ResourceUtil.getStream("test_public_key.csr"));
+ PrivateKey privateKey = PemUtil.readPemPrivateKey(ResourceUtil.getStream("test_private_key.pem"));
+ PublicKey publicKey = PemUtil.readPemPublicKey(ResourceUtil.getStream("test_public_key.csr"));
RSA rsa = new RSA(privateKey, publicKey);
String str = "你好,Hutool";//测试字符串
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/SM2Test.java b/hutool-crypto/src/test/java/cn/hutool/crypto/test/SM2Test.java
index eabd71f5a..a119ddb23 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/SM2Test.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/test/SM2Test.java
@@ -1,13 +1,5 @@
package cn.hutool.crypto.test;
-import java.security.KeyPair;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-
-import cn.hutool.core.lang.Console;
-import org.junit.Assert;
-import org.junit.Test;
-
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.HexUtil;
@@ -17,7 +9,13 @@ import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
-import cn.hutool.crypto.asymmetric.SM2Engine.SM2Mode;
+import org.bouncycastle.crypto.engines.SM2Engine;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
/**
* SM2算法单元测试
@@ -48,10 +46,9 @@ public class SM2Test {
KeyPair pair = SecureUtil.generateKeyPair("SM2");
byte[] privateKey = pair.getPrivate().getEncoded();
byte[] publicKey = pair.getPublic().getEncoded();
- Console.log(HexUtil.encodeHexStr(publicKey));
SM2 sm2 = SmUtil.sm2(privateKey, publicKey);
- sm2.setMode(SM2Mode.C1C3C2);
+ sm2.setMode(SM2Engine.Mode.C1C2C3);
// 公钥加密,私钥解密
byte[] encrypt = sm2.encrypt(StrUtil.bytes("我是一段测试aaaa", CharsetUtil.CHARSET_UTF_8), KeyType.PublicKey);
diff --git a/hutool-db/pom.xml b/hutool-db/pom.xml
index 9c6b609fa..0a121e96c 100644
--- a/hutool-db/pom.xml
+++ b/hutool-db/pom.xml
@@ -9,7 +9,7 @@