Browse Source

add method

Looly 4 years ago
parent
commit
32c4952d31

+ 2 - 1
CHANGELOG.md

@@ -3,7 +3,7 @@
 
 -------------------------------------------------------------------------------------------------------------
 
-# 5.5.9 (2021-02-25)
+# 5.5.9 (2021-02-26)
 
 ### 新特性
 * 【crypto 】     PemUtil.readPemKey支持EC(pr#1366@Github)
@@ -13,6 +13,7 @@
 * 【cache  】     AbstractCache增加keySet方法(issue#I37Z4C@Gitee)
 * 【core   】     NumberWordFormatter增加formatSimple方法(pr#1436@Github)
 * 【crypto 】     增加读取openSSL生成的sm2私钥
+* 【crypto 】     增加众多方法,SM2兼容各类密钥格式(issue#I37Z75@Gitee)
 
 ### Bug修复
 * 【json   】     JSONUtil.isJson方法改变trim策略,解决特殊空白符导致判断失败问题

+ 11 - 0
hutool-core/src/test/java/cn/hutool/core/collection/CollUtilTest.java

@@ -11,6 +11,7 @@ import org.junit.Assert;
 import org.junit.Test;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
@@ -694,4 +695,14 @@ public class CollUtilTest {
 
 		Assert.assertEquals(0, CollUtil.page(3, 5, objects).size());
 	}
+
+	@Test
+	public void subtractToListTest(){
+		List<Long> list1 = Arrays.asList(1L, 2L, 3L);
+		List<Long> list2 = Arrays.asList(2L, 3L);
+
+		List<Long> result = CollUtil.subtractToList(list1, list2);
+		Assert.assertEquals(1, result.size());
+		Assert.assertEquals(1L, result.get(0), 1);
+	}
 }

+ 114 - 5
hutool-crypto/src/main/java/cn/hutool/crypto/ECKeyUtil.java

@@ -11,7 +11,11 @@ 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.jcajce.spec.OpenSSHPrivateKeySpec;
+import org.bouncycastle.jcajce.spec.OpenSSHPublicKeySpec;
 import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.FixedPointCombMultiplier;
 import org.bouncycastle.util.BigIntegers;
 
 import java.io.IOException;
@@ -20,6 +24,7 @@ import java.security.InvalidKeyException;
 import java.security.Key;
 import java.security.PrivateKey;
 import java.security.PublicKey;
+import java.security.spec.KeySpec;
 
 /**
  * EC密钥参数相关工具类封装
@@ -45,7 +50,21 @@ public class ECKeyUtil {
 		return null;
 	}
 
+	/**
+	 * 根据私钥参数获取公钥参数
+	 *
+	 * @param privateKeyParameters 私钥参数
+	 * @return 公钥参数
+	 * @since 5.5.9
+	 */
+	public static ECPublicKeyParameters getPublicParams(ECPrivateKeyParameters privateKeyParameters) {
+		final ECDomainParameters domainParameters = privateKeyParameters.getParameters();
+		final ECPoint q = new FixedPointCombMultiplier().multiply(domainParameters.getG(), privateKeyParameters.getD());
+		return new ECPublicKeyParameters(q, domainParameters);
+	}
+
 	//--------------------------------------------------------------------------- Public Key
+
 	/**
 	 * 转换为 ECPublicKeyParameters
 	 *
@@ -91,8 +110,8 @@ public class ECKeyUtil {
 	/**
 	 * 转换为ECPublicKeyParameters
 	 *
-	 * @param x             公钥X
-	 * @param y             公钥Y
+	 * @param x                公钥X
+	 * @param y                公钥Y
 	 * @param domainParameters ECDomainParameters
 	 * @return ECPublicKeyParameters,x或y为{@code null}则返回{@code null}
 	 */
@@ -109,7 +128,7 @@ public class ECKeyUtil {
 	 * @return ECPublicKeyParameters
 	 */
 	public static ECPublicKeyParameters toPublicParams(byte[] xBytes, byte[] yBytes, ECDomainParameters domainParameters) {
-		if(null == xBytes || null == yBytes){
+		if (null == xBytes || null == yBytes) {
 			return null;
 		}
 		return toPublicParams(BigIntegers.fromUnsignedByteArray(xBytes), BigIntegers.fromUnsignedByteArray(yBytes), domainParameters);
@@ -187,6 +206,7 @@ public class ECKeyUtil {
 	}
 
 	//--------------------------------------------------------------------------- Private Key
+
 	/**
 	 * 转换为 ECPrivateKeyParameters
 	 *
@@ -220,7 +240,7 @@ public class ECKeyUtil {
 	/**
 	 * 转换为 ECPrivateKeyParameters
 	 *
-	 * @param d             私钥d值16进制字符串
+	 * @param d                私钥d值16进制字符串
 	 * @param domainParameters ECDomainParameters
 	 * @return ECPrivateKeyParameters
 	 */
@@ -272,10 +292,11 @@ public class ECKeyUtil {
 
 	/**
 	 * 将SM2算法的{@link ECPrivateKey} 转换为 {@link PrivateKey}
+	 *
 	 * @param privateKey {@link ECPrivateKey}
 	 * @return {@link PrivateKey}
 	 */
-	public static PrivateKey toSm2PrivateKey(ECPrivateKey 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);
@@ -284,4 +305,92 @@ public class ECKeyUtil {
 			throw new IORuntimeException(e);
 		}
 	}
+
+	/**
+	 * 创建{@link OpenSSHPrivateKeySpec}
+	 *
+	 * @param key 私钥,需为PKCS#1格式
+	 * @return {@link OpenSSHPrivateKeySpec}
+	 * @since 5.5.9
+	 */
+	public static KeySpec createOpenSSHPrivateKeySpec(byte[] key) {
+		return new OpenSSHPrivateKeySpec(key);
+	}
+
+	/**
+	 * 创建{@link OpenSSHPublicKeySpec}
+	 *
+	 * @param key 公钥,需为PKCS#1格式
+	 * @return {@link OpenSSHPublicKeySpec}
+	 * @since 5.5.9
+	 */
+	public static KeySpec createOpenSSHPublicKeySpec(byte[] key) {
+		return new OpenSSHPublicKeySpec(key);
+	}
+
+	/**
+	 * 尝试解析转换各种类型私钥为{@link ECPrivateKeyParameters},支持包括:
+	 *
+	 * <ul>
+	 *     <li>D值</li>
+	 *     <li>PKCS#8</li>
+	 *     <li>PKCS#1</li>
+	 * </ul>
+	 *
+	 * @param privateKeyBytes 私钥
+	 * @return {@link ECPrivateKeyParameters}
+	 * @since 5.5.9
+	 */
+	public static ECPrivateKeyParameters decodePrivateKeyParams(byte[] privateKeyBytes) {
+		try {
+			// 尝试D值
+			return toSm2PrivateParams(privateKeyBytes);
+		} catch (Exception ignore) {
+			// ignore
+		}
+
+		PrivateKey privateKey;
+		//尝试PKCS#8
+		try {
+			privateKey = KeyUtil.generatePrivateKey("sm2", privateKeyBytes);
+		} catch (Exception ignore) {
+			// 尝试PKCS#1
+			privateKey = KeyUtil.generatePrivateKey("sm2", createOpenSSHPrivateKeySpec(privateKeyBytes));
+		}
+
+		return toPrivateParams(privateKey);
+	}
+
+	/**
+	 * 尝试解析转换各种类型公钥为{@link ECPublicKeyParameters},支持包括:
+	 *
+	 * <ul>
+	 *     <li>Q值</li>
+	 *     <li>X.509</li>
+	 *     <li>PKCS#1</li>
+	 * </ul>
+	 *
+	 * @param publicKeyBytes 公钥
+	 * @return {@link ECPublicKeyParameters}
+	 * @since 5.5.9
+	 */
+	public static ECPublicKeyParameters decodePublicKeyParams(byte[] publicKeyBytes) {
+		try {
+			// 尝试Q值
+			return toSm2PublicParams(publicKeyBytes);
+		} catch (Exception ignore) {
+			// ignore
+		}
+
+		PublicKey publicKey;
+		//尝试X.509
+		try {
+			publicKey = KeyUtil.generatePublicKey("sm2", publicKeyBytes);
+		} catch (Exception ignore) {
+			// 尝试PKCS#1
+			publicKey = KeyUtil.generatePublicKey("sm2", createOpenSSHPublicKeySpec(publicKeyBytes));
+		}
+
+		return toPublicParams(publicKey);
+	}
 }

+ 3 - 3
hutool-crypto/src/main/java/cn/hutool/crypto/KeyUtil.java

@@ -256,8 +256,8 @@ public class KeyUtil {
 	 * 采用PKCS#8规范,此规范定义了私钥信息语法和加密私钥语法<br>
 	 * 算法见:https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyFactory
 	 *
-	 * @param algorithm 算法
-	 * @param key       密钥,必须为DER编码存储
+	 * @param algorithm 算法,如RSA、EC、SM2等
+	 * @param key       密钥,PKCS#8格式
 	 * @return 私钥 {@link PrivateKey}
 	 */
 	public static PrivateKey generatePrivateKey(String algorithm, byte[] key) {
@@ -271,7 +271,7 @@ public class KeyUtil {
 	 * 生成私钥,仅用于非对称加密<br>
 	 * 算法见:https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyFactory
 	 *
-	 * @param algorithm 算法
+	 * @param algorithm 算法,如RSA、EC、SM2等
 	 * @param keySpec   {@link KeySpec}
 	 * @return 私钥 {@link PrivateKey}
 	 * @since 3.1.1

+ 6 - 4
hutool-crypto/src/main/java/cn/hutool/crypto/PemUtil.java

@@ -3,7 +3,6 @@ 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;
@@ -134,14 +133,17 @@ public class PemUtil {
 	}
 
 	/**
-	 * 读取OpenSSL生成的ANS1格式的Pem私钥文件
+	 * 读取OpenSSL生成的ANS1格式的Pem私钥文件,必须为PKCS#1格式
 	 *
 	 * @param keyStream 私钥pem流
 	 * @return {@link PrivateKey}
 	 */
 	public static PrivateKey readSm2PemPrivateKey(InputStream keyStream) {
-		final ECPrivateKey ecPrivateKey = ECPrivateKey.getInstance(readPem(keyStream));
-		return ECKeyUtil.toSm2PrivateKey(ecPrivateKey);
+		try{
+			return KeyUtil.generatePrivateKey("sm2", ECKeyUtil.createOpenSSHPrivateKeySpec(readPem(keyStream)));
+		} finally {
+			IoUtil.close(keyStream);
+		}
 	}
 
 	/**

+ 42 - 5
hutool-crypto/src/main/java/cn/hutool/crypto/SmUtil.java

@@ -14,6 +14,8 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.gm.GMNamedCurves;
 import org.bouncycastle.crypto.digests.SM3Digest;
 import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
 import org.bouncycastle.crypto.signers.StandardDSAEncoding;
 import org.bouncycastle.util.Arrays;
 import org.bouncycastle.util.encoders.Hex;
@@ -22,11 +24,20 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.PublicKey;
 
 /**
  * SM国密算法工具类<br>
  * 此工具类依赖org.bouncycastle:bcprov-jdk15to18
  *
+ * <p>封装包括:</p>
+ * <ul>
+ *     <li>SM2 椭圆曲线非对称加密和签名</li>
+ *     <li>SM3 杂凑算法</li>
+ *     <li>SM4 对称加密</li>
+ * </ul>
+ *
  * @author looly
  * @since 4.3.2
  */
@@ -74,15 +85,43 @@ public class SmUtil {
 	 * 私钥和公钥同时为空时生成一对新的私钥和公钥<br>
 	 * 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
 	 *
+	 * @param privateKey 私钥,必须使用PKCS#8规范
+	 * @param publicKey  公钥,必须使用X509规范
+	 * @return {@link SM2}
+	 */
+	public static SM2 sm2(byte[] privateKey, byte[] publicKey) {
+		return new SM2(privateKey, publicKey);
+	}
+
+	/**
+	 * 创建SM2算法对象<br>
+	 * 私钥和公钥同时为空时生成一对新的私钥和公钥<br>
+	 * 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
+	 *
 	 * @param privateKey 私钥
 	 * @param publicKey  公钥
 	 * @return {@link SM2}
+	 * @since 5.5.9
 	 */
-	public static SM2 sm2(byte[] privateKey, byte[] publicKey) {
+	public static SM2 sm2(PrivateKey privateKey, PublicKey publicKey) {
 		return new SM2(privateKey, publicKey);
 	}
 
 	/**
+	 * 创建SM2算法对象<br>
+	 * 私钥和公钥同时为空时生成一对新的私钥和公钥<br>
+	 * 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
+	 *
+	 * @param privateKeyParams 私钥参数
+	 * @param publicKeyParams  公钥参数
+	 * @return {@link SM2}
+	 * @since 5.5.9
+	 */
+	public static SM2 sm2(ECPrivateKeyParameters privateKeyParams, ECPublicKeyParameters publicKeyParams) {
+		return new SM2(privateKeyParams, publicKeyParams);
+	}
+
+	/**
 	 * SM3加密<br>
 	 * 例:<br>
 	 * SM3加密:sm3().digest(data)<br>
@@ -192,8 +231,7 @@ public class SmUtil {
 	}
 
 	/**
-	 * BC的SM3withSM2签名得到的结果的rs是asn1格式的,这个方法转化成直接拼接r||s<br>
-	 * 来自:https://blog.csdn.net/pridas/article/details/86118774
+	 * BC的SM3withSM2签名得到的结果的rs是asn1格式的,这个方法转化成直接拼接r||s
 	 *
 	 * @param rsDer rs in asn1 format
 	 * @return sign result in plain byte array
@@ -214,8 +252,7 @@ public class SmUtil {
 	}
 
 	/**
-	 * BC的SM3withSM2验签需要的rs是asn1格式的,这个方法将直接拼接r||s的字节数组转化成asn1格式<br>
-	 * 来自:https://blog.csdn.net/pridas/article/details/86118774
+	 * BC的SM3withSM2验签需要的rs是asn1格式的,这个方法将直接拼接r||s的字节数组转化成asn1格式
 	 *
 	 * @param sign in plain byte array
 	 * @return rs result in asn1 format

+ 6 - 6
hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/SM2.java

@@ -4,7 +4,7 @@ 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.KeyUtil;
+import cn.hutool.crypto.ECKeyUtil;
 import cn.hutool.crypto.SecureUtil;
 import org.bouncycastle.crypto.CipherParameters;
 import org.bouncycastle.crypto.Digest;
@@ -74,13 +74,13 @@ public class SM2 extends AbstractAsymmetricCrypto<SM2> {
 	 * 私钥和公钥同时为空时生成一对新的私钥和公钥<br>
 	 * 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
 	 *
-	 * @param privateKey 私钥,必须使用PKCS#8规范
-	 * @param publicKey  公钥,必须使用X509规范
+	 * @param privateKey 私钥,可以使用PKCS#8、D值或PKCS#1规范
+	 * @param publicKey  公钥,可以使用X509、Q值或PKCS#1规范
 	 */
 	public SM2(byte[] privateKey, byte[] publicKey) {
-		this(//
-				KeyUtil.generatePrivateKey(ALGORITHM_SM2, privateKey), //
-				KeyUtil.generatePublicKey(ALGORITHM_SM2, publicKey)//
+		this(
+				ECKeyUtil.decodePrivateKeyParams(privateKey),
+				ECKeyUtil.decodePublicKeyParams(publicKey)
 		);
 	}
 

+ 1 - 1
hutool-crypto/src/main/java/cn/hutool/crypto/digest/SM3.java

@@ -1,7 +1,7 @@
 package cn.hutool.crypto.digest;
 
 /**
- * SM3算法
+ * SM3杂凑算法
  *
  * @author looly
  * @since 4.6.8

+ 19 - 0
hutool-crypto/src/test/java/cn/hutool/crypto/test/PemUtilTest.java

@@ -1,11 +1,14 @@
 package cn.hutool.crypto.test;
 
+import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.io.resource.ResourceUtil;
+import cn.hutool.core.util.StrUtil;
 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;
@@ -58,4 +61,20 @@ public class PemUtilTest {
 		// 64位签名
 		Assert.assertEquals(64, sign.length);
 	}
+
+	@Test
+	@Ignore
+	public void readECPrivateKeyTest2() {
+		// https://gitee.com/loolly/hutool/issues/I37Z75
+		byte[] d = PemUtil.readPem(FileUtil.getInputStream("d:/test/keys/priv.key"));
+		byte[] publicKey = PemUtil.readPem(FileUtil.getInputStream("d:/test/keys/pub.key"));
+
+		SM2 sm2 = new SM2(d, publicKey);
+		sm2.usePlainEncoding();
+
+		String content = "我是Hanley.";
+		byte[] sign = sm2.sign(StrUtil.utf8Bytes(content));
+		boolean verify = sm2.verify(StrUtil.utf8Bytes(content), sign);
+		Assert.assertTrue(verify);
+	}
 }

+ 38 - 8
hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/SM2Test.java

@@ -12,7 +12,7 @@ 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.bouncycastle.jcajce.spec.OpenSSHPrivateKeySpec;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -136,7 +136,7 @@ public class SM2Test {
 		//签名值
 		String signHex = "2881346e038d2ed706ccdd025f2b1dafa7377d5cf090134b98756fafe084dddbcdba0ab00b5348ed48025195af3f1dda29e819bb66aa9d4d088050ff148482a1";
 
-		final SM2 sm2 = new SM2(null, ECKeyUtil.toSm2PublicParams(publicKeyHex));
+		final SM2 sm2 = new SM2(null, publicKeyHex);
 		sm2.usePlainEncoding();
 
 		boolean verify = sm2.verify(dataBytes, HexUtil.decodeHex(signHex));
@@ -251,10 +251,7 @@ public class SM2Test {
 
 		String data = "123456";
 
-		final ECPublicKeyParameters ecPublicKeyParameters = ECKeyUtil.toSm2PublicParams(q);
-		final ECPrivateKeyParameters ecPrivateKeyParameters = ECKeyUtil.toSm2PrivateParams(d);
-
-		final SM2 sm2 = new SM2(ecPrivateKeyParameters, ecPublicKeyParameters);
+		final SM2 sm2 = new SM2(d, q);
 		sm2.setMode(SM2Engine.Mode.C1C2C3);
 		final String encryptHex = sm2.encryptHex(data, KeyType.PublicKey);
 		final String decryptStr = sm2.decryptStr(encryptHex, KeyType.PrivateKey);
@@ -277,8 +274,41 @@ public class SM2Test {
 	}
 
 	@Test
-	public void test(){
-		String priKey = "MHcCAQEEIE29XqAFV/rkJbnJzCoQRJLTeAHG2TR0h9ZCWag0+ZMEoAoGCCqBHM9VAYItoUQDQgAESkOzNigIsH5ehFvr9yQNQ66genyOrm+Q4umCA4aWXPeRzmcTAWSlTineiReTFN2lqor2xaulT8u3a4w3AM/F6A==";
+	public void getPublicKeyByPrivateKeyTest(){
+		// issue#I38SDP,openSSL生成的PKCS#1格式私钥
+		String priKey = "MHcCAQEEIE29XqAFV/rkJbnJzCoQRJLTeAHG2TR0h9ZCWag0+ZMEoAoGCCqBHM9VAYItoUQDQgAESkOzNigIsH5ehFvr9y" +
+				"QNQ66genyOrm+Q4umCA4aWXPeRzmcTAWSlTineiReTFN2lqor2xaulT8u3a4w3AM/F6A==";
+
+		PrivateKey privateKey = KeyUtil.generatePrivateKey("sm2", new OpenSSHPrivateKeySpec(SecureUtil.decode(priKey)));
+		final ECPrivateKeyParameters privateKeyParameters = ECKeyUtil.toPrivateParams(privateKey);
+
+		final SM2 sm2 = new SM2(privateKeyParameters, ECKeyUtil.getPublicParams(privateKeyParameters));
+
+		String src = "Sm2Test";
+		byte[] data = sm2.encrypt(src, KeyType.PublicKey);
+		byte[] sign =  sm2.sign(src.getBytes(StandardCharsets.UTF_8));
+
+		Assert.assertTrue(sm2.verify( src.getBytes(StandardCharsets.UTF_8), sign));
+
+		byte[] dec =  sm2.decrypt(data, KeyType.PrivateKey);
+		Assert.assertArrayEquals(dec, src.getBytes(StandardCharsets.UTF_8));
+	}
+
+	@Test
+	public void readPublicKeyTest(){
+		String priKey = "MHcCAQEEIE29XqAFV/rkJbnJzCoQRJLTeAHG2TR0h9ZCWag0+ZMEoAoGCCqBHM9VAYItoUQDQgAESkOzNigIsH5ehFvr9y" +
+				"QNQ66genyOrm+Q4umCA4aWXPeRzmcTAWSlTineiReTFN2lqor2xaulT8u3a4w3AM/F6A==";
 		String pubKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAESkOzNigIsH5ehFvr9yQNQ66genyOrm+Q4umCA4aWXPeRzmcTAWSlTineiReTFN2lqor2xaulT8u3a4w3AM/F6A==";
+
+		SM2 sm2 = SmUtil.sm2(priKey, pubKey);
+
+		String src = "Sm2Test中文";
+		byte[] data = sm2.encrypt(src, KeyType.PublicKey);
+		byte[] sign =  sm2.sign(src.getBytes(StandardCharsets.UTF_8));
+
+		Assert.assertTrue(sm2.verify( src.getBytes(StandardCharsets.UTF_8), sign));
+
+		byte[] dec =  sm2.decrypt(data, KeyType.PrivateKey);
+		Assert.assertArrayEquals(dec, src.getBytes(StandardCharsets.UTF_8));
 	}
 }