依赖
implementation("org.bouncycastle:bcprov-debug-jdk15on:1.64")
代码
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.asn1.x9.X9ECParametersHolder;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.*;
/**
* 国家密码管理局无线局域网密钥工具类
*/
public class WAPIUtil {
/**
* 中国无线 LAN 标准 (GB 15629.11-2003)
* http://www.chinabwips.org.cn/doc/101.pdf
*
* {@link GMObjectIdentifiers#wapip192v1}
*/
public static final ASN1ObjectIdentifier china_wapip192v1 = new ASN1ObjectIdentifier("1.2.156.11235.1.1.2.1");
/**
* 国密算法: WAPI_P192_V1
*
* {@link WAPIUtil#china_wapip192v1}
* {@link GMObjectIdentifiers#wapip192v1}
* {@link GMNamedCurves#wapip192v1}
*/
public static final String NAME_WAPI_P192_V1 = "wapip192v1";
/**
* 国密算法: SM2_P256_V1
*
* {@link GMObjectIdentifiers#sm2p256v1}
* {@link GMNamedCurves#sm2p256v1}
*/
public static final String NAME_SM2_P256_V1 = "sm2p256v1";
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
static {
try {
Field field = GMNamedCurves.class.getDeclaredField(NAME_WAPI_P192_V1);
field.setAccessible(true);
X9ECParametersHolder holder = (X9ECParametersHolder) field.get(null);
Method method = GMNamedCurves.class.getDeclaredMethod(
"defineCurve", String.class,
ASN1ObjectIdentifier.class, X9ECParametersHolder.class
);
method.setAccessible(true);
method.invoke(null, NAME_WAPI_P192_V1, china_wapip192v1, holder);
} catch (Exception e) {
e.printStackTrace();
}
Security.addProvider(new BouncyCastleProvider());
}
public static byte[] encrypt(PublicKey publicKey, byte[] data) throws InvalidKeyException, InvalidCipherTextException {
return processBlock(true, publicKey, data);
}
public static byte[] decrypt(PrivateKey privateKey, byte[] data) throws InvalidKeyException, InvalidCipherTextException {
return processBlock(false, privateKey, data);
}
public static byte[] sign(PrivateKey privateKey, byte[] id, byte[] data) throws InvalidKeyException, CryptoException {
SM2Signer sm2Signer = getSM2Signer(true, privateKey, id);
sm2Signer.update(data, 0, data.length);
return sm2Signer.generateSignature();
}
public static boolean verify(PublicKey publicKey, byte[] id, byte[] sign) throws InvalidKeyException {
return getSM2Signer(false, publicKey, id) .verifySignature(sign);
}
public static List<X509Certificate> parseCertificate(String pem) throws GeneralSecurityException {
List<byte[]> bytesList = parseObjectFromPem(pem, "CERTIFICATE");
List<X509Certificate> result = new ArrayList<>();
for (byte[] bytes : bytesList) {
result.add(parseCertificate(bytes));
}
return result;
}
public static X509Certificate parseCertificate(byte[] bytes) throws GeneralSecurityException {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
return (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(bytes));
}
public static BCECPrivateKey parsePrivateKey(String pem) throws GeneralSecurityException {
List<byte[]> bytesList = parseObjectFromPem(pem, "EC PRIVATE KEY");
byte[] bytes = bytesList.get(0);
return parsePrivateKey(NAME_SM2_P256_V1, bytes);
}
public static BCECPrivateKey parsePrivateKey(String name, byte[] bytes) throws GeneralSecurityException {
X9ECParameters ecParameters = GMNamedCurves.getByName(name);
ECParameterSpec ecParameterSpec = new ECParameterSpec(ecParameters.getCurve(), ecParameters.getG(), ecParameters.getN(), ecParameters.getH());
BigInteger bigIntegerD = new BigInteger(bytes);
KeyFactory keyFactory = KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME);
return (BCECPrivateKey) keyFactory.generatePrivate(new ECPrivateKeySpec(bigIntegerD, ecParameterSpec));
}
/**
* 从 pem 文件解析密钥
* @param pem
* @param type "CERTIFICATE"/"EC PRIVATE KEY"
* @return
*/
public static List<byte[]> parseObjectFromPem(String pem, String type) throws InvalidKeyException {
List<byte[]> result = new ArrayList<>();
PemReader pemReader = new PemReader(new StringReader(pem));
try {
PemObject pemObject;
while ((pemObject = pemReader.readPemObject()) != null) {
if (Objects.equals(type, pemObject.getType())) {
result.add(pemObject.getContent());
}
}
} catch (IOException e) {
throw new InvalidKeyException("read key failed", e);
}
if (result.isEmpty()) {
throw new InvalidKeyException("not found key");
}
return result;
}
private static byte[] processBlock(boolean forEncryption, Key key, byte[] data) throws InvalidKeyException, InvalidCipherTextException {
CipherParameters cipherParameters;
if (forEncryption) {
PublicKey publicKey = (PublicKey) key;
cipherParameters = new ParametersWithRandom(ECUtil.generatePublicKeyParameter(publicKey), SECURE_RANDOM);
} else {
PrivateKey privateKey = (PrivateKey) key;
cipherParameters = ECUtil.generatePrivateKeyParameter(privateKey);
}
SM2Engine sm2Engine = new SM2Engine();
sm2Engine.init(forEncryption, cipherParameters);
return sm2Engine.processBlock(data, 0, data.length);
}
private static SM2Signer getSM2Signer(boolean forSigning, Key key, byte[] id) throws InvalidKeyException {
CipherParameters cipherParameters;
if (forSigning) {
PrivateKey privateKey = (PrivateKey) key;
cipherParameters = ECUtil.generatePrivateKeyParameter(privateKey);
} else {
PublicKey publicKey = (PublicKey) key;
cipherParameters = ECUtil.generatePublicKeyParameter(publicKey);
}
SM2Signer sm2Signer = new SM2Signer();
sm2Signer.init(forSigning, new ParametersWithID(new ParametersWithRandom(cipherParameters, SECURE_RANDOM), id));
return sm2Signer;
}
}