前言
关于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-Id | artifact-Id | version | 完整jar包名 |
---|---|---|---|
org.bouncycastle | bcprov-jdk15 | 1.32 | bcprov-jdk15-1.32.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15 bcprov-jdk16 |
1.38 | bcprov-jdk14-1.38.jar bcprov-jdk15-1.38.jar bcprov-jdk16-1.38.jar |
org.bouncycastle | bcprov-jdk15 bcprov-jdk16 |
1.40 | bcprov-jdk15-1.40.jar bcprov-jdk16-1.40.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15 bcprov-jdk16 |
1.43 | bcprov-jdk14-1.43.jar bcprov-jdk15-1.43.jar bcprov-jdk16-1.43.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15 bcprov-jdk16 |
1.44 | bcprov-jdk14-1.44.jar bcprov-jdk15-1.44.jar bcprov-jdk16-1.44.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15 bcprov-jdk16 |
1.44 | bcprov-jdk14-1.44.jar bcprov-jdk15-1.44.jar bcprov-jdk16-1.44.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15 bcprov-jdk16 |
1.45 | bcprov-jdk14-1.45.jar bcprov-jdk15-1.45.jar bcprov-jdk16-1.45.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15 bcprov-jdk15+ bcprov-jdk15on bcprov-jdk16 |
1.46 | bcprov-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.bouncycastle | bcprov-jdk14 bcprov-jdk15on |
1.47 | bcprov-jdk14-1.47.jar bcprov-jdk15on-1.47.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on |
1.48 | bcprov-jdk14-1.48.jar bcprov-jdk15on-1.48.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on |
1.49 | bcprov-jdk14-1.49.jar bcprov-jdk15on-1.49.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on |
1.50 | bcprov-jdk14-1.50.jar bcprov-jdk15on-1.50.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on |
1.51 | bcprov-jdk14-1.51.jar bcprov-jdk15on-1.51.jar |
org.bouncycastle | bcprov-jdk15on | 1.52 | bcprov-jdk15on-1.52.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on |
1.53 | bcprov-jdk14-1.53.jar bcprov-jdk15on-1.53.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on |
1.54 | bcprov-jdk14-1.54.jar bcprov-jdk15on-1.54.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on |
1.55 | bcprov-jdk14-1.55.jar bcprov-jdk15on-1.55.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on |
1.56 | bcprov-jdk14-1.56.jar bcprov-jdk15on-1.56.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on |
1.57 | bcprov-jdk14-1.57.jar bcprov-jdk15on-1.57.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on |
1.58 | bcprov-jdk14-1.58.jar bcprov-jdk15on-1.58.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on |
1.59 | bcprov-jdk14-1.59.jar bcprov-jdk15on-1.59.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on |
1.60 | bcprov-jdk14-1.60.jar bcprov-jdk15on-1.60.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on |
1.61 | bcprov-jdk14-1.61.jar bcprov-jdk15on-1.61.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on |
1.62 | bcprov-jdk14-1.62.jar bcprov-jdk15on-1.62.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on bcprov-jdk15to18 |
1.63 | bcprov-jdk14-1.63.jar bcprov-jdk15on-1.63.jar bcprov-jdk15to18-1.63.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on bcprov-jdk15to18 |
1.64 | bcprov-jdk14-1.64.jar bcprov-jdk15on-1.64.jar bcprov-jdk15to18-1.64.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on bcprov-jdk15to18 |
1.65 | bcprov-jdk14-1.65.jar bcprov-jdk15on-1.65.jar bcprov-jdk15to18-1.65.jar |
org.bouncycastle | bcprov-jdk15on bcprov-jdk15to18 |
1.66 | bcprov-jdk15-1.66.jar bcprov-jdk16-1.66.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on bcprov-jdk15to18 |
1.67 | bcprov-jdk14-1.67.jar bcprov-jdk15on-1.67.jar bcprov-jdk15to18-1.67.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on bcprov-jdk15to18 |
1.68 | bcprov-jdk14-1.68.jar bcprov-jdk15on-1.68.jar bcprov-jdk15to18-1.68.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on bcprov-jdk15to18 |
1.69 | bcprov-jdk14-1.69.jar bcprov-jdk15on-1.69.jar bcprov-jdk15to18-1.69.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15on bcprov-jdk15to18 |
1.70 | bcprov-jdk14-1.70.jar bcprov-jdk15on-1.70.jar bcprov-jdk15to18-1.70.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15to18 bcprov-jdk18on |
1.71 | bcprov-jdk14-1.71.jar bcprov-jdk15to18-1.71.jar bcprov-jdk18on-1.71.jar |
org.bouncycastle | bcprov-jdk14 bcprov-jdk15to18 bcprov-jdk18on |
1.72 | bcprov-jdk14-1.72.jar bcprov-jdk15to18-1.72.jar bcprov-jdk18on-1.72.jar |
更新说明
2023-06-27 增加1.73-1.75版本,且从1.74开始、不再支持jdk1.4版本,至少要jdk1.5及以上。
group-Id | artifact-Id | version | 完整jar包名 |
---|---|---|---|
org.bouncycastle | bcprov-jdk14 bcprov-jdk15to18 bcprov-jdk18on |
1.73 | bcprov-jdk14-1.73.jar bcprov-jdk15to18-1.73.jar bcprov-jdk18on-1.73.jar |
org.bouncycastle | bcprov-jdk15to18 bcprov-jdk18on |
1.74 | bcprov-jdk15to18-1.74.jar bcprov-jdk18on-1.74.jar |
org.bouncycastle | bcprov-jdk15to18 bcprov-jdk18on |
1.75 | bcprov-jdk15to18-1.75.jar bcprov-jdk18on-1.75.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)更新说明
2023-05-22 调整1.64-1.72区间代码,SM2和SM2Utils类,之前这个区间的代码贴成1.50-1.63区间的了,很抱歉。
2023-06-27 “版本1.64-1.72区间”调整为”版本1.64-1.75区间”,博主实测以下代码兼容1.73-1.75版本。
(2)引入依赖
我只演示区间内的其中一个版本,其他版本可自行替换测试,注意jdk版本。
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.64</version>
</dependency>
(3)关键代码
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);
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});
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包版本,这两种方式如果想看的也可以评论区提出。文章来源:https://www.toymoban.com/news/detail-440808.html
感谢各位大佬的阅读,还望动动小手,一键三连就行了,给博主一点创作的动力。文章来源地址https://www.toymoban.com/news/detail-440808.html
到了这里,关于java bcprov 国密 依赖 jar包 版本 升级 降级 教程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!