java bcprov 国密 依赖 jar包 版本 升级 降级 教程


更新记录

2023-05-22
1、调整1.64-1.72区间代码,SM2和SM2Utils类,之前这个区间的代码贴成1.50-1.63区间的了,很抱歉。


2023-06-27
1、“版本1.64-1.72区间”调整为”版本1.64-1.75区间”,博主实测以下代码兼容1.73-1.75版本。

2、增加1.73-1.75版本,且从1.74开始、不再支持jdk1.4版本,至少要jdk1.5及以上。

group-Idartifact-Idversion完整jar包名
org.bouncycastlebcprov-jdk14
bcprov-jdk15to18
bcprov-jdk18on
1.73bcprov-jdk14-1.73.jar
bcprov-jdk15to18-1.73.jar
bcprov-jdk18on-1.73.jar
org.bouncycastlebcprov-jdk15to18
bcprov-jdk18on
1.74bcprov-jdk15to18-1.74.jar
bcprov-jdk18on-1.74.jar
org.bouncycastlebcprov-jdk15to18
bcprov-jdk18on
1.75bcprov-jdk15to18-1.75.jar
bcprov-jdk18on-1.75.jar

*2024-03-19 *
1、增加1.76-1.77版本包,增加1.74-1.75的jdk1.4版本包,去年更新时候官方未提供支持jdk1.4版本,现在已支持,特此更新一版,所有版本看下方章节一中表格,后续新增的版本也不再更新记录中列举。

2、删除章节二-5中SM2类的多余代码,感谢阿凯同学-825在评论区指出。

        // 以下两行代码在try块中通过反射创建,故需注释
		// this.ecc_gx_fieldelement = new Fp(this.ecc_p, this.ecc_gx);
		// this.ecc_gy_fieldelement = new Fp(this.ecc_p, this.ecc_gy);
		// 以下一行代码位置移动到try块中,故需注释
		// this.ecc_curve = new ECCurve.Fp(this.ecc_p, this.ecc_a, this.ecc_b);

前言

关于java的国密算法原理以及sm2、sm3、sm4的演示demo,很多博主都写过。但是如果说自身项目中用到的bcprov这个依赖jar包的版本,和别人博客里演示的不一样,或者说引用了多个版本bcprov的jar包,这种情况怎么办呢?

一般有两个方案,第一个是直接全部白嫖别人的版本,这种方案不是本文所讲内容。另一种方案就是弄明白每个版本依赖包的区别,这样我们的项目就可以只保留一个版本的依赖包了,而且想要留哪一个版本也不在话下。

重要说明:
在看代码前我做一些说明,bcprov这个包在高版本中增加了一些国密相关的签名或者加密类,但是为了兼容所有的版本,所以我并没有使用高版本中才有的类,而是根据比较低的基线版本上开发实现,基线版本代码链接:基于Java的(SM2_SM3_SM4)国密算法, 加密解密工具类及测试demo
所以我在本博客中不会把所有的类代码都放上,只放关键的代码,如果有人因此喷我是cv党,那请自觉关闭本博客。


一、org.bouncycastle下面的bcprov版本有哪些?

从国内的某代理中央仓库里可以查到目前bcprov的版本参考下表。
说明1:包名中jdk14的版本适用于jdk1.4,jdk15on的版本适用于jdk1.5以上,jdk15to18的版本适用于jdk1.5到jdk1.8,jdk18on的版本适用于jdk1.8以上,各位根据自己的jdk版本自行选择对应的版本。如果这说明不明白的可以在评论区提问。
说明2:早期的bcprov版本号不一定是相连的,如果各位大佬使用的版本表格中,可以评论区提问或者私信。
说明3:如果只用国密算法的sm2、sm3、sm4,是不需要用到bcprov的ext包或者util包,只用核心包就可以了。

group-Idartifact-Idversion完整jar包名
org.bouncycastlebcprov-jdk151.32bcprov-jdk15-1.32.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15
bcprov-jdk16
1.38bcprov-jdk14-1.38.jar
bcprov-jdk15-1.38.jar
bcprov-jdk16-1.38.jar
org.bouncycastlebcprov-jdk15
bcprov-jdk16
1.40bcprov-jdk15-1.40.jar
bcprov-jdk16-1.40.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15
bcprov-jdk16
1.43bcprov-jdk14-1.43.jar
bcprov-jdk15-1.43.jar
bcprov-jdk16-1.43.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15
bcprov-jdk16
1.44bcprov-jdk14-1.44.jar
bcprov-jdk15-1.44.jar
bcprov-jdk16-1.44.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15
bcprov-jdk16
1.44bcprov-jdk14-1.44.jar
bcprov-jdk15-1.44.jar
bcprov-jdk16-1.44.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15
bcprov-jdk16
1.45bcprov-jdk14-1.45.jar
bcprov-jdk15-1.45.jar
bcprov-jdk16-1.45.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15
bcprov-jdk15+
bcprov-jdk15on
bcprov-jdk16
1.46bcprov-jdk14-1.46.jar
bcprov-jdk15-1.46.jar
bcprov-jdk15±1.46.jar
bcprov-jdk15on-1.46.jar
bcprov-jdk16-1.46.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
1.47bcprov-jdk14-1.47.jar
bcprov-jdk15on-1.47.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
1.48bcprov-jdk14-1.48.jar
bcprov-jdk15on-1.48.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
1.49bcprov-jdk14-1.49.jar
bcprov-jdk15on-1.49.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
1.50bcprov-jdk14-1.50.jar
bcprov-jdk15on-1.50.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
1.51bcprov-jdk14-1.51.jar
bcprov-jdk15on-1.51.jar
org.bouncycastlebcprov-jdk15on1.52bcprov-jdk15on-1.52.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
1.53bcprov-jdk14-1.53.jar
bcprov-jdk15on-1.53.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
1.54bcprov-jdk14-1.54.jar
bcprov-jdk15on-1.54.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
1.55bcprov-jdk14-1.55.jar
bcprov-jdk15on-1.55.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
1.56bcprov-jdk14-1.56.jar
bcprov-jdk15on-1.56.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
1.57bcprov-jdk14-1.57.jar
bcprov-jdk15on-1.57.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
1.58bcprov-jdk14-1.58.jar
bcprov-jdk15on-1.58.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
1.59bcprov-jdk14-1.59.jar
bcprov-jdk15on-1.59.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
1.60bcprov-jdk14-1.60.jar
bcprov-jdk15on-1.60.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
1.61bcprov-jdk14-1.61.jar
bcprov-jdk15on-1.61.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
1.62bcprov-jdk14-1.62.jar
bcprov-jdk15on-1.62.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
bcprov-jdk15to18
1.63bcprov-jdk14-1.63.jar
bcprov-jdk15on-1.63.jar
bcprov-jdk15to18-1.63.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
bcprov-jdk15to18
1.64bcprov-jdk14-1.64.jar
bcprov-jdk15on-1.64.jar
bcprov-jdk15to18-1.64.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
bcprov-jdk15to18
1.65bcprov-jdk14-1.65.jar
bcprov-jdk15on-1.65.jar
bcprov-jdk15to18-1.65.jar
org.bouncycastlebcprov-jdk15on
bcprov-jdk15to18
1.66bcprov-jdk15-1.66.jar
bcprov-jdk16-1.66.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
bcprov-jdk15to18
1.67bcprov-jdk14-1.67.jar
bcprov-jdk15on-1.67.jar
bcprov-jdk15to18-1.67.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
bcprov-jdk15to18
1.68bcprov-jdk14-1.68.jar
bcprov-jdk15on-1.68.jar
bcprov-jdk15to18-1.68.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
bcprov-jdk15to18
1.69bcprov-jdk14-1.69.jar
bcprov-jdk15on-1.69.jar
bcprov-jdk15to18-1.69.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15on
bcprov-jdk15to18
1.70bcprov-jdk14-1.70.jar
bcprov-jdk15on-1.70.jar
bcprov-jdk15to18-1.70.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15to18
bcprov-jdk18on
1.71bcprov-jdk14-1.71.jar
bcprov-jdk15to18-1.71.jar
bcprov-jdk18on-1.71.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15to18
bcprov-jdk18on
1.72bcprov-jdk14-1.72.jar
bcprov-jdk15to18-1.72.jar
bcprov-jdk18on-1.72.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15to18
bcprov-jdk18on
1.73bcprov-jdk14-1.73.jar
bcprov-jdk15to18-1.73.jar
bcprov-jdk18on-1.73.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15to18
bcprov-jdk18on
1.74bcprov-jdk14-1.74.jar
bcprov-jdk15to18-1.74.jar
bcprov-jdk18on-1.74.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15to18
bcprov-jdk18on
1.75bcprov-jdk14-1.75.jar
bcprov-jdk15to18-1.75.jar
bcprov-jdk18on-1.75.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15to18
bcprov-jdk18on
1.76bcprov-jdk14-1.76.jar
bcprov-jdk15to18-1.76.jar
bcprov-jdk18on-1.76.jar
org.bouncycastlebcprov-jdk14
bcprov-jdk15to18
bcprov-jdk18on
1.77bcprov-jdk14-1.77.jar
bcprov-jdk15to18-1.77.jar
bcprov-jdk18on-1.77.jar

二、升级降级说明

上述表格中的版本,博主除了最老的1.32版本没有搞,其他的版本都测试过,测试使用的jdk1.8,其他版本jdk自行测试,下面会把上述jar包版本分成4个区间,也就是在区间内的任意一个版本都可以使用对应的代码。

1、基线版本

博客开头已经说明,博主原始国密算法实现用的bcprov版本是1.45,所以这里先展示基线的关键代码,方便各位对比。

(1)引入依赖

        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.45</version>
        </dependency>

(2)关键代码

这里只放三个类的代码,Cipher、SM2和SM2Utils,对于不同版本bcprov最多只需要改这三个类,所以其他类就不贴了,各位要所有类的代码,看上述的链接就行。

Cipher
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;

import java.math.BigInteger;


public class Cipher
{
    private int ct;
    private ECPoint p2;
    private SM3Digest sm3keybase;
    private SM3Digest sm3c3;
    private byte[] key;
    private byte keyOff;

    public Cipher()
    {
        this.ct = 1;
        this.key = new byte[32];
        this.keyOff = 0;
    }

    private void Reset()
    {
        this.sm3keybase = new SM3Digest();
        this.sm3c3 = new SM3Digest();

        byte[] p = Util.byteConvert32Bytes(p2.getX().toBigInteger());
        this.sm3keybase.update(p, 0, p.length);
        this.sm3c3.update(p, 0, p.length);

        p = Util.byteConvert32Bytes(p2.getY().toBigInteger());
        this.sm3keybase.update(p, 0, p.length);
        this.ct = 1;
        NextKey();
    }

    private void NextKey()
    {
        SM3Digest sm3keycur = new SM3Digest(this.sm3keybase);
        sm3keycur.update((byte) (ct >> 24 & 0xff));
        sm3keycur.update((byte) (ct >> 16 & 0xff));
        sm3keycur.update((byte) (ct >> 8 & 0xff));
        sm3keycur.update((byte) (ct & 0xff));
        sm3keycur.doFinal(key, 0);
        this.keyOff = 0;
        this.ct++;
    }

    public ECPoint Init_enc(SM2 sm2, ECPoint userKey)
    {
        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();
        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();
        ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();
        BigInteger k = ecpriv.getD();
        ECPoint c1 = ecpub.getQ();
        this.p2 = userKey.multiply(k);
        Reset();
        return c1;
    }

    public void Encrypt(byte[] data)
    {
        this.sm3c3.update(data, 0, data.length);
        for (int i = 0; i < data.length; i++)
        {
            if (keyOff == key.length)
            {
                NextKey();
            }
            data[i] ^= key[keyOff++];
        }
    }

    public void Init_dec(BigInteger userD, ECPoint c1)
    {
        this.p2 = c1.multiply(userD);
        Reset();
    }

    public void Decrypt(byte[] data)
    {
        for (int i = 0; i < data.length; i++)
        {
            if (keyOff == key.length)
            {
                NextKey();
            }
            data[i] ^= key[keyOff++];
        }

        this.sm3c3.update(data, 0, data.length);
    }

    public void Dofinal(byte[] c3)
    {
        byte[] p = Util.byteConvert32Bytes(p2.getY().toBigInteger());
        this.sm3c3.update(p, 0, p.length);
        this.sm3c3.doFinal(c3, 0);
        Reset();
    }
}
SM2
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECFieldElement;
import org.bouncycastle.math.ec.ECFieldElement.Fp;
import org.bouncycastle.math.ec.ECPoint;

import java.math.BigInteger;
import java.security.SecureRandom;

public class SM2
{
	 //测试参数
//	public static final String[] ecc_param = {
//			"8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3",
//			"787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498",
//			"63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A",
//			"8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7",
//			"421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D",
//			"0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2"
//	};

	// 正式参数 为国密算法推荐参数
	public static String[] ecc_param = {
		"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",
		"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",
		"28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",
		"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",
		"32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",
		"BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"
	};

	public static SM2 Instance()
	{
		return new SM2();
	}

	public final BigInteger ecc_p;
	public final BigInteger ecc_a;
	public final BigInteger ecc_b;
	public final BigInteger ecc_n;
	public final BigInteger ecc_gx;
	public final BigInteger ecc_gy;
	public final ECCurve ecc_curve;
	public final ECPoint ecc_point_g;
	public final ECDomainParameters ecc_bc_spec;
	public final ECKeyPairGenerator ecc_key_pair_generator;
	public final ECFieldElement ecc_gx_fieldelement;
	public final ECFieldElement ecc_gy_fieldelement;

	public SM2()
	{
		this.ecc_p = new BigInteger(ecc_param[0], 16);
		this.ecc_a = new BigInteger(ecc_param[1], 16);
		this.ecc_b = new BigInteger(ecc_param[2], 16);
		this.ecc_n = new BigInteger(ecc_param[3], 16);
		this.ecc_gx = new BigInteger(ecc_param[4], 16);
		this.ecc_gy = new BigInteger(ecc_param[5], 16);

		this.ecc_gx_fieldelement = new Fp(this.ecc_p, this.ecc_gx);
		this.ecc_gy_fieldelement = new Fp(this.ecc_p, this.ecc_gy);

		this.ecc_curve = new ECCurve.Fp(this.ecc_p, this.ecc_a, this.ecc_b);
		this.ecc_point_g = new ECPoint.Fp(this.ecc_curve, this.ecc_gx_fieldelement, this.ecc_gy_fieldelement);

		this.ecc_bc_spec = new ECDomainParameters(this.ecc_curve, this.ecc_point_g, this.ecc_n);

		ECKeyGenerationParameters ecc_ecgenparam;
		ecc_ecgenparam = new ECKeyGenerationParameters(this.ecc_bc_spec, new SecureRandom());

		this.ecc_key_pair_generator = new ECKeyPairGenerator();
		this.ecc_key_pair_generator.init(ecc_ecgenparam);
	}

	public byte[] sm2GetZ(byte[] userId, ECPoint userKey)
	{
		SM3Digest sm3 = new SM3Digest();

		int len = userId.length * 8;
		sm3.update((byte) (len >> 8 & 0xFF));
		sm3.update((byte) (len & 0xFF));
		sm3.update(userId, 0, userId.length);

		byte[] p = Util.byteConvert32Bytes(ecc_a);
		sm3.update(p, 0, p.length);

		p = Util.byteConvert32Bytes(ecc_b);
		sm3.update(p, 0, p.length);

		p = Util.byteConvert32Bytes(ecc_gx);
		sm3.update(p, 0, p.length);

		p = Util.byteConvert32Bytes(ecc_gy);
		sm3.update(p, 0, p.length);

		p = Util.byteConvert32Bytes(userKey.getX().toBigInteger());
		sm3.update(p, 0, p.length);

		p = Util.byteConvert32Bytes(userKey.getY().toBigInteger());
		sm3.update(p, 0, p.length);

		byte[] md = new byte[sm3.getDigestSize()];
		sm3.doFinal(md, 0);
		return md;
	}

	public void sm2Sign(byte[] md, BigInteger userD, ECPoint userKey, SM2Result sm2Result)
	{
		BigInteger e = new BigInteger(1, md);
		BigInteger k = null;
		ECPoint kp = null;
		BigInteger r = null;
		BigInteger s = null;
		do
		{
			do
			{
				// 正式环境
				AsymmetricCipherKeyPair keypair = ecc_key_pair_generator.generateKeyPair();
				ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) keypair.getPrivate();
				ECPublicKeyParameters ecpub = (ECPublicKeyParameters) keypair.getPublic();
				k = ecpriv.getD();
				kp = ecpub.getQ();

				// 国密规范测试 随机数k
//				String kS = "6CB28D99385C175C94F94E934817663FC176D925DD72B727260DBAAE1FB2F96F";
//				k = new BigInteger(kS, 16);
//				kp = this.ecc_point_g.multiply(k);

//				System.out.println("计算曲线点X1: " + kp.getX().toBigInteger().toString(16));
//				System.out.println("计算曲线点Y1: " + kp.getY().toBigInteger().toString(16));
//				System.out.println("");

				// r
				r = e.add(kp.getX().toBigInteger());
				r = r.mod(ecc_n);
			} while (r.equals(BigInteger.ZERO) || r.add(k).equals(ecc_n));

			// (1 + dA)~-1
			BigInteger da_1 = userD.add(BigInteger.ONE);
			da_1 = da_1.modInverse(ecc_n);

			// s
			s = r.multiply(userD);
			s = k.subtract(s).mod(ecc_n);
			s = da_1.multiply(s).mod(ecc_n);
		} while (s.equals(BigInteger.ZERO));

		sm2Result.r = r;
		sm2Result.s = s;
	}

	public void sm2Verify(byte[] md, ECPoint userKey, BigInteger r, BigInteger s, SM2Result sm2Result)
	{
		sm2Result.R = null;
		BigInteger e = new BigInteger(1, md);
		BigInteger t = r.add(s).mod(ecc_n);
		if(t.equals(BigInteger.ZERO))
		{
			return;
		}
		else
		{
			ECPoint x1y1 = ecc_point_g.multiply(sm2Result.s);
//			System.out.println("计算曲线点X0: " + x1y1.getX().toBigInteger().toString(16));
//			System.out.println("计算曲线点Y0: " + x1y1.getY().toBigInteger().toString(16));
//			System.out.println("");

			x1y1 = x1y1.add(userKey.multiply(t));
//			System.out.println("计算曲线点X1: " + x1y1.getX().toBigInteger().toString(16));
//			System.out.println("计算曲线点Y1: " + x1y1.getY().toBigInteger().toString(16));
//			System.out.println("");
			sm2Result.R = e.add(x1y1.getX().toBigInteger()).mod(ecc_n);
			System.out.println("R: " + sm2Result.R.toString(16));
			return;
		}
	}
}
SM2Utils
import org.bouncycastle.asn1.*;
import org.bouncycastle.math.ec.ECPoint;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Enumeration;

public class SM2Utils
{
	public static byte[] encrypt(byte[] publicKey, byte[] data) throws IOException
	{
		if (publicKey == null || publicKey.length == 0)
		{
			return null;
		}

		if (data == null || data.length == 0)
		{
			return null;
		}

		byte[] source = new byte[data.length];
		System.arraycopy(data, 0, source, 0, data.length);

		Cipher cipher = new Cipher();
		SM2 sm2 = SM2.Instance();
		ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);

		ECPoint c1 = cipher.Init_enc(sm2, userKey);
		cipher.Encrypt(source);
		byte[] c3 = new byte[32];
		cipher.Dofinal(c3);

		DERInteger x = new DERInteger(c1.getX().toBigInteger());
		DERInteger y = new DERInteger(c1.getY().toBigInteger());
		DEROctetString derDig = new DEROctetString(c3);
		DEROctetString derEnc = new DEROctetString(source);
		ASN1EncodableVector v = new ASN1EncodableVector();
		v.add(x);
		v.add(y);
		v.add(derDig);
		v.add(derEnc);
		DERSequence seq = new DERSequence(v);
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		DEROutputStream dos = new DEROutputStream(bos);
		dos.writeObject(seq);
		return bos.toByteArray();
	}

	public static byte[] decrypt(byte[] privateKey, byte[] encryptedData) throws IOException
	{
		if (privateKey == null || privateKey.length == 0)
		{
			return null;
		}

		if (encryptedData == null || encryptedData.length == 0)
		{
			return null;
		}

		byte[] enc = new byte[encryptedData.length];
		System.arraycopy(encryptedData, 0, enc, 0, encryptedData.length);

		SM2 sm2 = SM2.Instance();
		BigInteger userD = new BigInteger(1, privateKey);

		ByteArrayInputStream bis = new ByteArrayInputStream(enc);
		ASN1InputStream dis = new ASN1InputStream(bis);
		DERObject derObj = dis.readObject();
		ASN1Sequence asn1 = (ASN1Sequence) derObj;
		DERInteger x = (DERInteger) asn1.getObjectAt(0);
		DERInteger y = (DERInteger) asn1.getObjectAt(1);
		ECPoint c1 = sm2.ecc_curve.createPoint(x.getValue(), y.getValue(), true);

		Cipher cipher = new Cipher();
		cipher.Init_dec(userD, c1);
		DEROctetString data = (DEROctetString) asn1.getObjectAt(3);
		enc = data.getOctets();
		cipher.Decrypt(enc);
		byte[] c3 = new byte[32];
		cipher.Dofinal(c3);
		return enc;
	}

	public static byte[] sign(byte[] userId, byte[] privateKey, byte[] sourceData) throws IOException
	{
		if (privateKey == null || privateKey.length == 0)
		{
			return null;
		}

		if (sourceData == null || sourceData.length == 0)
		{
			return null;
		}

		SM2 sm2 = SM2.Instance();
		BigInteger userD = new BigInteger(privateKey);
//		System.out.println("userD: " + userD.toString(16));
//		System.out.println("");

		ECPoint userKey = sm2.ecc_point_g.multiply(userD);
//		System.out.println("椭圆曲线点X: " + userKey.getX().toBigInteger().toString(16));
//		System.out.println("椭圆曲线点Y: " + userKey.getY().toBigInteger().toString(16));
//		System.out.println("");

		SM3Digest sm3 = new SM3Digest();
		byte[] z = sm2.sm2GetZ(userId, userKey);
//		System.out.println("SM3摘要Z: " + Util.getHexString(z));
//		System.out.println("");
//
//		System.out.println("M: " + Util.getHexString(sourceData));
//		System.out.println("");

		sm3.update(z, 0, z.length);
		sm3.update(sourceData, 0, sourceData.length);
		byte[] md = new byte[32];
		sm3.doFinal(md, 0);

//		System.out.println("SM3摘要值: " + Util.getHexString(md));
//		System.out.println("");

		SM2Result sm2Result = new SM2Result();
		sm2.sm2Sign(md, userD, userKey, sm2Result);
//		System.out.println("r: " + sm2Result.r.toString(16));
//		System.out.println("s: " + sm2Result.s.toString(16));
//		System.out.println("");

		DERInteger d_r = new DERInteger(sm2Result.r);
		DERInteger d_s = new DERInteger(sm2Result.s);
		ASN1EncodableVector v2 = new ASN1EncodableVector();
		v2.add(d_r);
		v2.add(d_s);
		DERObject sign = new DERSequence(v2);
		byte[] signdata = sign.getDEREncoded();
		return signdata;
	}

	@SuppressWarnings("unchecked")
	public static boolean verifySign(byte[] userId, byte[] publicKey, byte[] sourceData, byte[] signData) throws IOException
	{
		if (publicKey == null || publicKey.length == 0)
		{
			return false;
		}

		if (sourceData == null || sourceData.length == 0)
		{
			return false;
		}

		SM2 sm2 = SM2.Instance();
		ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);

		SM3Digest sm3 = new SM3Digest();
		byte[] z = sm2.sm2GetZ(userId, userKey);
		sm3.update(z, 0, z.length);
		sm3.update(sourceData, 0, sourceData.length);
		byte[] md = new byte[32];
		sm3.doFinal(md, 0);
		System.out.println("SM3摘要值: " + Util.getHexString(md));
		System.out.println();

		ByteArrayInputStream bis = new ByteArrayInputStream(signData);
		ASN1InputStream dis = new ASN1InputStream(bis);
		DERObject derObj = dis.readObject();
		Enumeration<DERInteger> e = ((ASN1Sequence) derObj).getObjects();
		BigInteger r = e.nextElement().getValue();
		BigInteger s = e.nextElement().getValue();
		SM2Result sm2Result = new SM2Result();
		sm2Result.r = r;
		sm2Result.s = s;
//		System.out.println("r: " + sm2Result.r.toString(16));
//		System.out.println("s: " + sm2Result.s.toString(16));
//		System.out.println("");


		sm2.sm2Verify(md, userKey, sm2Result.r, sm2Result.s, sm2Result);
		return sm2Result.r.equals(sm2Result.R);
	}

}

2、版本区间1.48-1.59

之所以先写这个版本区间,是因为博主一开始用的版本是1.45改的1.55,所以就讲这个。各位使用的bcprov的版本在1.49到1.59之间都可以参考。

(1)引入依赖

我只演示区间内的其中一个版本,其他版本可自行替换测试,注意jdk版本。

        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.55</version>
        </dependency>

(2)关键代码

Cipher

同基线版本就可以,不再重复。

SM2

同基线版本就可以,不再重复。

SM2Utils
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bouncycastle.asn1.*;
import org.bouncycastle.math.ec.ECPoint;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Enumeration;

public class SM2Utils
{
	private static Log log = LogFactory.getLog(SM2Utils.class);
	public static byte[] encrypt(byte[] publicKey, byte[] data) throws IOException
	{
		if (publicKey == null || publicKey.length == 0)
		{
			return null;
		}

		if (data == null || data.length == 0)
		{
			return null;
		}

		byte[] source = new byte[data.length];
		System.arraycopy(data, 0, source, 0, data.length);

		Cipher cipher = new Cipher();
		SM2 sm2 = SM2.Instance();
		ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);

		ECPoint c1 = cipher.Init_enc(sm2, userKey);
		cipher.Encrypt(source);
		byte[] c3 = new byte[32];
		cipher.Dofinal(c3);

		DERInteger x = new DERInteger(c1.getX().toBigInteger());
		DERInteger y = new DERInteger(c1.getY().toBigInteger());
		DEROctetString derDig = new DEROctetString(c3);
		DEROctetString derEnc = new DEROctetString(source);
		ASN1EncodableVector v = new ASN1EncodableVector();
		v.add(x);
		v.add(y);
		v.add(derDig);
		v.add(derEnc);
		DERSequence seq = new DERSequence(v);
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		DEROutputStream dos = new DEROutputStream(bos);
		dos.writeObject(seq);
		return bos.toByteArray();
	}

	public static byte[] decrypt(byte[] privateKey, byte[] encryptedData) throws IOException
	{
		if (privateKey == null || privateKey.length == 0)
		{
			return null;
		}

		if (encryptedData == null || encryptedData.length == 0)
		{
			return null;
		}

		byte[] enc = new byte[encryptedData.length];
		System.arraycopy(encryptedData, 0, enc, 0, encryptedData.length);

		SM2 sm2 = SM2.Instance();
		BigInteger userD = new BigInteger(1, privateKey);

		ByteArrayInputStream bis = new ByteArrayInputStream(enc);
		ASN1InputStream dis = new ASN1InputStream(bis);
		// 使用ASN1Object代替DERObject,ASN1Integer代替DERInteger
		// DERObject derObj = dis.readObject();
		// ASN1Sequence asn1 = (ASN1Sequence) derObj;
		// DERInteger x = (DERInteger) asn1.getObjectAt(0);
		// DERInteger y = (DERInteger) asn1.getObjectAt(1);
		ASN1Object derObj = (ASN1Object) dis.readObject();
		ASN1Sequence asn1 = (ASN1Sequence) derObj;
		ASN1Integer x = (ASN1Integer) asn1.getObjectAt(0);
		ASN1Integer y = (ASN1Integer) asn1.getObjectAt(1);
		
		ECPoint c1 = sm2.ecc_curve.createPoint(x.getValue(), y.getValue(), true);

		Cipher cipher = new Cipher();
		cipher.Init_dec(userD, c1);
		DEROctetString data = (DEROctetString) asn1.getObjectAt(3);
		enc = data.getOctets();
		cipher.Decrypt(enc);
		byte[] c3 = new byte[32];
		cipher.Dofinal(c3);
		return enc;
	}

	public static byte[] sign(byte[] userId, byte[] privateKey, byte[] sourceData) throws IOException
	{
		if (privateKey == null || privateKey.length == 0)
		{
			return null;
		}

		if (sourceData == null || sourceData.length == 0)
		{
			return null;
		}

		SM2 sm2 = SM2.Instance();
		BigInteger userD = new BigInteger(privateKey);
//		System.out.println("userD: " + userD.toString(16));
//		System.out.println("");

		ECPoint userKey = sm2.ecc_point_g.multiply(userD);
//		System.out.println("椭圆曲线点X: " + userKey.getX().toBigInteger().toString(16));
//		System.out.println("椭圆曲线点Y: " + userKey.getY().toBigInteger().toString(16));
//		System.out.println("");

		SM3Digest sm3 = new SM3Digest();
		byte[] z = sm2.sm2GetZ(userId, userKey);
//		System.out.println("SM3摘要Z: " + Util.getHexString(z));
//		System.out.println("");
//
//		System.out.println("M: " + Util.getHexString(sourceData));
//		System.out.println("");

		sm3.update(z, 0, z.length);
		sm3.update(sourceData, 0, sourceData.length);
		byte[] md = new byte[32];
		sm3.doFinal(md, 0);

//		System.out.println("SM3摘要值: " + Util.getHexString(md));
//		System.out.println("");

		SM2Result sm2Result = new SM2Result();
		sm2.sm2Sign(md, userD, userKey, sm2Result);
//		System.out.println("r: " + sm2Result.r.toString(16));
//		System.out.println("s: " + sm2Result.s.toString(16));
//		System.out.println("");

		DERInteger d_r = new DERInteger(sm2Result.r);
		DERInteger d_s = new DERInteger(sm2Result.s);
		ASN1EncodableVector v2 = new ASN1EncodableVector();
		v2.add(d_r);
		v2.add(d_s);
		// 调整DER编码的写法
		// DERObject sign = new DERSequence(v2);
		// byte[] signdata = sign.getDEREncoded();
		ASN1Object sign = new DERSequence(v2);
		byte[] signdata = sign.getEncoded("DER");
		
		return signdata;
	}

	@SuppressWarnings("unchecked")
	public static boolean verifySign(byte[] userId, byte[] publicKey, byte[] sourceData, byte[] signData) throws IOException
	{
		if (publicKey == null || publicKey.length == 0)
		{
			return false;
		}

		if (sourceData == null || sourceData.length == 0)
		{
			return false;
		}

		SM2 sm2 = SM2.Instance();
		ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);

		SM3Digest sm3 = new SM3Digest();
		byte[] z = sm2.sm2GetZ(userId, userKey);
		sm3.update(z, 0, z.length);
		sm3.update(sourceData, 0, sourceData.length);
		byte[] md = new byte[32];
		sm3.doFinal(md, 0);
		if (log.isInfoEnabled()){
			log.info("SM3摘要值: " + Util.getHexString(md));
		}
//		System.out.println("SM3摘要值: " + Util.getHexString(md));
//		System.out.println();

		ByteArrayInputStream bis = new ByteArrayInputStream(signData);
		ASN1InputStream dis = new ASN1InputStream(bis);
		// 使用ASN1Object替换DERObject,ASN1Integer替换DERInteger
		// DERObject derObj = dis.readObject();
		// Enumeration<DERInteger> e = ((ASN1Sequence) derObj).getObjects();
		ASN1Object derObj = (ASN1Object) dis.readObject();
		Enumeration<ASN1Integer> e = ((ASN1Sequence) derObj).getObjects();
		
		BigInteger r = e.nextElement().getValue();
		BigInteger s = e.nextElement().getValue();
		SM2Result sm2Result = new SM2Result();
		sm2Result.r = r;
		sm2Result.s = s;
//		System.out.println("r: " + sm2Result.r.toString(16));
//		System.out.println("s: " + sm2Result.s.toString(16));
//		System.out.println("");


		sm2.sm2Verify(md, userKey, sm2Result.r, sm2Result.s, sm2Result);
		return sm2Result.r.equals(sm2Result.R);
	}

}

3、版本区间1.38-1.47

仓库不存在1.39、1.41和1.42版本,另外1.32无法适配,这个问题在上面也有说过,如果想用1.32版本但是不会降级的小伙伴也可以评论区咨询。

(1)引入依赖

我只演示区间内的其中一个版本,其他版本可自行替换测试,注意jdk版本。

        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15</artifactId>
            <version>1.45</version>
        </dependency>

(2)关键代码

Cipher

同基线版本就可以,不再重复。

SM2

同基线版本就可以,不再重复。

SM2Utils

同基线版本就可以,不再重复。

4、版本区间1.50-1.63

有些小伙伴可能会很奇怪,上面1.49-1.59不是包含了1.48-1.59了吗,为什么这里还有呢?其实也很好理解,毕竟实现方法不止一种,所以说版本在1.50-1.59之间的可以用上面的方法,也可以用这里的方法。

(1)引入依赖

我只演示区间内的其中一个版本,其他版本可自行替换测试,注意jdk版本。

        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.60</version>
        </dependency>

(2)关键代码

Cipher
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;

import java.math.BigInteger;


public class Cipher
{
    private int ct;
    private ECPoint p2;
    private SM3Digest sm3keybase;
    private SM3Digest sm3c3;
    private byte[] key;
    private byte keyOff;

    public Cipher()
    {
        this.ct = 1;
        this.key = new byte[32];
        this.keyOff = 0;
    }

    private void Reset()
    {
        this.sm3keybase = new SM3Digest();
        this.sm3c3 = new SM3Digest();

        byte[] p = Util.byteConvert32Bytes(p2.normalize().getXCoord().toBigInteger());
        this.sm3keybase.update(p, 0, p.length);
        this.sm3c3.update(p, 0, p.length);

        p = Util.byteConvert32Bytes(p2.normalize().getYCoord().toBigInteger());
        this.sm3keybase.update(p, 0, p.length);
        this.ct = 1;
        NextKey();
    }

    private void NextKey()
    {
        SM3Digest sm3keycur = new SM3Digest(this.sm3keybase);
        sm3keycur.update((byte) (ct >> 24 & 0xff));
        sm3keycur.update((byte) (ct >> 16 & 0xff));
        sm3keycur.update((byte) (ct >> 8 & 0xff));
        sm3keycur.update((byte) (ct & 0xff));
        sm3keycur.doFinal(key, 0);
        this.keyOff = 0;
        this.ct++;
    }

    public ECPoint Init_enc(SM2 sm2, ECPoint userKey)
    {
        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();
        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();
        ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();
        BigInteger k = ecpriv.getD();
        ECPoint c1 = ecpub.getQ();
        this.p2 = userKey.multiply(k);
        Reset();
        return c1;
    }

    public void Encrypt(byte[] data)
    {
        this.sm3c3.update(data, 0, data.length);
        for (int i = 0; i < data.length; i++)
        {
            if (keyOff == key.length)
            {
                NextKey();
            }
            data[i] ^= key[keyOff++];
        }
    }

    public void Init_dec(BigInteger userD, ECPoint c1)
    {
        this.p2 = c1.multiply(userD);
        Reset();
    }

    public void Decrypt(byte[] data)
    {
        for (int i = 0; i < data.length; i++)
        {
            if (keyOff == key.length)
            {
                NextKey();
            }
            data[i] ^= key[keyOff++];
        }

        this.sm3c3.update(data, 0, data.length);
    }

    public void Dofinal(byte[] c3)
    {
        byte[] p = Util.byteConvert32Bytes(p2.normalize().getYCoord().toBigInteger());
        this.sm3c3.update(p, 0, p.length);
        this.sm3c3.doFinal(c3, 0);
        Reset();
    }
}
SM2
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.math.BigInteger;
import java.security.SecureRandom;

public class SM2
{
	 //测试参数
//	public static final String[] ecc_param = {
//			"8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3",
//			"787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498",
//			"63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A",
//			"8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7",
//			"421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D",
//			"0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2"
//	};

	// 正式参数 为国密算法推荐参数
	public static String[] ecc_param = {
		"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",
		"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",
		"28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",
		"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",
		"32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",
		"BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"
	};

	public static SM2 Instance()
	{
		return new SM2();
	}

	public final BigInteger ecc_p;
	public final BigInteger ecc_a;
	public final BigInteger ecc_b;
	public final BigInteger ecc_n;
	public final BigInteger ecc_gx;
	public final BigInteger ecc_gy;
	public final ECCurve ecc_curve;
	public final ECPoint ecc_point_g;
	public final ECDomainParameters ecc_bc_spec;
	public final ECKeyPairGenerator ecc_key_pair_generator;
	public final ECFieldElement ecc_gx_fieldelement;
	public final ECFieldElement ecc_gy_fieldelement;

	public SM2()
	{
		this.ecc_p = new BigInteger(ecc_param[0], 16);
		this.ecc_a = new BigInteger(ecc_param[1], 16);
		this.ecc_b = new BigInteger(ecc_param[2], 16);
		this.ecc_n = new BigInteger(ecc_param[3], 16);
		this.ecc_gx = new BigInteger(ecc_param[4], 16);
		this.ecc_gy = new BigInteger(ecc_param[5], 16);

		this.ecc_gx_fieldelement = new Fp(this.ecc_p, this.ecc_gx);
		this.ecc_gy_fieldelement = new Fp(this.ecc_p, this.ecc_gy);

		this.ecc_curve = new ECCurve.Fp(this.ecc_p, this.ecc_a, this.ecc_b);
		// 使用反射调用方法
		ECPoint ecc_point_g1 = null;
		try {
			// 此区间的bcprov版本的构造方法是私有的,无法直接new,只能通过反射来调用构造方法
			Class clazz = ECPoint.Fp.class;
			/*以下调用带参的、私有构造函数*/
			Constructor c1 = clazz.getDeclaredConstructor(new Class[]{ECCurve.class, ECFieldElement.class, ECFieldElement.class, boolean.class});
			c1.setAccessible(true);
			ecc_point_g1 = (ECPoint.Fp)c1.newInstance(new Object[]{this.ecc_curve, this.ecc_gx_fieldelement, this.ecc_gy_fieldelement, false});
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}

		this.ecc_point_g = ecc_point_g1;
		
		this.ecc_bc_spec = new ECDomainParameters(this.ecc_curve, this.ecc_point_g, this.ecc_n);

		ECKeyGenerationParameters ecc_ecgenparam;
		ecc_ecgenparam = new ECKeyGenerationParameters(this.ecc_bc_spec, new SecureRandom());

		this.ecc_key_pair_generator = new ECKeyPairGenerator();
		this.ecc_key_pair_generator.init(ecc_ecgenparam);
	}

	public byte[] sm2GetZ(byte[] userId, ECPoint userKey)
	{
		SM3Digest sm3 = new SM3Digest();

		int len = userId.length * 8;
		sm3.update((byte) (len >> 8 & 0xFF));
		sm3.update((byte) (len & 0xFF));
		sm3.update(userId, 0, userId.length);

		byte[] p = Util.byteConvert32Bytes(ecc_a);
		sm3.update(p, 0, p.length);

		p = Util.byteConvert32Bytes(ecc_b);
		sm3.update(p, 0, p.length);

		p = Util.byteConvert32Bytes(ecc_gx);
		sm3.update(p, 0, p.length);

		p = Util.byteConvert32Bytes(ecc_gy);
		sm3.update(p, 0, p.length);

		p = Util.byteConvert32Bytes(userKey.normalize().getXCoord().toBigInteger());
		sm3.update(p, 0, p.length);

		p = Util.byteConvert32Bytes(userKey.normalize().getYCoord().toBigInteger());
		sm3.update(p, 0, p.length);

		byte[] md = new byte[sm3.getDigestSize()];
		sm3.doFinal(md, 0);
		return md;
	}

	public void sm2Sign(byte[] md, BigInteger userD, ECPoint userKey, SM2Result sm2Result)
	{
		BigInteger e = new BigInteger(1, md);
		BigInteger k = null;
		ECPoint kp = null;
		BigInteger r = null;
		BigInteger s = null;
		do
		{
			do
			{
				// 正式环境
				AsymmetricCipherKeyPair keypair = ecc_key_pair_generator.generateKeyPair();
				ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) keypair.getPrivate();
				ECPublicKeyParameters ecpub = (ECPublicKeyParameters) keypair.getPublic();
				k = ecpriv.getD();
				kp = ecpub.getQ();

				// 国密规范测试 随机数k
//				String kS = "6CB28D99385C175C94F94E934817663FC176D925DD72B727260DBAAE1FB2F96F";
//				k = new BigInteger(kS, 16);
//				kp = this.ecc_point_g.multiply(k);

//				System.out.println("计算曲线点X1: " + kp.getX().toBigInteger().toString(16));
//				System.out.println("计算曲线点Y1: " + kp.getY().toBigInteger().toString(16));
//				System.out.println("");

				// r
				r = e.add(kp.normalize().getXCoord().toBigInteger());
				r = r.mod(ecc_n);
			} while (r.equals(BigInteger.ZERO) || r.add(k).equals(ecc_n));

			// (1 + dA)~-1
			BigInteger da_1 = userD.add(BigInteger.ONE);
			da_1 = da_1.modInverse(ecc_n);

			// s
			s = r.multiply(userD);
			s = k.subtract(s).mod(ecc_n);
			s = da_1.multiply(s).mod(ecc_n);
		} while (s.equals(BigInteger.ZERO));

		sm2Result.r = r;
		sm2Result.s = s;
	}

	public void sm2Verify(byte[] md, ECPoint userKey, BigInteger r, BigInteger s, SM2Result sm2Result)
	{
		sm2Result.R = null;
		BigInteger e = new BigInteger(1, md);
		BigInteger t = r.add(s).mod(ecc_n);
		if(t.equals(BigInteger.ZERO))
		{
			return;
		}
		else
		{
			ECPoint x1y1 = ecc_point_g.multiply(sm2Result.s);
//			System.out.println("计算曲线点X0: " + x1y1.getX().toBigInteger().toString(16));
//			System.out.println("计算曲线点Y0: " + x1y1.getY().toBigInteger().toString(16));
//			System.out.println("");

			x1y1 = x1y1.add(userKey.multiply(t));
//			System.out.println("计算曲线点X1: " + x1y1.getX().toBigInteger().toString(16));
//			System.out.println("计算曲线点Y1: " + x1y1.getY().toBigInteger().toString(16));
//			System.out.println("");
			sm2Result.R = e.add(x1y1.normalize().getXCoord().toBigInteger()).mod(ecc_n);
//			System.out.println("R: " + sm2Result.R.toString(16));
			return;
		}
	}
}
SM2Utils
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bouncycastle.asn1.*;
import org.bouncycastle.math.ec.ECPoint;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Enumeration;

public class SM2Utils
{
	private static Log log = LogFactory.getLog(SM2Utils.class);
	public static byte[] encrypt(byte[] publicKey, byte[] data) throws IOException
	{
		if (publicKey == null || publicKey.length == 0)
		{
			return null;
		}

		if (data == null || data.length == 0)
		{
			return null;
		}

		byte[] source = new byte[data.length];
		System.arraycopy(data, 0, source, 0, data.length);

		Cipher cipher = new Cipher();
		SM2 sm2 = SM2.Instance();
		ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);

		ECPoint c1 = cipher.Init_enc(sm2, userKey);
		cipher.Encrypt(source);
		byte[] c3 = new byte[32];
		cipher.Dofinal(c3);

		DERInteger x = new DERInteger(c1.normalize().getXCoord().toBigInteger());
		DERInteger y = new DERInteger(c1.normalize().getYCoord().toBigInteger());
		DEROctetString derDig = new DEROctetString(c3);
		DEROctetString derEnc = new DEROctetString(source);
		ASN1EncodableVector v = new ASN1EncodableVector();
		v.add(x);
		v.add(y);
		v.add(derDig);
		v.add(derEnc);
		DERSequence seq = new DERSequence(v);
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		DEROutputStream dos = new DEROutputStream(bos);
		dos.writeObject(seq);
		return bos.toByteArray();
	}

	public static byte[] decrypt(byte[] privateKey, byte[] encryptedData) throws IOException
	{
		if (privateKey == null || privateKey.length == 0)
		{
			return null;
		}

		if (encryptedData == null || encryptedData.length == 0)
		{
			return null;
		}

		byte[] enc = new byte[encryptedData.length];
		System.arraycopy(encryptedData, 0, enc, 0, encryptedData.length);

		SM2 sm2 = SM2.Instance();
		BigInteger userD = new BigInteger(1, privateKey);

		ByteArrayInputStream bis = new ByteArrayInputStream(enc);
		ASN1InputStream dis = new ASN1InputStream(bis);
		// 使用ASN1Object代替DERObject,ASN1Integer代替ASN1Object
		// DERObject derObj = dis.readObject();
		// ASN1Sequence asn1 = (ASN1Sequence) derObj;
		// DERInteger x = (DERInteger) asn1.getObjectAt(0);
		// DERInteger y = (DERInteger) asn1.getObjectAt(1);
		ASN1Object derObj = (ASN1Object) dis.readObject();
		ASN1Sequence asn1 = (ASN1Sequence) derObj;
		ASN1Integer x = (ASN1Integer) asn1.getObjectAt(0);
		ASN1Integer y = (ASN1Integer) asn1.getObjectAt(1);
		
		ECPoint c1 = sm2.ecc_curve.createPoint(x.getValue(), y.getValue());

		Cipher cipher = new Cipher();
		cipher.Init_dec(userD, c1);
		DEROctetString data = (DEROctetString) asn1.getObjectAt(3);
		enc = data.getOctets();
		cipher.Decrypt(enc);
		byte[] c3 = new byte[32];
		cipher.Dofinal(c3);
		return enc;
	}

	public static byte[] sign(byte[] userId, byte[] privateKey, byte[] sourceData) throws IOException
	{
		if (privateKey == null || privateKey.length == 0)
		{
			return null;
		}

		if (sourceData == null || sourceData.length == 0)
		{
			return null;
		}

		SM2 sm2 = SM2.Instance();
		BigInteger userD = new BigInteger(privateKey);
//		System.out.println("userD: " + userD.toString(16));
//		System.out.println("");

		ECPoint userKey = sm2.ecc_point_g.multiply(userD);
//		System.out.println("椭圆曲线点X: " + userKey.getX().toBigInteger().toString(16));
//		System.out.println("椭圆曲线点Y: " + userKey.getY().toBigInteger().toString(16));
//		System.out.println("");

		SM3Digest sm3 = new SM3Digest();
		byte[] z = sm2.sm2GetZ(userId, userKey);
//		System.out.println("SM3摘要Z: " + Util.getHexString(z));
//		System.out.println("");
//
//		System.out.println("M: " + Util.getHexString(sourceData));
//		System.out.println("");

		sm3.update(z, 0, z.length);
		sm3.update(sourceData, 0, sourceData.length);
		byte[] md = new byte[32];
		sm3.doFinal(md, 0);

//		System.out.println("SM3摘要值: " + Util.getHexString(md));
//		System.out.println("");

		SM2Result sm2Result = new SM2Result();
		sm2.sm2Sign(md, userD, userKey, sm2Result);
//		System.out.println("r: " + sm2Result.r.toString(16));
//		System.out.println("s: " + sm2Result.s.toString(16));
//		System.out.println("");

		DERInteger d_r = new DERInteger(sm2Result.r);
		DERInteger d_s = new DERInteger(sm2Result.s);
		ASN1EncodableVector v2 = new ASN1EncodableVector();
		v2.add(d_r);
		v2.add(d_s);
		// 调整DER编码的写法
		// DERObject sign = new DERSequence(v2);
		// byte[] signdata = sign.getDEREncoded();
		ASN1Object sign = new DERSequence(v2);
		byte[] signdata = sign.getEncoded("DER");
		
		return signdata;
	}

	@SuppressWarnings("unchecked")
	public static boolean verifySign(byte[] userId, byte[] publicKey, byte[] sourceData, byte[] signData) throws IOException
	{
		if (publicKey == null || publicKey.length == 0)
		{
			return false;
		}

		if (sourceData == null || sourceData.length == 0)
		{
			return false;
		}

		SM2 sm2 = SM2.Instance();
		ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);

		SM3Digest sm3 = new SM3Digest();
		byte[] z = sm2.sm2GetZ(userId, userKey);
		sm3.update(z, 0, z.length);
		sm3.update(sourceData, 0, sourceData.length);
		byte[] md = new byte[32];
		sm3.doFinal(md, 0);
		if (log.isDebugEnabled()){
			log.debug("SM3摘要值: " + Util.getHexString(md));
		}
//		System.out.println("SM3摘要值: " + Util.getHexString(md));
//		System.out.println();

		ByteArrayInputStream bis = new ByteArrayInputStream(signData);
		ASN1InputStream dis = new ASN1InputStream(bis);
		// 使用ASN1Object替换DERObject,ASN1Integer替换DERInteger
		// DERObject derObj = dis.readObject();
		// Enumeration<DERInteger> e = ((ASN1Sequence) derObj).getObjects();
		ASN1Object derObj = (ASN1Object) dis.readObject();
		Enumeration<ASN1Integer> e = ((ASN1Sequence) derObj).getObjects();
		
		BigInteger r = e.nextElement().getValue();
		BigInteger s = e.nextElement().getValue();
		SM2Result sm2Result = new SM2Result();
		sm2Result.r = r;
		sm2Result.s = s;
//		System.out.println("r: " + sm2Result.r.toString(16));
//		System.out.println("s: " + sm2Result.s.toString(16));
//		System.out.println("");

		sm2.sm2Verify(md, userKey, sm2Result.r, sm2Result.s, sm2Result);
		return sm2Result.r.equals(sm2Result.R);
	}

}

5、版本区间1.64-1.75

(1)引入依赖

我只演示区间内的其中一个版本,其他版本可自行替换测试,注意jdk版本。

        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.64</version>
        </dependency>

(2)关键代码

Cipher
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;

import java.math.BigInteger;


public class Cipher
{
    private int ct;
    private ECPoint p2;
    private SM3Digest sm3keybase;
    private SM3Digest sm3c3;
    private byte[] key;
    private byte keyOff;

    public Cipher()
    {
        this.ct = 1;
        this.key = new byte[32];
        this.keyOff = 0;
    }

    private void Reset()
    {
        this.sm3keybase = new SM3Digest();
        this.sm3c3 = new SM3Digest();

        byte[] p = Util.byteConvert32Bytes(p2.normalize().getXCoord().toBigInteger());
        this.sm3keybase.update(p, 0, p.length);
        this.sm3c3.update(p, 0, p.length);

        p = Util.byteConvert32Bytes(p2.normalize().getYCoord().toBigInteger());
        this.sm3keybase.update(p, 0, p.length);
        this.ct = 1;
        NextKey();
    }

    private void NextKey()
    {
        SM3Digest sm3keycur = new SM3Digest(this.sm3keybase);
        sm3keycur.update((byte) (ct >> 24 & 0xff));
        sm3keycur.update((byte) (ct >> 16 & 0xff));
        sm3keycur.update((byte) (ct >> 8 & 0xff));
        sm3keycur.update((byte) (ct & 0xff));
        sm3keycur.doFinal(key, 0);
        this.keyOff = 0;
        this.ct++;
    }

    public ECPoint Init_enc(SM2 sm2, ECPoint userKey)
    {
        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();
        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();
        ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();
        BigInteger k = ecpriv.getD();
        ECPoint c1 = ecpub.getQ();
        this.p2 = userKey.multiply(k);
        Reset();
        return c1;
    }

    public void Encrypt(byte[] data)
    {
        this.sm3c3.update(data, 0, data.length);
        for (int i = 0; i < data.length; i++)
        {
            if (keyOff == key.length)
            {
                NextKey();
            }
            data[i] ^= key[keyOff++];
        }
    }

    public void Init_dec(BigInteger userD, ECPoint c1)
    {
        this.p2 = c1.multiply(userD);
        Reset();
    }

    public void Decrypt(byte[] data)
    {
        for (int i = 0; i < data.length; i++)
        {
            if (keyOff == key.length)
            {
                NextKey();
            }
            data[i] ^= key[keyOff++];
        }

        this.sm3c3.update(data, 0, data.length);
    }

    public void Dofinal(byte[] c3)
    {
        byte[] p = Util.byteConvert32Bytes(p2.normalize().getYCoord().toBigInteger());
        this.sm3c3.update(p, 0, p.length);
        this.sm3c3.doFinal(c3, 0);
        Reset();
    }
}
SM2
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECFieldElement;
import org.bouncycastle.math.ec.ECFieldElement.Fp;
import org.bouncycastle.math.ec.ECPoint;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.math.BigInteger;
import java.security.SecureRandom;

public class SM2
{
	 //测试参数
//	public static final String[] ecc_param = {
//			"8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3",
//			"787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498",
//			"63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A",
//			"8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7",
//			"421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D",
//			"0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2"
//	};

	// 正式参数 为国密算法推荐参数
	public static String[] ecc_param = {
		"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",
		"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",
		"28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",
		"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",
		"32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",
		"BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"
	};

	public static SM2 Instance()
	{
		return new SM2();
	}

	public final BigInteger ecc_p;
	public final BigInteger ecc_a;
	public final BigInteger ecc_b;
	public final BigInteger ecc_n;
	public final BigInteger ecc_gx;
	public final BigInteger ecc_gy;
	public final ECCurve ecc_curve;
	public final ECPoint ecc_point_g;
	public final ECDomainParameters ecc_bc_spec;
	public final ECKeyPairGenerator ecc_key_pair_generator;
	public final ECFieldElement ecc_gx_fieldelement;
	public final ECFieldElement ecc_gy_fieldelement;

	public SM2()
	{
		this.ecc_p = new BigInteger(ecc_param[0], 16);
		this.ecc_a = new BigInteger(ecc_param[1], 16);
		this.ecc_b = new BigInteger(ecc_param[2], 16);
		this.ecc_n = new BigInteger(ecc_param[3], 16);
		this.ecc_gx = new BigInteger(ecc_param[4], 16);
		this.ecc_gy = new BigInteger(ecc_param[5], 16);

        // 以下两行代码在try块中通过反射创建,故需注释
		// this.ecc_gx_fieldelement = new Fp(this.ecc_p, this.ecc_gx);
		// this.ecc_gy_fieldelement = new Fp(this.ecc_p, this.ecc_gy);
		
		// 以下一行代码位置移动到try块中,故需注释
		// this.ecc_curve = new ECCurve.Fp(this.ecc_p, this.ecc_a, this.ecc_b);
		
		// 使用反射调用方法
		ECPoint ecc_point_g1 = null;
		try {
			// 此区间的bcprov版本的构造方法是私有的,无法直接new,只能通过反射来调用构造方法
			Class clazz = ECPoint.Fp.class;
			/*以下调用带参的、私有构造函数*/
			Constructor c1 = clazz.getDeclaredConstructor(new Class[]{ECCurve.class, ECFieldElement.class, ECFieldElement.class});
			c1.setAccessible(true);
			Class clazz2 = ECFieldElement.Fp.class;

			Constructor c2 = clazz2.getDeclaredConstructor(new Class[]{BigInteger.class, BigInteger.class, BigInteger.class});
			c2.setAccessible(true);
//		this.ecc_gx_fieldelement = new Fp(this.ecc_p, this.ecc_gx);
			// 此区间的bcprov版本的构造方法是私有的,无法直接new,只能通过反射来获取对象
			BigInteger r = calculateResidue(this.ecc_p);
			this.ecc_gx_fieldelement = (ECFieldElement.Fp)c2.newInstance(new Object[]{this.ecc_p, r, this.ecc_gx});
			// 此区间的bcprov版本的构造方法是私有的,无法直接new,只能通过反射来获取对象
//		this.ecc_gy_fieldelement = new Fp(this.ecc_p, this.ecc_gy);
			this.ecc_gy_fieldelement = (ECFieldElement.Fp)c2.newInstance(new Object[]{this.ecc_p, r, this.ecc_gy});

			this.ecc_curve = new ECCurve.Fp(this.ecc_p, this.ecc_a, this.ecc_b);

//		this.ecc_point_g = new ECPoint.Fp(this.ecc_curve, this.ecc_gx_fieldelement, this.ecc_gy_fieldelement);
			ecc_point_g1 = (ECPoint.Fp)c1.newInstance(new Object[]{this.ecc_curve, this.ecc_gx_fieldelement, this.ecc_gy_fieldelement});
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}

		this.ecc_point_g = ecc_point_g1;
		this.ecc_bc_spec = new ECDomainParameters(this.ecc_curve, this.ecc_point_g, this.ecc_n);

		ECKeyGenerationParameters ecc_ecgenparam;
		ecc_ecgenparam = new ECKeyGenerationParameters(this.ecc_bc_spec, new SecureRandom());

		this.ecc_key_pair_generator = new ECKeyPairGenerator();
		this.ecc_key_pair_generator.init(ecc_ecgenparam);
	}

	/**
	 * 计算Residue
	 *
	 * @param p
	 * @return
	 */
	public static BigInteger calculateResidue(BigInteger p)
	{
		int bitLength = p.bitLength();
		if (bitLength >= 96)
		{
			BigInteger firstWord = p.shiftRight(bitLength - 64);
			if (firstWord.longValue() == -1L)
			{
				return ECConstants.ONE.shiftLeft(bitLength).subtract(p);
			}
		}
		return null;
	}

	public byte[] sm2GetZ(byte[] userId, ECPoint userKey)
	{
		SM3Digest sm3 = new SM3Digest();

		int len = userId.length * 8;
		sm3.update((byte) (len >> 8 & 0xFF));
		sm3.update((byte) (len & 0xFF));
		sm3.update(userId, 0, userId.length);

		byte[] p = Util.byteConvert32Bytes(ecc_a);
		sm3.update(p, 0, p.length);

		p = Util.byteConvert32Bytes(ecc_b);
		sm3.update(p, 0, p.length);

		p = Util.byteConvert32Bytes(ecc_gx);
		sm3.update(p, 0, p.length);

		p = Util.byteConvert32Bytes(ecc_gy);
		sm3.update(p, 0, p.length);

		p = Util.byteConvert32Bytes(userKey.normalize().getXCoord().toBigInteger());
		sm3.update(p, 0, p.length);

		p = Util.byteConvert32Bytes(userKey.normalize().getYCoord().toBigInteger());
		sm3.update(p, 0, p.length);

		byte[] md = new byte[sm3.getDigestSize()];
		sm3.doFinal(md, 0);
		return md;
	}

	public void sm2Sign(byte[] md, BigInteger userD, ECPoint userKey, SM2Result sm2Result)
	{
		BigInteger e = new BigInteger(1, md);
		BigInteger k = null;
		ECPoint kp = null;
		BigInteger r = null;
		BigInteger s = null;
		do
		{
			do
			{
				// 正式环境
				AsymmetricCipherKeyPair keypair = ecc_key_pair_generator.generateKeyPair();
				ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) keypair.getPrivate();
				ECPublicKeyParameters ecpub = (ECPublicKeyParameters) keypair.getPublic();
				k = ecpriv.getD();
				kp = ecpub.getQ();

				// 国密规范测试 随机数k
//				String kS = "6CB28D99385C175C94F94E934817663FC176D925DD72B727260DBAAE1FB2F96F";
//				k = new BigInteger(kS, 16);
//				kp = this.ecc_point_g.multiply(k);

//				System.out.println("计算曲线点X1: " + kp.getX().toBigInteger().toString(16));
//				System.out.println("计算曲线点Y1: " + kp.getY().toBigInteger().toString(16));
//				System.out.println("");

				// r
				r = e.add(kp.normalize().getXCoord().toBigInteger());
				r = r.mod(ecc_n);
			} while (r.equals(BigInteger.ZERO) || r.add(k).equals(ecc_n));

			// (1 + dA)~-1
			BigInteger da_1 = userD.add(BigInteger.ONE);
			da_1 = da_1.modInverse(ecc_n);

			// s
			s = r.multiply(userD);
			s = k.subtract(s).mod(ecc_n);
			s = da_1.multiply(s).mod(ecc_n);
		} while (s.equals(BigInteger.ZERO));

		sm2Result.r = r;
		sm2Result.s = s;
	}

	public void sm2Verify(byte[] md, ECPoint userKey, BigInteger r, BigInteger s, SM2Result sm2Result)
	{
		sm2Result.R = null;
		BigInteger e = new BigInteger(1, md);
		BigInteger t = r.add(s).mod(ecc_n);
		if(t.equals(BigInteger.ZERO))
		{
			return;
		}
		else
		{
			ECPoint x1y1 = ecc_point_g.multiply(sm2Result.s);
//			System.out.println("计算曲线点X0: " + x1y1.getX().toBigInteger().toString(16));
//			System.out.println("计算曲线点Y0: " + x1y1.getY().toBigInteger().toString(16));
//			System.out.println("");

			x1y1 = x1y1.add(userKey.multiply(t));
//			System.out.println("计算曲线点X1: " + x1y1.getX().toBigInteger().toString(16));
//			System.out.println("计算曲线点Y1: " + x1y1.getY().toBigInteger().toString(16));
//			System.out.println("");
			sm2Result.R = e.add(x1y1.normalize().getXCoord().toBigInteger()).mod(ecc_n);
//			System.out.println("R: " + sm2Result.R.toString(16));
			return;
		}
	}
}
SM2Utils
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bouncycastle.asn1.*;
import org.bouncycastle.math.ec.ECPoint;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Enumeration;

public class SM2Utils
{
	private static Log log = LogFactory.getLog(SM2Utils.class);
	public static byte[] encrypt(byte[] publicKey, byte[] data) throws IOException
	{
		if (publicKey == null || publicKey.length == 0)
		{
			return null;
		}

		if (data == null || data.length == 0)
		{
			return null;
		}

		byte[] source = new byte[data.length];
		System.arraycopy(data, 0, source, 0, data.length);

		Cipher cipher = new Cipher();
		SM2 sm2 = SM2.Instance();
		ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);

		ECPoint c1 = cipher.Init_enc(sm2, userKey);
		cipher.Encrypt(source);
		byte[] c3 = new byte[32];
		cipher.Dofinal(c3);

		ASN1Integer x = new ASN1Integer(c1.normalize().getXCoord().toBigInteger());
		ASN1Integer y = new ASN1Integer(c1.normalize().getYCoord().toBigInteger());
		DEROctetString derDig = new DEROctetString(c3);
		DEROctetString derEnc = new DEROctetString(source);
		ASN1EncodableVector v = new ASN1EncodableVector();
		v.add(x);
		v.add(y);
		v.add(derDig);
		v.add(derEnc);
		DERSequence seq = new DERSequence(v);
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		try {
			// 此区间的bcprov版本的构造方法是私有的,无法直接new,只能通过反射来调用构造方法
			Class clazz = ASN1OutputStream.class;
			Constructor c4 = clazz.getDeclaredConstructor(new Class[]{OutputStream.class});
			c4.setAccessible(true);
//			ASN1OutputStream dos = new ASN1OutputStream(bos);
			ASN1OutputStream dos = (ASN1OutputStream) c4.newInstance(new Object[]{bos});
			dos.writeObject(seq);
			return bos.toByteArray();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public static byte[] decrypt(byte[] privateKey, byte[] encryptedData) throws IOException
	{
		if (privateKey == null || privateKey.length == 0)
		{
			return null;
		}

		if (encryptedData == null || encryptedData.length == 0)
		{
			return null;
		}

		byte[] enc = new byte[encryptedData.length];
		System.arraycopy(encryptedData, 0, enc, 0, encryptedData.length);

		SM2 sm2 = SM2.Instance();
		BigInteger userD = new BigInteger(1, privateKey);

		ByteArrayInputStream bis = new ByteArrayInputStream(enc);
		ASN1InputStream dis = new ASN1InputStream(bis);
		// 使用ASN1Object替换DERObject,ASN1Integer替换DERInteger
		// DERObject derObj = dis.readObject();
		// ASN1Sequence asn1 = (ASN1Sequence) derObj;
		// DERInteger x = (DERInteger) asn1.getObjectAt(0);
		// DERInteger y = (DERInteger) asn1.getObjectAt(1);
		ASN1Object derObj = (ASN1Object) dis.readObject();
		ASN1Sequence asn1 = (ASN1Sequence) derObj;
		ASN1Integer x = (ASN1Integer) asn1.getObjectAt(0);
		ASN1Integer y = (ASN1Integer) asn1.getObjectAt(1);
		
		ECPoint c1 = sm2.ecc_curve.createPoint(x.getValue(), y.getValue());

		Cipher cipher = new Cipher();
		cipher.Init_dec(userD, c1);
		DEROctetString data = (DEROctetString) asn1.getObjectAt(3);
		enc = data.getOctets();
		cipher.Decrypt(enc);
		byte[] c3 = new byte[32];
		cipher.Dofinal(c3);
		return enc;
	}

	public static byte[] sign(byte[] userId, byte[] privateKey, byte[] sourceData) throws IOException
	{
		if (privateKey == null || privateKey.length == 0)
		{
			return null;
		}

		if (sourceData == null || sourceData.length == 0)
		{
			return null;
		}

		SM2 sm2 = SM2.Instance();
		BigInteger userD = new BigInteger(privateKey);
//		System.out.println("userD: " + userD.toString(16));
//		System.out.println("");

		ECPoint userKey = sm2.ecc_point_g.multiply(userD);
//		System.out.println("椭圆曲线点X: " + userKey.getX().toBigInteger().toString(16));
//		System.out.println("椭圆曲线点Y: " + userKey.getY().toBigInteger().toString(16));
//		System.out.println("");

		SM3Digest sm3 = new SM3Digest();
		byte[] z = sm2.sm2GetZ(userId, userKey);
//		System.out.println("SM3摘要Z: " + Util.getHexString(z));
//		System.out.println("");
//
//		System.out.println("M: " + Util.getHexString(sourceData));
//		System.out.println("");

		sm3.update(z, 0, z.length);
		sm3.update(sourceData, 0, sourceData.length);
		byte[] md = new byte[32];
		sm3.doFinal(md, 0);

//		System.out.println("SM3摘要值: " + Util.getHexString(md));
//		System.out.println("");

		SM2Result sm2Result = new SM2Result();
		sm2.sm2Sign(md, userD, userKey, sm2Result);
//		System.out.println("r: " + sm2Result.r.toString(16));
//		System.out.println("s: " + sm2Result.s.toString(16));
//		System.out.println("");

		ASN1Integer d_r = new ASN1Integer(sm2Result.r);
		ASN1Integer d_s = new ASN1Integer(sm2Result.s);
//		BigInteger d_r = sm2Result.r;
//		BigInteger d_s = sm2Result.s;
		ASN1EncodableVector v2 = new ASN1EncodableVector();
		v2.add(d_r);
		v2.add(d_s);
		// 调整DER编码的写法
		// DERObject sign = new DERSequence(v2);
		// byte[] signdata = sign.getDEREncoded();
		ASN1Object sign = new DERSequence(v2);
		byte[] signdata = sign.getEncoded("DER");
		
		return signdata;
	}

	@SuppressWarnings("unchecked")
	public static boolean verifySign(byte[] userId, byte[] publicKey, byte[] sourceData, byte[] signData) throws IOException
	{
		if (publicKey == null || publicKey.length == 0)
		{
			return false;
		}

		if (sourceData == null || sourceData.length == 0)
		{
			return false;
		}

		SM2 sm2 = SM2.Instance();
		ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);

		SM3Digest sm3 = new SM3Digest();
		byte[] z = sm2.sm2GetZ(userId, userKey);
		sm3.update(z, 0, z.length);
		sm3.update(sourceData, 0, sourceData.length);
		byte[] md = new byte[32];
		sm3.doFinal(md, 0);
		if (log.isDebugEnabled()){
			log.debug("SM3摘要值: " + Util.getHexString(md));
		}
//		System.out.println("SM3摘要值: " + Util.getHexString(md));
//		System.out.println();

		ByteArrayInputStream bis = new ByteArrayInputStream(signData);
		ASN1InputStream dis = new ASN1InputStream(bis);
		// 使用ASN1Object替换DERObject,ASN1Integer替换DERInteger
		// DERObject derObj = dis.readObject();
		// Enumeration<DERInteger> e = ((ASN1Sequence) derObj).getObjects();
		ASN1Object derObj = (ASN1Object) dis.readObject();
		Enumeration<ASN1Integer> e = ((ASN1Sequence) derObj).getObjects();
		
		BigInteger r = e.nextElement().getValue();
		BigInteger s = e.nextElement().getValue();
		SM2Result sm2Result = new SM2Result();
		sm2Result.r = r;
		sm2Result.s = s;
//		System.out.println("r: " + sm2Result.r.toString(16));
//		System.out.println("s: " + sm2Result.s.toString(16));
//		System.out.println("");


		sm2.sm2Verify(md, userKey, sm2Result.r, sm2Result.s, sm2Result);
		return sm2Result.r.equals(sm2Result.R);
	}

}

总结

虽然贴了很多代码,但是如果用对比工具看的话,实际改动的代码也就二三十行而已,主要是高版本的方法稍微改了,还有个别方法无法直接使用,需要用反射来调用,仅此而已。
当然,除了上述的代码调整外,还可以使用第三方工具包,比如hutool,不过也是需要注意hutool也有适用的bcprov版本;还有方法是隔离jar包加载,让特定的类加载特定版本的jar包版本,这两种方式如果想看的也可以评论区提出。

感谢各位大佬的阅读,还望动动小手,一键三连就行了,给博主一点创作的动力。

  • 42
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 32
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 32
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九二战歌

原创不易,尽量不白瓢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值