Java 算法SM2加密解密

2022-09-06 12:55:35

简介

什么是SM2

SM2是国家密码管理局于2010年12月17日发布的椭圆曲线公钥密码算法。

SM2 算法和RSA 算法都是公钥密码算法,SM2 算法是一种更先进安全的算法,在我们国家商用密码体系中被用来替换RSA 算法。

随着密码技术和计算机技术的发展,目前常用的1024RSA 算法面临严重的安全威胁,我们国家密码管理部门经过研究,决定采用SM2 椭圆曲线算法替换RSA算法。

SM2算法和RSA算法比较

SM2性能更优更安全:密码复杂度高、处理速度快、机器性能消耗更小

-SM2RSA
算法结构基本椭圆曲线(ECC)基于特殊的可逆模幂运算
计算复杂度完全指数级亚指数级
存储空间192-256bit2048-4096bit
秘钥生成速度较RSA算法快百倍以上
解密加密速度较快一般

POM依赖

<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-ext-jdk15to18</artifactId><version>1.68</version></dependency><dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15to18</artifactId><version>1.68</version></dependency>

Java工具类

packagecom.file.system.tools.sm2;importorg.bouncycastle.asn1.gm.GMNamedCurves;importorg.bouncycastle.asn1.x9.X9ECParameters;importorg.bouncycastle.crypto.engines.SM2Engine;importorg.bouncycastle.crypto.params.ECDomainParameters;importorg.bouncycastle.crypto.params.ECPrivateKeyParameters;importorg.bouncycastle.crypto.params.ECPublicKeyParameters;importorg.bouncycastle.crypto.params.ParametersWithRandom;importorg.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;importorg.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;importorg.bouncycastle.jce.provider.BouncyCastleProvider;importorg.bouncycastle.jce.spec.ECParameterSpec;importorg.bouncycastle.jce.spec.ECPrivateKeySpec;importorg.bouncycastle.jce.spec.ECPublicKeySpec;importorg.bouncycastle.util.encoders.Hex;importjava.math.BigInteger;importjava.security.*;importjava.security.spec.ECGenParameterSpec;/**
 * @ClassName SM2Utils
 * @Description SM2算法工具类
 * @Author msx
 * @Date 2021/9/24 16:50
 * @Version 1.0
 */publicclassSM2Utils{/**
     * @Description 生成秘钥对
     * @Author msx
     * @return KeyPair
     */publicstaticKeyPaircreateECKeyPair(){//使用标准名称创建EC参数生成的参数规范finalECGenParameterSpec sm2Spec=newECGenParameterSpec("sm2p256v1");// 获取一个椭圆曲线类型的密钥对生成器finalKeyPairGenerator kpg;try{
            kpg=KeyPairGenerator.getInstance("EC",newBouncyCastleProvider());// 使用SM2算法域参数集初始化密钥生成器(默认使用以最高优先级安装的提供者的 SecureRandom 的实现作为随机源)// kpg.initialize(sm2Spec);// 使用SM2的算法域参数集和指定的随机源初始化密钥生成器
            kpg.initialize(sm2Spec,newSecureRandom());// 通过密钥生成器生成密钥对return kpg.generateKeyPair();}catch(Exception e){
            e.printStackTrace();returnnull;}}/**
     * @Description 公钥加密
     * @Author msx
     * @param publicKeyHex SM2十六进制公钥
     * @param data         明文数据
     * @return String
     */publicstaticStringencrypt(String publicKeyHex,String data){returnencrypt(getECPublicKeyByPublicKeyHex(publicKeyHex), data,1);}/**
     * @Description 公钥加密
     * @Author msx
     * @param publicKey SM2公钥
     * @param data      明文数据
     * @param modeType  加密模式
     * @return String
     */publicstaticStringencrypt(BCECPublicKey publicKey,String data,int modeType){//加密模式SM2Engine.Mode mode=SM2Engine.Mode.C1C3C2;if(modeType!=1){
            mode=SM2Engine.Mode.C1C2C3;}//通过公钥对象获取公钥的基本域参数。ECParameterSpec ecParameterSpec= publicKey.getParameters();ECDomainParameters ecDomainParameters=newECDomainParameters(ecParameterSpec.getCurve(),
                ecParameterSpec.getG(), ecParameterSpec.getN());//通过公钥值和公钥基本参数创建公钥参数对象ECPublicKeyParameters ecPublicKeyParameters=newECPublicKeyParameters(publicKey.getQ(), ecDomainParameters);//根据加密模式实例化SM2公钥加密引擎SM2Engine sm2Engine=newSM2Engine(mode);//初始化加密引擎
        sm2Engine.init(true,newParametersWithRandom(ecPublicKeyParameters,newSecureRandom()));byte[] arrayOfBytes=null;try{//将明文字符串转换为指定编码的字节串byte[] in= data.getBytes("utf-8");//通过加密引擎对字节数串行加密
            arrayOfBytes= sm2Engine.processBlock(in,0, in.length);}catch(Exception e){System.out.println("SM2加密时出现异常:"+ e.getMessage());
            e.printStackTrace();}//将加密后的字节串转换为十六进制字符串returnHex.toHexString(arrayOfBytes);}/**
     * @Description 私钥解密
     * @Author msx
     * @param privateKeyHex SM2十六进制私钥
     * @param cipherData    密文数据
     * @return String
     */publicstaticStringdecrypt(String privateKeyHex,String cipherData){returndecrypt(getBCECPrivateKeyByPrivateKeyHex(privateKeyHex), cipherData,1);}/**
     * @Description 私钥解密
     * @Author msx
     * @param privateKey SM私钥
     * @param cipherData 密文数据
     * @param modeType   解密模式
     * @return
     */publicstaticStringdecrypt(BCECPrivateKey privateKey,String cipherData,int modeType){//解密模式SM2Engine.Mode mode=SM2Engine.Mode.C1C3C2;if(modeType!=1)
            mode=SM2Engine.Mode.C1C2C3;//将十六进制字符串密文转换为字节数组(需要与加密一致,加密是:加密后的字节数组转换为了十六进制字符串)byte[] cipherDataByte=Hex.decode(cipherData);//通过私钥对象获取私钥的基本域参数。ECParameterSpec ecParameterSpec= privateKey.getParameters();ECDomainParameters ecDomainParameters=newECDomainParameters(ecParameterSpec.getCurve(),
                ecParameterSpec.getG(), ecParameterSpec.getN());//通过私钥值和私钥钥基本参数创建私钥参数对象ECPrivateKeyParameters ecPrivateKeyParameters=newECPrivateKeyParameters(privateKey.getD(),
                ecDomainParameters);//通过解密模式创建解密引擎并初始化SM2Engine sm2Engine=newSM2Engine(mode);
        sm2Engine.init(false, ecPrivateKeyParameters);String result=null;try{//通过解密引擎对密文字节串进行解密byte[] arrayOfBytes= sm2Engine.processBlock(cipherDataByte,0, cipherDataByte.length);//将解密后的字节串转换为utf8字符编码的字符串(需要与明文加密时字符串转换成字节串所指定的字符编码保持一致)
            result=newString(arrayOfBytes,"utf-8");}catch(Exception e){System.out.println("SM2解密时出现异常"+ e.getMessage());}return result;}//椭圆曲线ECParameters ASN.1 结构privatestaticX9ECParameters x9ECParameters=GMNamedCurves.getByName("sm2p256v1");//椭圆曲线公钥或私钥的基本域参数。privatestaticECParameterSpec ecDomainParameters=newECParameterSpec(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN());/**
     * @Description 公钥字符串转换为 BCECPublicKey 公钥对象
     * @Author msx
     * @param pubKeyHex 64字节十六进制公钥字符串(如果公钥字符串为65字节首个字节为0x04:表示该公钥为非压缩格式,操作时需要删除)
     * @return BCECPublicKey SM2公钥对象
     */publicstaticBCECPublicKeygetECPublicKeyByPublicKeyHex(String pubKeyHex){//截取64字节有效的SM2公钥(如果公钥首个字节为0x04)if(pubKeyHex.length()>128){
            pubKeyHex= pubKeyHex.substring(pubKeyHex.length()-128);}//将公钥拆分为x,y分量(各32字节)String stringX= pubKeyHex.substring(0,64);String stringY= pubKeyHex.substring(stringX.length());//将公钥x、y分量转换为BigInteger类型BigInteger x=newBigInteger(stringX,16);BigInteger y=newBigInteger(stringY,16);//通过公钥x、y分量创建椭圆曲线公钥规范ECPublicKeySpec ecPublicKeySpec=newECPublicKeySpec(x9ECParameters.getCurve().createPoint(x, y), ecDomainParameters);//通过椭圆曲线公钥规范,创建出椭圆曲线公钥对象(可用于SM2加密及验签)returnnewBCECPublicKey("EC", ecPublicKeySpec,BouncyCastleProvider.CONFIGURATION);}/**
     * @Description 私钥字符串转换为 BCECPrivateKey 私钥对象
     * @Author msx
     * @param privateKeyHex 32字节十六进制私钥字符串
     * @return BCECPrivateKey SM2私钥对象
     */publicstaticBCECPrivateKeygetBCECPrivateKeyByPrivateKeyHex(String privateKeyHex){//将十六进制私钥字符串转换为BigInteger对象BigInteger d=newBigInteger(privateKeyHex,16);//通过私钥和私钥域参数集创建椭圆曲线私钥规范ECPrivateKeySpec ecPrivateKeySpec=newECPrivateKeySpec(d, ecDomainParameters);//通过椭圆曲线私钥规范,创建出椭圆曲线私钥对象(可用于SM2解密和签名)returnnewBCECPrivateKey("EC", ecPrivateKeySpec,BouncyCastleProvider.CONFIGURATION);}publicstaticvoidmain(String[] args){String publicKeyHex=null;String privateKeyHex=null;KeyPair keyPair=createECKeyPair();PublicKey publicKey= keyPair.getPublic();if(publicKeyinstanceofBCECPublicKey){//获取65字节非压缩缩的十六进制公钥串(0x04)
            publicKeyHex=Hex.toHexString(((BCECPublicKey) publicKey).getQ().getEncoded(false));System.out.println("---->SM2公钥:"+ publicKeyHex);}PrivateKey privateKey= keyPair.getPrivate();if(privateKeyinstanceofBCECPrivateKey){//获取32字节十六进制私钥串
            privateKeyHex=((BCECPrivateKey) privateKey).getD().toString(16);System.out.println("---->SM2私钥:"+ privateKeyHex);}/**
         * 公钥加密
         */String data="=========待加密数据=========";//将十六进制公钥串转换为 BCECPublicKey 公钥对象String encryptData=encrypt(publicKeyHex, data);System.out.println("---->加密结果:"+ encryptData);/**
         * 私钥解密
         *///将十六进制私钥串转换为 BCECPrivateKey 私钥对象
        data=decrypt(privateKeyHex, encryptData);System.out.println("---->解密结果:"+ data);}}
扩展资料

国密即国家密码局认定的国产密码算法。主要有SM1,SM2,SM3,SM4。密钥长度和分组长度均为128位。
(1)SM1 为对称加密。其加密强度与AES相当。该算法不公开,调用该算法时,需要通过加密芯片的接口进行调用。
(2)SM2为非对称加密,基于ECC。该算法已公开。由于该算法基于ECC,故其签名速度与秘钥生成速度都快于RSA。ECC 256位(SM2采用的就是ECC 256位的一种)安全强度比RSA 2048位高,但运算速度快于RSA。
(3)SM3 消息摘要。可以用MD5作为对比理解。该算法已公开。校验结果为256位。
(4)SM4 无线局域网标准的分组数据算法。对称加密,密钥长度和分组长度均为128位。

这里有一篇关于SM1、SM2 、SM3、 SM4算法详解

  • 作者:码上仙
  • 原文链接:https://blog.csdn.net/qq_36949163/article/details/120511612
    更新时间:2022-09-06 12:55:35