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; } }