<dependency>
<groupId>org.bouncycastlegroupId>
<artifactId>bcprov-ext-jdk15to18artifactId>
<version>1.68version>
dependency>
<dependency>
<groupId>org.bouncycastlegroupId>
<artifactId>bcprov-jdk15to18artifactId>
<version>1.68version>
dependency>
private static void initKeyBase64() {
// 创建 sm2 对象
SM2 sm2 = SmUtil.sm2();
// 这里会自动生成对应的随机秘钥对 , 注意! 这里一定要强转,才能得到对应有效的秘钥信息
byte[] privateKey = BCUtil.encodeECPrivateKey(sm2.getPrivateKey());
// 这里公钥不压缩 公钥的第一个字节用于表示是否压缩 可以不要
byte[] publicKey = ((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false);
// 打印当前的公私秘钥
System.out.println("SM2 公钥(HEX): " + HexUtil.encodeHexStr(publicKey));
System.out.println("SM2 公钥长度(HEX): " + HexUtil.encodeHexStr(publicKey).length());
System.out.println("SM2 公钥(BASE64): " + Base64.encodeBase64String(publicKey));
System.out.println("SM2 公钥长度(BASE64): " + Base64.encodeBase64String(publicKey).length());
System.out.println("SM2 私钥(HEX): " + HexUtil.encodeHexStr(privateKey));
System.out.println("SM2 私钥公钥长度(HEX): " + HexUtil.encodeHexStr(privateKey).length());
System.out.println("SM2 私钥(BASE64): " + Base64.encodeBase64String(privateKey));
System.out.println("SM2 私钥长度(BASE64): " + Base64.encodeBase64String(privateKey).length());
}
public static String cmbSM2Encrypt(String sPubKey, String pladat, String charset) {
if (null == charset || !GBK.equalsIgnoreCase(charset)) {
charset = UTF_8;
}
if (StringUtils.isEmpty(pladat)) {
throw new BusinessException("TYSM208", "原文为空");
}
try {
byte[] pubkey = Base64.decodeBase64(sPubKey);
byte[] msg = pladat.getBytes(charset);
byte[] resBt = cmbSM2Encrypt(pubkey, msg);
return Base64.encodeBase64String(resBt);
} catch (Exception ex) {
System.out.println("SM4Tool.CMBEecrypt error:" + ex);
throw new BusinessException("加密异常:" + ex.getMessage(), "TYSM209");
}
}
private static byte[] cmbSM2Encrypt(byte[] pubkey, byte[] msg) {
if (pubkey == null || msg == null || msg.length == 0) {
throw new BusinessException("请求参数不合法", "TYSM211");
} else if (pubkey.length != 65) {
throw new BusinessException("公钥非法", "TYSM212");
} else if (pubkey[0] != 4) {
throw new BusinessException("公钥非法", "TYSM213");
} else {
ECPublicKeyParameters publicKey = null;
try {
publicKey = encodePublicKey(pubkey);
} catch (Exception var7) {
throw new BusinessException("公钥非法", "TYSM214");
}
SM2Engine engine = new SM2Engine();
engine.init(true, new ParametersWithRandom(publicKey, new SecureRandom()));
try {
byte[] cipherText = engine.processBlock(msg, 0, msg.length);
return C1C2C3ToC1C3C2(cipherText);
} catch (InvalidCipherTextException var6) {
throw new BusinessException("加密失败。", "TYSM215");
}
}
}
public static String cmbSM2Decrypt(String sPrvKeyStr, String strData, String charset) {
if (null == charset || !GBK.equalsIgnoreCase(charset)) {
charset = UTF_8;
}
if (StringUtils.isEmpty(strData)) {
throw new BusinessException("密文为空", "TYSM206");
}
try {
byte[] privkey = Base64.decodeBase64(sPrvKeyStr);
byte[] msg = Base64.decodeBase64(strData);
byte[] resBt = cmbSM2Decrypt(privkey, msg);
return new String(resBt, charset);
} catch (Exception ex) {
System.out.println("SM4Tool.CMBDecrypt error:" + ex);
throw new BusinessException("解密异常:" + ex.getMessage(), "TYSM207");
}
}
private static byte[] cmbSM2Decrypt(byte[] privkey, byte[] msg) {
if (privkey == null || msg == null || privkey.length != 32) {
throw new BusinessException("请求参数不合法", "TYSM216");
} else if (msg.length < 97) {
throw new BusinessException("密文有误", "TYSM217");
} else if (msg[0] != 4) {
throw new BusinessException("密文有误#2", "TYSM218");
} else {
msg = C1C3C2ToC1C2C3(msg);
ECPrivateKeyParameters privateKey = null;
try {
privateKey = encodePrivateKey(privkey);
} catch (Exception var7) {
throw new BusinessException("TYSM219", "公钥错误");
}
SM2Engine engine = new SM2Engine();
engine.init(false, privateKey);
try {
return engine.processBlock(msg, 0, msg.length);
} catch (InvalidCipherTextException var6) {
throw new BusinessException("TYSM220", "解密失败。");
}
}
}
private static byte[] C1C3C2ToC1C2C3(byte[] cipherText) {
if (cipherText != null && cipherText.length >= 97) {
byte[] bytes = new byte[cipherText.length];
System.arraycopy(cipherText, 0, bytes, 0, 65);
System.arraycopy(cipherText, 97, bytes, 65, cipherText.length - 97);
System.arraycopy(cipherText, 65, bytes, cipherText.length - 32, 32);
return bytes;
} else {
throw new BusinessException("TYSM221", "密文有误#3");
}
}
public static String cmbSM2Sign(String sPrivateKey, String sStrToSign, String doSM3, String charset) {
if (StringUtils.isEmpty(sPrivateKey) || StringUtils.isEmpty(sStrToSign)) {
throw new BusinessException("签名数据有误,请检查", "TYSM201");
}
if (!"gbk".equalsIgnoreCase(charset)) {
charset = "utf-8";
}
try {
byte[] privkey = Base64.decodeBase64(sPrivateKey);
byte[] msg = "Y".equals(doSM3) ? CMBSM3Digest(sStrToSign.getBytes(charset)) : sStrToSign.getBytes(charset);
ECPrivateKeyParameters privateKey = encodePrivateKey(privkey);
SM2Signer signer = new SM2Signer();
ParametersWithID parameters = new ParametersWithID(privateKey, USER_ID);
signer.init(true, parameters);
signer.update(msg, 0, msg.length);
return Base64.encodeBase64String(decodeDERSignature(signer.generateSignature()));
} catch (Exception var8) {
throw new BusinessException("签名异常:" + var8.getMessage(), "TYSM202");
}
}
private static byte[] CMBSM3Digest(byte[] msg) {
byte[]bytes = new byte[32];
SM3Digest digest = new SM3Digest();
digest.update(msg, 0, msg.length);
digest.doFinal(bytes, 0);
digest.reset();
return bytes;
}
private static ECPrivateKeyParameters encodePrivateKey(byte[] value) {
BigInteger d = new BigInteger(1, value);
return new ECPrivateKeyParameters(d, getECDomainParameters());
}
private static ECDomainParameters getECDomainParameters() {
ECParameterSpec spec = ECNamedCurveTable.getParameterSpec("sm2p256v1");
return new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN(), spec.getH(), spec.getSeed());
}
public static Boolean cmbSM2Verify(String sPubKey, String strToSign, String strSign, String doSM3, String charset) {
if (!GBK.equalsIgnoreCase(charset)) {
charset = UTF_8;
}
try {
byte[] pubKeys = Base64.decodeBase64(sPubKey);
byte[] byteBuffer = "Y".equals(doSM3) ? CMBSM3Digest(strToSign.getBytes(charset)) : strToSign.getBytes(charset);
byte[] signature = Base64.decodeBase64(strSign);
ECPublicKeyParameters publicKey = encodePublicKey(pubKeys);
SM2Signer signer = new SM2Signer();
ParametersWithID parameters = new ParametersWithID(publicKey, USER_ID);
signer.init(false, parameters);
signer.update(byteBuffer, 0, byteBuffer.length);
if (!signer.verifySignature(encodeDERSignature(signature))) {
throw new BusinessException("请求签名校验不通过。", "TYSM204");
}
return true;
} catch (Exception e) {
if (e instanceof BusinessException) {
throw (BusinessException) e;
}
System.out.println("Verify signature fail: " + e.getMessage());
throw new BusinessException("请求签名校验失败。", "TYSM205");
}
}
private static ECPublicKeyParameters encodePublicKey(byte[] value) {
byte[] x = new byte[32];
byte[] y = new byte[32];
System.arraycopy(value, 1, x, 0, 32);
System.arraycopy(value, 33, y, 0, 32);
BigInteger iX = new BigInteger(1, x);
BigInteger iY = new BigInteger(1, y);
ECPoint ecQ = getSM2Curve().createPoint(iX, iY);
return new ECPublicKeyParameters(ecQ, getECDomainParameters());
}
private static ECCurve getSM2Curve() {
ECParameterSpec spec = ECNamedCurveTable.getParameterSpec("sm2p256v1");
return spec.getCurve();
}
private static ECDomainParameters getECDomainParameters() {
ECParameterSpec spec = ECNamedCurveTable.getParameterSpec("sm2p256v1");
return new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN(), spec.getH(), spec.getSeed());
}
}
public static void main(String[] args) {
//initKeyBase64();
Map<String, String> map = new HashMap<>(3);
map.put("mobile", "18468242454");
map.put("skuCode", "sku2021001");
//TODO 后面替换为真实的核心企业ID
map.put("coreId", "sku2021001");
String data = JSON.toJSONString(map);
String publicSecret = "BMTxlXewbroQEvkgEg41bzUfYE5TVQiBpd4yrOeBQ9Ck3Kj0gHxvGaKnjc4ECwwJ7lIHYwNoCkh6JzxX/3sQ36A=";
System.out.println("公钥字符长度:" + publicSecret.length());
String privateSecret = "NgQBMpptzmgbnl2/yp1xBz7iafpBsyFEpz5kqhdpLSk=";
System.out.println("私钥字符长度:" + privateSecret.length());
System.out.println("加密前的字符:" + data);
//用对方给的公钥加密,然后传给对方
//result:加密得到的数据
String result = cmbSM2Encrypt(publicSecret, data, "UTF-8");
System.out.println("加密得到的字符:" + result);
//dt:对方数据解密都得到的原文
String olData = cmbSM2Decrypt(privateSecret, result, "UTF-8");
System.out.println("解密后的字符:" + olData);
String signData = cmbSM2Sign(privateSecret, data, "Y", "UTF-8");
System.out.println("签名得到的字符:" + signData);
Boolean y = cmbSM2Verify(publicSecret, data, signData, "Y", "UTF-8");
System.out.println("签名验证结果:" + y);
}
package com.***;
public class SM2Utils {
private static final String UTF_8 = "UTF-8";
private static final String GBK = "GBK";
private static final byte[] USER_ID = "1234567812345678".getBytes();
/**
* 使用SM2私钥进行签名
*
* @param sPrivateKey:私钥字符串(BASE64)
* @param sStrToSign:待签名数据
* @param doSM3:是否通过SM3摘要器获取数据摘要
* @param charset:字符集
* @return
* @throws BusinessException
*/
public static String cmbSM2Sign(String sPrivateKey, String sStrToSign, String doSM3, String charset) {
if (StringUtils.isEmpty(sPrivateKey) || StringUtils.isEmpty(sStrToSign)) {
throw new BusinessException("签名数据有误,请检查", "TYSM201");
}
if (!"gbk".equalsIgnoreCase(charset)) {
charset = "utf-8";
}
try {
byte[] privkey = Base64.decodeBase64(sPrivateKey);
byte[] msg = "Y".equals(doSM3) ? CMBSM3Digest(sStrToSign.getBytes(charset)) : sStrToSign.getBytes(charset);
ECPrivateKeyParameters privateKey = encodePrivateKey(privkey);
SM2Signer signer = new SM2Signer();
ParametersWithID parameters = new ParametersWithID(privateKey, USER_ID);
signer.init(true, parameters);
signer.update(msg, 0, msg.length);
return Base64.encodeBase64String(decodeDERSignature(signer.generateSignature()));
} catch (Exception var8) {
throw new BusinessException("签名异常:" + var8.getMessage(), "TYSM202");
}
}
/**
* 验证签名
* @param sPubKey:公钥字符串(BASE64)
* @param strToSign:待验签数据
* @param strSign:签名结果
* @param doSM3:是否通过SM3摘要器获取数据摘要
* @param charset:字符集
* @throws BusinessException
*/
public static Boolean cmbSM2Verify(String sPubKey, String strToSign, String strSign, String doSM3, String charset) {
if (!GBK.equalsIgnoreCase(charset)) {
charset = UTF_8;
}
try {
byte[] pubKeys = Base64.decodeBase64(sPubKey);
byte[] byteBuffer = "Y".equals(doSM3) ? CMBSM3Digest(strToSign.getBytes(charset)) : strToSign.getBytes(charset);
byte[] signature = Base64.decodeBase64(strSign);
ECPublicKeyParameters publicKey = encodePublicKey(pubKeys);
SM2Signer signer = new SM2Signer();
ParametersWithID parameters = new ParametersWithID(publicKey, USER_ID);
signer.init(false, parameters);
signer.update(byteBuffer, 0, byteBuffer.length);
if (!signer.verifySignature(encodeDERSignature(signature))) {
throw new BusinessException("请求签名校验不通过。", "TYSM204");
}
return true;
} catch (Exception e) {
if (e instanceof BusinessException) {
throw (BusinessException) e;
}
System.out.println("Verify signature fail: " + e.getMessage());
throw new BusinessException("请求签名校验失败。", "TYSM205");
}
}
/**
* 使用SM2私钥进行解密
*
* @return
* @throws Exception
*/
public static String cmbSM2Decrypt(String sPrvKeyStr, String strData, String charset) {
if (null == charset || !GBK.equalsIgnoreCase(charset)) {
charset = UTF_8;
}
if (StringUtils.isEmpty(strData)) {
throw new BusinessException("密文为空", "TYSM206");
}
try {
byte[] privkey = Base64.decodeBase64(sPrvKeyStr);
byte[] msg = Base64.decodeBase64(strData);
byte[] resBt = cmbSM2Decrypt(privkey, msg);
return new String(resBt, charset);
} catch (Exception ex) {
System.out.println("SM4Tool.CMBDecrypt error:" + ex);
throw new BusinessException("解密异常:" + ex.getMessage(), "TYSM207");
}
}
/**
* 使用SM2公钥进行加密
*
* @return
* @throws Exception
*/
public static String cmbSM2Encrypt(String sPubKey, String pladat, String charset) {
if (null == charset || !GBK.equalsIgnoreCase(charset)) {
charset = UTF_8;
}
if (StringUtils.isEmpty(pladat)) {
throw new BusinessException("TYSM208", "原文为空");
}
try {
byte[] pubkey = Base64.decodeBase64(sPubKey);
byte[] msg = pladat.getBytes(charset);
byte[] resBt = cmbSM2Encrypt(pubkey, msg);
return Base64.encodeBase64String(resBt);
} catch (Exception ex) {
System.out.println("SM4Tool.CMBEecrypt error:" + ex);
throw new BusinessException("加密异常:" + ex.getMessage(), "TYSM209");
}
}
private static byte[] cmbSM2Encrypt(byte[] pubkey, byte[] msg) {
if (pubkey == null || msg == null || msg.length == 0) {
throw new BusinessException("请求参数不合法", "TYSM211");
} else if (pubkey.length != 65) {
throw new BusinessException("公钥非法", "TYSM212");
} else if (pubkey[0] != 4) {
throw new BusinessException("公钥非法", "TYSM213");
} else {
ECPublicKeyParameters publicKey = null;
try {
publicKey = encodePublicKey(pubkey);
} catch (Exception var7) {
throw new BusinessException("公钥非法", "TYSM214");
}
SM2Engine engine = new SM2Engine();
engine.init(true, new ParametersWithRandom(publicKey, new SecureRandom()));
try {
byte[] cipherText = engine.processBlock(msg, 0, msg.length);
return C1C2C3ToC1C3C2(cipherText);
} catch (InvalidCipherTextException var6) {
throw new BusinessException("加密失败。", "TYSM215");
}
}
}
private static byte[] cmbSM2Decrypt(byte[] privkey, byte[] msg) {
if (privkey == null || msg == null || privkey.length != 32) {
throw new BusinessException("请求参数不合法", "TYSM216");
} else if (msg.length < 97) {
throw new BusinessException("密文有误", "TYSM217");
} else if (msg[0] != 4) {
throw new BusinessException("密文有误#2", "TYSM218");
} else {
msg = C1C3C2ToC1C2C3(msg);
ECPrivateKeyParameters privateKey = null;
try {
privateKey = encodePrivateKey(privkey);
} catch (Exception var7) {
throw new BusinessException("TYSM219", "公钥错误");
}
SM2Engine engine = new SM2Engine();
engine.init(false, privateKey);
try {
return engine.processBlock(msg, 0, msg.length);
} catch (InvalidCipherTextException var6) {
throw new BusinessException("TYSM220", "解密失败。");
}
}
}
private static byte[] C1C3C2ToC1C2C3(byte[] cipherText) {
if (cipherText != null && cipherText.length >= 97) {
byte[] bytes = new byte[cipherText.length];
System.arraycopy(cipherText, 0, bytes, 0, 65);
System.arraycopy(cipherText, 97, bytes, 65, cipherText.length - 97);
System.arraycopy(cipherText, 65, bytes, cipherText.length - 32, 32);
return bytes;
} else {
throw new BusinessException("TYSM221", "密文有误#3");
}
}
private static byte[] C1C2C3ToC1C3C2(byte[] cipherText) {
if (cipherText != null && cipherText.length >= 97) {
byte[] bytes = new byte[cipherText.length];
System.arraycopy(cipherText, 0, bytes, 0, 65);
System.arraycopy(cipherText, cipherText.length - 32, bytes, 65, 32);
System.arraycopy(cipherText, 65, bytes, 97, cipherText.length - 97);
return bytes;
} else {
throw new BusinessException("TYSM222", "密文有误#3");
}
}
private static byte[] decodeDERSignature(byte[] signature) {
try (ASN1InputStream stream = new ASN1InputStream(new ByteArrayInputStream(signature))) {
ASN1Sequence primitive = (ASN1Sequence) stream.readObject();
Enumeration<ASN1Integer> enumeration = primitive.getObjects();
BigInteger R = enumeration.nextElement().getValue();
BigInteger S = enumeration.nextElement().getValue();
byte[] bytes = new byte[64];
byte[] r = format(R.toByteArray());
byte[] s = format(S.toByteArray());
System.arraycopy(r, 0, bytes, 0, 32);
System.arraycopy(s, 0, bytes, 32, 32);
return bytes;
} catch (Exception var10) {
throw new BusinessException("签名解析异常:" + var10.getMessage(), "TYSM223");
}
}
private static byte[] format(byte[] value) {
if (value.length == 32) {
return value;
} else {
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;
}
}
private static ECPrivateKeyParameters encodePrivateKey(byte[] value) {
BigInteger d = new BigInteger(1, value);
return new ECPrivateKeyParameters(d, getECDomainParameters());
}
private static byte[] encodeDERSignature(byte[] signature) {
byte[] r = new byte[32];
byte[] s = new byte[32];
System.arraycopy(signature, 0, r, 0, 32);
System.arraycopy(signature, 32, s, 0, 32);
ASN1EncodableVector vector = new ASN1EncodableVector();
vector.add(new ASN1Integer(new BigInteger(1, r)));
vector.add(new ASN1Integer(new BigInteger(1, s)));
try {
return (new DERSequence(vector)).getEncoded();
} catch (IOException var6) {
throw new BusinessException("签名数据不正确", "TYSM224");
}
}
private static ECPublicKeyParameters encodePublicKey(byte[] value) {
byte[] x = new byte[32];
byte[] y = new byte[32];
System.arraycopy(value, 1, x, 0, 32);
System.arraycopy(value, 33, y, 0, 32);
BigInteger iX = new BigInteger(1, x);
BigInteger iY = new BigInteger(1, y);
ECPoint ecQ = getSM2Curve().createPoint(iX, iY);
return new ECPublicKeyParameters(ecQ, getECDomainParameters());
}
private static ECCurve getSM2Curve() {
ECParameterSpec spec = ECNamedCurveTable.getParameterSpec("sm2p256v1");
return spec.getCurve();
}
private static ECDomainParameters getECDomainParameters() {
ECParameterSpec spec = ECNamedCurveTable.getParameterSpec("sm2p256v1");
return new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN(), spec.getH(), spec.getSeed());
}
/**
* 通过SM3摘要器获取数据摘要
*
* @return 摘要
*/
private static byte[] CMBSM3Digest(byte[] msg) {
byte[] bytes = new byte[32];
SM3Digest digest = new SM3Digest();
digest.update(msg, 0, msg.length);
digest.doFinal(bytes, 0);
digest.reset();
return bytes;
}
private static void initKeyBase64() {
// 创建 sm2 对象
SM2 sm2 = SmUtil.sm2();
// 这里会自动生成对应的随机秘钥对 , 注意! 这里一定要强转,才能得到对应有效的秘钥信息
byte[] privateKey = BCUtil.encodeECPrivateKey(sm2.getPrivateKey());
// 这里公钥不压缩 公钥的第一个字节用于表示是否压缩 可以不要
byte[] publicKey = ((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false);
// 打印当前的公私秘钥
System.out.println("SM2 公钥(HEX): " + HexUtil.encodeHexStr(publicKey));
System.out.println("SM2 公钥长度(HEX): " + HexUtil.encodeHexStr(publicKey).length());
System.out.println("SM2 公钥(BASE64): " + Base64.encodeBase64String(publicKey));
System.out.println("SM2 公钥长度(BASE64): " + Base64.encodeBase64String(publicKey).length());
System.out.println("SM2 私钥(HEX): " + HexUtil.encodeHexStr(privateKey));
System.out.println("SM2 私钥公钥长度(HEX): " + HexUtil.encodeHexStr(privateKey).length());
System.out.println("SM2 私钥(BASE64): " + Base64.encodeBase64String(privateKey));
System.out.println("SM2 私钥长度(BASE64): " + Base64.encodeBase64String(privateKey).length());
}
public static void main(String[] args) {
//initKeyBase64();
Map<String, String> map = new HashMap<>(3);
map.put("mobile", "18468242454");
map.put("skuCode", "sku2021001");
//TODO 后面替换为真实的核心企业ID
map.put("coreId", "sku2021001");
String data = JSON.toJSONString(map);
String publicSecret = "BMTxlXewbroQEvkgEg41bzUfYE5TVQiBpd4yrOeBQ9Ck3Kj0gHxvGaKnjc4ECwwJ7lIHYwNoCkh6JzxX/3sQ36A=";
System.out.println("公钥字符长度:" + publicSecret.length());
String privateSecret = "NgQBMpptzmgbnl2/yp1xBz7iafpBsyFEpz5kqhdpLSk=";
System.out.println("私钥字符长度:" + privateSecret.length());
System.out.println("加密前的字符:" + data);
//用对方给的公钥加密,然后传给对方
//result:加密得到的数据
String result = cmbSM2Encrypt(publicSecret, data, "UTF-8");
System.out.println("加密得到的字符:" + result);
//dt:对方数据解密都得到的原文
String olData = cmbSM2Decrypt(privateSecret, result, "UTF-8");
System.out.println("解密后的字符:" + olData);
String signData = cmbSM2Sign(privateSecret, data, "Y", "UTF-8");
System.out.println("签名得到的字符:" + signData);
Boolean y = cmbSM2Verify(publicSecret, data, signData, "Y", "UTF-8");
System.out.println("签名验证结果:" + y);
}
}