1. 程式人生 > 其它 >SM2加解密

SM2加解密

SM2演算法(國密演算法)

國密即國家密碼局認定的國產密碼演算法。主要有SM1,SM2,SM3,SM4。金鑰長度和分組長度均為128位
一、SM1 為對稱加密。其加密強度與AES相當。該演算法不公開,呼叫該演算法時,需要通過加密晶片的介面進行呼叫。
二、SM2為非對稱加密,基於ECC。該演算法已公開。由於該演算法基於ECC,故其簽名速度與祕鑰生成速度都快於RSA。ECC 256位(SM2採用的就是ECC 256位的一種)安全強度比RSA 2048位高,但運算速度快於RSA。
三、SM3 訊息摘要。可以用MD5作為對比理解。該演算法已公開。校驗結果為256位。
四、SM4 無線區域網標準的分組資料演算法。對稱加密,金鑰長度和分組長度均為128位。

 

import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey; import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec; import org.bouncycastle.util.encoders.Hex; import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.security.*; import java.security.spec.ECGenParameterSpec; public class SM2Demo { private static String mStr="zym55mmyz"; public static void main(String[] args) { try { final ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1"); // 獲取一個橢圓曲線型別的金鑰對生成器 final KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider()); // 使用SM2引數初始化生成器 kpg.initialize(sm2Spec); // 獲取金鑰對 KeyPair keyPair = kpg.generateKeyPair(); PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); String data = encrypt(publicKey,mStr); System.out.println("SM2加密:" + data); String text = decrypt(privateKey, data); System.out.println("SM2解密:" + text); byte[] privateKeyEncoded = privateKey.getEncoded(); /*// 進行Base64編碼 String privateKeyString = Base64.getEncoder().encodeToString(privateKeyEncoded); //Base64.encode(privateKeyEncoded);*/ String privateKeyStr = ""; if (privateKey instanceof BCECPrivateKey){ privateKeyStr = ((BCECPrivateKey)privateKey).getD().toString(16); } String ret = sm2Decrypt(privateKeyStr, data); System.out.println("SM2解密2:" + ret); } catch (Exception e) { e.printStackTrace(); } } /** * SM2加密演算法 * @param publicKey 公鑰 * @param data 明文資料 * @return **/ public static String encrypt(PublicKey publicKey, String data) { ECPublicKeyParameters ecPublicKeyParameters = null; if (publicKey instanceof BCECPublicKey) { BCECPublicKey bcecPublicKey = (BCECPublicKey) publicKey; ECParameterSpec ecParameterSpec = bcecPublicKey.getParameters(); ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN()); ecPublicKeyParameters = new ECPublicKeyParameters(bcecPublicKey.getQ(),ecDomainParameters); } SM2Engine sm2Engine = new SM2Engine(); sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom())); byte[] arrayOfBytes = null; try { byte[] in = data.getBytes(StandardCharsets.UTF_8); arrayOfBytes = sm2Engine.processBlock(in,0, in.length); } catch (Exception e) { System.out.println("SM2加密時出現異常:"); } return Hex.toHexString(arrayOfBytes); } /** * SM2解密演算法 * @param privateKey 私鑰 * @param cipherData 密文資料 * @return **/ public static String decrypt(PrivateKey privateKey, String cipherData) { byte[] cipherDataByte = Hex.decode(cipherData); BCECPrivateKey bcecPrivateKey = (BCECPrivateKey) privateKey; ECParameterSpec ecParameterSpec = bcecPrivateKey.getParameters(); ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN()); ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(bcecPrivateKey.getD(), ecDomainParameters); SM2Engine sm2Engine = new SM2Engine(); sm2Engine.init(false, ecPrivateKeyParameters); String result = null; try { byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length); return new String(arrayOfBytes, StandardCharsets.UTF_8); } catch (Exception e) { System.out.println("SM2解密時出現異常"); } return result; } /** * SM2解密演算法 * @param key 私鑰 * @param cipherData 密文資料 * @return */ public static String sm2Decrypt(String key, String cipherData){ String result = null; try { // 加密演算法 String algorithm = "EC"; //私鑰Hex,還原私鑰 BigInteger privateKeyD = new BigInteger(key, 16); //使用標準名稱建立EC引數生成的引數規範 X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1"); //獲取私鑰的基本域引數 ECParameterSpec ecParameterSpec = new ECParameterSpec(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN()); ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(privateKeyD,ecParameterSpec); //獲取私鑰物件 BCECPrivateKey bcecPrivateKey = new BCECPrivateKey(algorithm,ecPrivateKeySpec, BouncyCastleProvider.CONFIGURATION); byte[] cipherDataByte = Hex.decode(cipherData); ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN()); //通過私鑰值和私鑰基本引數建立私鑰引數物件 ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(bcecPrivateKey.getD(), ecDomainParameters); //通過解密模式建立解密引擎並初始化 SM2Engine sm2Engine = new SM2Engine(); sm2Engine.init(false, ecPrivateKeyParameters); try { byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length); return new String(arrayOfBytes, StandardCharsets.UTF_8); } catch (Exception e) { } } catch (Exception e) { } return result; } }