SM2国密——前端加密,后端解密(备忘)

问题:前端提交请求时,用户名及密码到后台的过程明文传输,不安全,所以通过对账号和密码进行SM2加密后再进行提交,后台接收后再进行解密获取。

SM2加密知识:https://blog.csdn.net/mogoweb/article/details/105108689

SM2代码和文章借鉴源地址:    https://blog.51cto.com/boytnt/2503384

                                        https://github.com/Saberization/SM2

正文:

总的来说就是通过一定的算法获取到两个密钥,一个叫公钥,一个叫私钥。公钥留给前端进行进行加密,私钥留给后端进行解密。

首先先添加maven依赖:(最好使用1.60之后的版本,1.56版本测试缺少包)

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

然后公钥给前端之前,我们需要先生成公钥和私钥(不用问,借鉴来的(老脸一红)):

        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();

//上面的代码都是直接用maven依赖中的包直接import就可以用了
//还有一些更底层的写法,可以自己搜索一下,图方便的这个挺好的


        //私钥,16进制格式,自己保存
        BigInteger privatekey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
        String privateKeyHex = privatekey.toString(16);
        System.out.println("private Key :" + privateKeyHex);

        //公钥,16进制格式,发给前端
        ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
        String publicKeyHex = Hex.toHexString(ecPoint.getEncoded(false));
        System.out.println("Public Key :" + publicKeyHex);

这个时候,我们手持公钥和私钥,大手一挥,扔给前端一个公钥。

前端说,你等等,我先准备一下:

然后就添加了这两个js

<script type="text/javascript" src="自己的地址/crypto-js.js"></script>
<script type="text/javascript" src="自己的地址/sm2.js"></script>

        var psd = $('#password').val();
        var publichex = '后端获取到的公钥写这块';
		var password = sm2Encrypt(psd,publichex,0);

前端通sm2Encrypt加密完成后,现在的password就是一大串字符 。

然后这时候给后端,提交过程中就算你获取到了你也解不开,因为你没有私钥~~~

后端呢,获取到了一大串字符的password之后,就开始进行解密(还是借鉴来的代码(稍作更改)):

        String cipherData = "从前端获取的加密后的字符串";
		byte[] cipherDataByte = Hex.decode(cipherData);

		//刚才的私钥Hex,先还原私钥
		String privateKey = "先前获取的私钥写在这里";
		BigInteger privateKeyD = new BigInteger(privateKey, 16);
		X9ECParameters sm2ECParameters1 = GMNamedCurves.getByName("sm2p256v1");
		ECDomainParameters domainParameters1 = new ECDomainParameters(sm2ECParameters1.getCurve(), sm2ECParameters1.getG(), sm2ECParameters1.getN());
		ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters1);

		//用私钥解密
		SM2Engine sm2Engine = new SM2Engine();
		sm2Engine.init(false, privateKeyParameters);

		//processBlock得到Base64格式,记得解码
		byte[] arrayOfBytes =Base64.decodeBase64(sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length));

		//得到明文:SM2 Encryption Test
		String data = new String(arrayOfBytes);

这个时候就获得了前端界面提交上来的密码,并且传输过程中现实的是一串16进制的字符串,解决了明文传输,实现了加密传输的问题。

猜你喜欢

转载自blog.csdn.net/python_small_pan/article/details/120064529