Java端工具類:
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.SM2Engine;
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.ECPoint;
import org.bouncycastle.util.encoders.Hex;
/**
*
* @類名稱 Sm2Utils.java
* @類描述 <pre>國密sm2工具類-适用于 js+java後端互動使用</pre>
* @作者 yw [email protected]
* @建立時間 2021年4月13日 下午1:52:56
* @版本 5.0.0
*
* @修改記錄
* <pre>
* 版本 修改人 修改日期 修改内容描述
* ----------------------------------------------
* 5.0.0 yw 2021年4月13日
* ----------------------------------------------
* </pre>
*/
public class Sm2Utils {
//流程 通過背景代碼生産公私鑰對,公鑰提供給js端用于資料加密,私鑰用于js端傳來的密文串解密
private static ECDomainParameters domainParameters = null;
private static final String privateKey = "80cfeb110007a9a11295b9289c4b889063f35fe66e54d53fdbb5b8aa335d665a";//生成的私鑰 用來解密
/**
* 擷取橢圓曲線
*/
static {
//生成密鑰對
X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
}
public static void main(String args[]) {
String text = "04be17bf6fe47da1f34a01ad0ff67901241b72d103e998f2f7cc78a004703bdfb8d2c6e3939f4f708f3a57d872d58ec5c41bbe5976666bcb01acea43f5a1c68a62cc117c24821d17c3023035641894d7c978a5521f8dc6798515550c73071f9703602e0ee490157729b648c1cc3eb929c1a0501e12a216d42461117402";
verification(text);
}
/**
*
* @方法名稱 genPUPRkey
* @功能描述 <pre>生成公私鑰對 公鑰給别人拿去加密傳輸資料,私鑰留個自己用來解密</pre>
* @作者 yw
* @建立時間 2021年4月13日 下午1:57:07
* @throws NoSuchAlgorithmException
*/
public static void genPUPRkey() throws NoSuchAlgorithmException {
//生成密鑰對
ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG")));
AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();
//私鑰,16進制格式,自己儲存,格式如80cfeb110007a9a11295b9289c4b889063f35fe66e54d53fdbb5b8aa335d665a
BigInteger privatekey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
String privateKeyHex = privatekey.toString(16);
System.out.println("私鑰:" + privateKeyHex);
//公鑰,16進制格式,發給前端,格式如0467e8c00b1fc2049aa006e75a7216eaf1fb42347b664ea63897917f1281427fa22254d39a3f5fd38e6773edc5eddc074dae27bfbe82d13094bfcbe6b344e89ee9
ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
String publicKeyHex = Hex.toHexString(ecPoint.getEncoded(false));
System.out.println("公鑰:" + publicKeyHex);
}
/**
* 解密
* @方法名稱 decrypt
* @功能描述 <pre></pre>
* @作者 yw
* @建立時間 2021年4月13日 下午2:09:59
* @param ciphertext
* @param privatekey
* @throws InvalidCipherTextException
*/
public static String decrypt(String ciphertext, String privatekey) throws InvalidCipherTextException {
String cipherData = ciphertext;//JS加密産生的密文
byte[] cipherDataByte = Hex.decode(cipherData);//格式轉換
BigInteger privateKeyD = new BigInteger(privatekey, 16);//私鑰Hex,還原私鑰
ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);
//用私鑰解密
SM2Engine sm2Engine = new SM2Engine();
sm2Engine.init(false, privateKeyParameters);
//processBlock得到Base64格式,記得解碼
byte[] arrayOfBytes = Base64.getDecoder().decode(sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length));
//得到明文:SM2 Encryption Test
String mtext = new String(arrayOfBytes);
System.out.println(mtext);
return mtext;
}
/**
*
* @方法名稱 verification
* @功能描述 <pre>js的密文校驗</pre>
* @作者 yw
* @建立時間 2021年4月13日 下午2:13:07
* @param ciphertext
* @return
*/
public static String verification(String ciphertext) {
String mtext = "";//明文
try {
mtext = decrypt(ciphertext, privateKey);
System.out.println("mtext:" + mtext);
} catch (InvalidCipherTextException e) {
e.printStackTrace();
}
return mtext ;
}
}
前端js部分,請參考項目(感謝大佬):
https://github.com/Saberization/SM2