zoukankan      html  css  js  c++  java
  • JS实现国密算法SM2加密,后端Java解密

    项目涉及保密传输,要求使用国密算法,一般遇到类似问题首先想到的就是使用非对称加密,后端生成密钥对,将公钥交给前端,前端用公钥加密数据,后端用私钥对数据解密。项目的复杂度在于国密的非对称加密算法SM2的Java及JS实现。

    Java版比较好办,较新版本的bouncycastle就支持了SM2/SM3/SM4,麻烦在于JS版,找了很多都有问题,直到遇到了这个项目:https://github.com/Saberization/SM2,感谢作者。分别整理下前端后端的实现过程:

    后端首先引入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);
    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);
    

      

  • 相关阅读:
    ActionScript简单实现Socket Tcp应用协议分析器
    您还有心跳吗?超时机制分析
    Java线程池架构2-多线程调度器
    Java 连接池的工作原理
    Integrating JDBC with Hibernate
    Codeforce 1255 Round #601 (Div. 2) C. League of Leesins (大模拟)
    Codeforce 1255 Round #601 (Div. 2)B. Fridge Lockers(思维)
    Codeforce 1255 Round #601 (Div. 2) A. Changing Volume (贪心)
    图论--拓扑排序--判断是否为DAG图
    图论--拓扑排序--判断一个图能否被拓扑排序
  • 原文地址:https://www.cnblogs.com/BoyTNT/p/13086321.html
Copyright © 2011-2022 走看看