JS实现国密算法SM2加密,后端Java解密

Posted Java烟雨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS实现国密算法SM2加密,后端Java解密相关的知识,希望对你有一定的参考价值。

后端的实现过程:

后端首先引入bouncycastle,Maven配置如下:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.65</version>
</dependency>

后端Java代码如下:

//生成密钥对
X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG")));
AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();
 
//私钥,16进制格式,自己保存,格式如a2081b5b81fbea0b6b973a3ab6dbbbc65b1164488bf22d8ae2ff0b8260f64853
BigInteger privatekey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
String privateKeyHex = privatekey.toString(16);
 
//公钥,16进制格式,发给前端,格式如04813d4d97ad31bd9d18d785f337f683233099d5abed09cb397152d50ac28cc0ba43711960e811d90453db5f5a9518d660858a8d0c57e359a8bf83427760ebcbba
ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
String publicKeyHex = Hex.toHexString(ecPoint.getEncoded(false));

前端javascript示例代码,写了个页面:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>SM2-TEST</title>
    <script src="crypto-js.js"></script>
    <script src="sm2.js"></script>
    <script>
    function encrypt() 
        //公钥,16进制格式,由后端生成
        var pubkeyHex = "04813d4d97ad31bd9d18d785f337f683233099d5abed09cb397152d50ac28cc0ba43711960e811d90453db5f5a9518d660858a8d0c57e359a8bf83427760ebcbba";
        var encryptData = sm2Encrypt("SM2 Encryption Test", pubkeyHex, 0);
        console.log(encryptData);
    
    </script>
</head>
<body onload="encrypt()">
</body>
</html>
 

执行会生成密文,每次生成都会不同,比如我的环境某次生成如下:

04be17bf6fe47da1f34a01ad0ff67901241b72d103e998f2f7cc78a004703bdfb8d2c6e3939f4f708f3a57d872d58ec5c41bbe5976666bcb01acea43f5a1c68a62cc117c24821d17c3023035641894d7c978a5521f8dc6798515550c73071f9703602e0ee490157729b648c1cc3eb929c1a0501e12a216d42461117402

后端尝试解密:

/JS加密产生的密文
String cipherData = "04be17bf6fe47da1f34a01ad0ff67901241b72d103e998f2f7cc78a004703bdfb8d2c6e3939f4f708f3a57d872d58ec5c41bbe5976666bcb01acea43f5a1c68a62cc117c24821d17c3023035641894d7c978a5521f8dc6798515550c73071f9703602e0ee490157729b648c1cc3eb929c1a0501e12a216d42461117402";
byte[] cipherDataByte = Hex.decode(cipherData);
 
//刚才的私钥Hex,先还原私钥
String privateKey = "a2081b5b81fbea0b6b973a3ab6dbbbc65b1164488bf22d8ae2ff0b8260f64853";
BigInteger privateKeyD = new BigInteger(privateKey, 16);
X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
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 data = new String(arrayOfBytes);


小伙伴们有兴趣想了解内容和更多相关学习资料的请点赞收藏+评论转发+关注我,后面会有很多干货。如果在阅读过程中有疑问,请留言讨论

此份文档详细记录了千道面试题与详解; 
! 
   私信我回复【03】即可免费获取


很多人感叹“学习无用”,实际上之所以产生无用论,
   是因为自己想要的与自己所学的匹配不上,这也就意味着自己学得远远不够。无论是学习还是工作,
    都应该有主动性,所以如果拥有大厂梦,那么就要自己努力去实现它。

以上学习资料均免费放送,最后祝愿各位顺利拿到心仪的offer

作者: 

BoyTNT 

原文出处:JS实现国密算法SM2加密,后端Java解密 - BoyTNT - 博客园

国密SM2的前端加密,后端解密(Java版本)及SM3 摘要加密

一、简介

国密即国家密码局认定的国产密码算法。常用的主要有SM2,SM3,SM4。

SM2:椭圆曲线公钥密码算法是我国自主设计的公钥密码算法,为非对称加密,基于ECC。该算法已公开。由于该算法基于ECC,故其签名速度与秘钥生成速度都快于RSA。

SM3:消息摘要。可以用MD5作为对比理解。该算法已公开。校验结果为256位。

SM4:对称加密,密钥长度和分组长度均为128位。

由于国际环境(与美国的关系),我们在加密领域也基本切换为国密算法。

在有些项目中,没有使用HTTPS的时候,登录的口令(用户名/密码),需要进行加密传输的需求,这时候我们就需要采用非对称加密来实现。

故: 前端采用公钥加密, 后端私钥解密。

经过多次的百度及代码验证,折腾,最终找好了合适的方案。

前端加密

前端加密js示例:

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="X-UA-Compatible" content="chrome=1" />
    <meta name="description" content="JavaScript implementation of SM2 Algorithm Encryption and Decryption sample." />

    <!--<link rel="stylesheet" type="text/css" media="screen" href="stylesheets/stylesheet.css">-->
    <title>SM2 Algorithm Encryption and Decryption sample</title>
    <style>
        textarea {
            width: 100%;
        }
    </style>
    <!-- for pkcs5pkey -->
    <script src="sm2.js"></script>
    <script language="JavaScript" type="text/javascript">
       /**
        *  生成秘钥对
        */
        function doGenerate() {
            var ec = new KJUR.crypto.ECDSA({
                "curve": 'sm2'
            });
            var keypair = ec.generateKeyPairHex();
            // 私钥:keypair.ecprvhex;
            // 公钥:keypair.ecpubhex;
            console.log(keypair)
        }

        function test(){

           /**
             * [SM2Encrypt description  加密数据]
             * @param {[type]} data       [待加密数据]
             * @param {[type]} publickey  [公钥 hex]
             * @param {[type]} cipherMode [加密模式 C1C3C2:1, C1C2C3:0]
             * @return {[type]}           [返回加密后的数据 hex]
             */
           var cipherText = sm2Encrypt("我是妞见妞爱===", "04b96fb7504d7a0509745b80ae8079d5250119899e8620fe322ff47d3a3cbf7d17330ff6c8019b8c0cb06b4a881aef40240354dded8eef4b9c557c817cd7b3788d", 1);
           console.log("cipherText:",cipherText)

           /**
             * [SM2Decrypt sm2 解密数据]
             * @param {[type]} encrypted  [待解密数据 hex]
             * @param {[type]} privateKey [私钥 hex]
             * @param {[type]} cipherMode [加密模式 C1C3C2:1, C1C2C3:0]
             * @return {[type]}           [返回解密后的数据]
             */
           var plainText = sm2Decrypt(cipherText,"0a7e399f15e1ca85a4112635589fedce85eb62298d7154788c24c3485a598138", 1)
           console.log("plainText:",plainText)

        }
    </script>
</head>

<body>

<!-- MAIN CONTENT -->
<div id="main_content_wrap" class="outer">
    <section class="inner">
        <hr size="1" />
        <h4>SM2 Certificate Encryption</h4>
        <fieldset>
            <legend>SM2证书加密</legend>
            <ul>
                <li>
                    <input type="button" value="测试,看控制台" onClick="doGenerate();" />
                </li>

                <li>
                    <input type="button" value="加密、解密" onClick="test();" />
                </li>

            </ul>
            <div>
            </div>
        </fieldset>
    </section>
</div>
</body>

</html>

后端加密

下面是我封装的工具类:

package com.topinfo.basic.platform.common.sm;

import com.topinfo.basic.platform.common.sm.sm2.KeyVo;
import com.topinfo.basic.platform.common.sm.sm2.SM2EncDecUtils;
import com.topinfo.basic.platform.common.sm.sm2.SM2KeyVO;

/**
 * @ClassName: Sm2Util
 * @Description: Sm2 加密工具类
 * @Author: 杨攀
 * @Date: 2020/12/10 16:47
 * @Copyright: 2020 www.tuxun.net Inc. All rights reserved.
 */
public class TpSm2Util {



    /**
     * 生成非对称秘钥对
     * @author 杨攀
     * @date 2020/12/11 10:50
     * @param
     * @return com.topinfo.basic.platform.common.sm.sm2.KeyVo
     */
    public static KeyVo generateKeyPair() {
        SM2KeyVO sm2KeyVO = SM2EncDecUtils.generateKeyPair();
        KeyVo vo = new KeyVo(sm2KeyVO.getPubHexInSoft(), sm2KeyVO.getPriHexInSoft());
        return vo;
    }


    /**
     * 加密
     * @author 杨攀
     * @date 2020/12/11 10:54
     * @param publicKeyHex 公钥
     * @param plainText 明文
     * @return java.lang.String
     */
    public static String  encrypt(String publicKeyHex, String plainText) {
        String cipherText = SM2EncDecUtils.encrypt(publicKeyHex, plainText);
        return cipherText;
    }


    /**
     * 解密
     * @author 杨攀
     * @date 2020/12/11 10:56
     * @param privateKeyHex 私钥
     * @param cipherText 密文
     * @return java.lang.String
     */
    public static String  decrypt(String privateKeyHex, String cipherText) {
        byte[] decryptData = SM2EncDecUtils.decrypt(privateKeyHex, cipherText);
        String  plainText = new String(decryptData);
        return plainText;
    }

}

一开始,后端使用hutool的工具类, 发现hutool的key生成与前端JS的不同,使用的算法不一样,使用不得已在重现找了一个。

使用前需要依赖:

<!-- 国密算法bcprov-jdk15to18 hutool -->
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15to18</artifactId>
    <version>1.66</version>
</dependency>

最后

最近我整理了整套《JAVA核心知识点总结》,说实话 ,作为一名Java程序员,不论你需不需要面试都应该好好看下这份资料。拿到手总是不亏的~我的不少粉丝也因此拿到腾讯字节快手等公司的Offer

Java进阶群

好了,以上就是本文的全部内容了,如果觉得有收获,记得三连,我们下期再见。

以上是关于JS实现国密算法SM2加密,后端Java解密的主要内容,如果未能解决你的问题,请参考以下文章

国密SM2前端VUE,后端Hutool工具的搭配

国密算法 SM2 SM3 SM4分别用作什么

openssl 加解密以及国密算法

Java-国密算法SM2实现(bouncycastle)

Java-国密算法SM2实现(bouncycastle)

国密gmssl介绍(SM2SM3SM4算法)