老版本bcprov-jdk15on和新版本的有点不一样,新版本的签名后需要DER格式和r|s格式转换,可以和老版本一样
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
import org.bouncycastle.asn1.*;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithID;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Arrays;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.Security;
import java.util.Enumeration;
import java.util.function.Function;
/**
* @author EvanY
* @since 2023/01
*/
public class SM2Utils {
public static final String CURVE_NAME = "sm2p256v1";
private static ECDomainParameters getECDomainParameters() {
ECParameterSpec spec = ECNamedCurveTable.getParameterSpec(CURVE_NAME);
return new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN(), spec.getH(), spec.getSeed());
}
private static ECCurve getSM2Curve() {
ECParameterSpec spec = ECNamedCurveTable.getParameterSpec(CURVE_NAME);
return spec.getCurve();
}
private static ECPublicKeyParameters encodePublicKey(byte[] value) {
byte[] x = new byte[32];
byte[] y = new byte[32];
System.arraycopy(value, 0, x, 0, 32);
System.arraycopy(value, 32, y, 0, 32);
BigInteger X = new BigInteger(1, x);
BigInteger Y = new BigInteger(1, y);
ECPoint Q = getSM2Curve().createPoint(X, Y);
return new ECPublicKeyParameters(Q, getECDomainParameters());
}
public static byte[] sign(byte[] privateKey, byte[] iv, byte[] message) throws CryptoException {
BigInteger d = new BigInteger(1, privateKey);
CipherParameters privateKeyParam = new ECPrivateKeyParameters(d, getECDomainParameters());
CipherParameters parameters = privateKeyParam;
SM2Signer signer = new SM2Signer();
if (iv != null && iv.length > 0) {
parameters = new ParametersWithID(privateKeyParam, iv);
}
signer.init(true, parameters);
signer.update(message, 0, message.length);
return signer.generateSignature();
}
public static boolean verify(byte[] publicKey, byte[] iv, byte[] message, byte[] signature) {
ECPublicKeyParameters pubKey = encodePublicKey(publicKey);
CipherParameters parameters = pubKey;
SM2Signer signer = new SM2Signer();
if (iv != null && iv.length > 0) {
signer.init(false, pubKey);
} else {
parameters = new ParametersWithID(pubKey, iv);
}
signer.init(false, parameters);
signer.update(message, 0, message.length);
return signer.verifySignature(signature);
}
/**
* 将 r|s 格式的签名值转换为 DER 格式的签名
*/
public static byte[] encodeDERSignature(byte[] signature) throws IOException {
// 将签名的字节数组分割成两个 32 字节的数组,分别对应 R 和 S 的值
byte[] r = new byte[32];
byte[] s = new byte[32];
System.arraycopy(signature, 0, r, 0, 32);
System.arraycopy(signature, 32, s, 0, 32);
// 将 R 和 S 的值转换为 BigInteger 对象,使用 ASN1Integer 类进行封装
ASN1Integer rAsn1 = new ASN1Integer(new BigInteger(1, r));
ASN1Integer sAsn1 = new ASN1Integer(new BigInteger(1, s));
// 将两个 ASN1Integer 对象添加到一个 ASN1EncodableVector 对象中,使用 DERSequence 类进行编码
ASN1EncodableVector vector = new ASN1EncodableVector();
vector.add(rAsn1);
vector.add(sAsn1);
DERSequence derSequence = new DERSequence(vector);
// 将 DERSequence 对象转换为字节数组,即为 DER 格式的签名
return derSequence.getEncoded();
}
/**
* 将DER格式的签名解码为r|s格式的签名值
*/
public static byte[] decodeDERSignature(byte[] signature) throws IOException {
// 格式化r和s的值,确保长度为32字节
Function<byte[], byte[]> format = value -> {
if (value.length == 32) {
return value;
} else {
final byte[] bytes = new byte[32];
if (value.length > 32) {
System.arraycopy(value, value.length - 32, bytes, 0, 32);
} else {
System.arraycopy(value, 0, bytes, 32 - value.length, value.length);
}
return bytes;
}
};
// 解析ASN.1结构,提取r和s的值
final ASN1InputStream stream = new ASN1InputStream(new ByteArrayInputStream(signature));
final ASN1Sequence primitive = (ASN1Sequence)stream.readObject();
final Enumeration<?> enumeration = primitive.getObjects();
final BigInteger R = ((ASN1Integer)enumeration.nextElement()).getValue();
final BigInteger S = ((ASN1Integer)enumeration.nextElement()).getValue();
final byte[] r = format.apply(R.toByteArray());
final byte[] s = format.apply(S.toByteArray());
// 拼接r和s的值,得到64字节的字节数组
return Arrays.concatenate(r, s);
}
static {
if (Security.getProvider("BC") == null) {
Security.addProvider(new BouncyCastleProvider());
}
}
}
标签:Java,32,org,bouncycastle,SM2,jdk15on,import,new,byte
From: https://www.cnblogs.com/yy299/p/18031268