需要的jar包
bcprov-jdk15on-1.59.jar
commons-lang3-3.1.jar
代碼
package com.ggp.sqy42d;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import java.security.*;
/**
* @author: ggp
* @Date: 2019/3/18 18:45
* @Description:
*/
public class SM2Util {
public static Signature signature;
public static KeyPair keyPair;
public static KeyPair getKeyPair() {
return keyPair;
}
public static void setKeyPair(KeyPair keyPair) {
SM2Util.keyPair = keyPair;
}
public static void createKeyPair(){
// 獲取SM2 橢圓曲線推薦參數
X9ECParameters ecParameters = GMNamedCurves.getByName("sm2p256v1");
// 構造EC 算法參數
ECNamedCurveParameterSpec sm2Spec = new ECNamedCurveParameterSpec(
// 設置SM2 算法的 OID
GMObjectIdentifiers.sm2p256v1.toString()
// 設置曲線方程
, ecParameters.getCurve()
// 橢圓曲線G點
, ecParameters.getG()
// 大整數N
, ecParameters.getN());
try {
// 創建 密鑰對生成器
KeyPairGenerator gen = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
// 使用SM2的算法區域初始化密鑰生成器
gen.initialize(sm2Spec, new SecureRandom());
// 獲取密鑰對
SM2Util.keyPair = gen.generateKeyPair();
}catch (Exception e){
e.printStackTrace();
}
}
static {
try {
signature = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(),new BouncyCastleProvider());
System.out.println(GMObjectIdentifiers.sm2sign_with_sm3.toString());
createKeyPair();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
/**
* 簽名
* @param privateKey 簽名私鑰
* @param plainText 明文
* @return
*/
public static String encrypt(PrivateKey privateKey,String plainText){
try {
signature.initSign(privateKey);
signature.update(plainText.getBytes());
byte[] bytes = signature.sign();
return new String(bytes,0,bytes.length,"ISO-8859-1");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 驗證簽名
* @param publicKey 簽名公鑰
* @param signResult 簽名結果
* @param plainText 明文
* @return
*/
public static boolean verify(PublicKey publicKey,byte[] signResult,String plainText){
boolean result = false;
try {
signature.initVerify(publicKey);
signature.update(plainText.getBytes());
result = signature.verify(signResult);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
String ss = SM2Util.encrypt(keyPair.getPrivate(),"111");
try {
System.out.println(ss);
String ab = SM3Util.bytesToHexString(ss.getBytes("ISO-8859-1"));
byte[] c = SM3Util.hexStringToBytes(ab);
System.out.println(SM3Util.bytesToHexString(ss.getBytes("ISO-8859-1")));
System.out.println(SM2Util.verify(keyPair.getPublic(), new String(c,"ISO-8859-1").getBytes("ISO-8859-1"), "111"));
}catch (Exception e){
e.printStackTrace();
}
}
}
需要注意的問題
new String 和 String.getBytes()如果沒有指定字符集,默認使用的是utf-8,utf-8會用一個或多個字節去表示一個字符,所以得到的結果會不同,因爲沒有牽涉到漢子,所以我們用ISO-8859-1字符集即可,我會在另一篇博客去敘述這個問題