首页 > 其他分享 >SM2加密传输解决方案

SM2加密传输解决方案

时间:2022-09-22 20:12:18浏览次数:43  
标签:加密传输 hutool String 解决方案 sm2 SM2 org import crypto

后端

引入依赖


<dependency>
  <groupId>cn.hutool</groupId>
  <artifactId>hutool-all</artifactId>
  <version>5.8.5</version>
</dependency>

<dependency>
  <groupId>cn.hutool</groupId>
  <artifactId>hutool-all</artifactId>
  <version>5.8.5</version>
</dependency>

密钥对生成

import java.math.BigInteger;
import java.security.KeyPair;
import java.security.SecureRandom;

import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;

import cn.hutool.crypto.SecureUtil;

/**
 * 国密sm2密钥对生成工具
 *  
 * @author 吕晓飞
 * @date 2022-08-31 18:07
 * @version 1.0
 */
public class Sm2KeyGenUtil {

	/**
	 * sm2密钥生成
	 */
	private static KeyPair pair = SecureUtil.generateKeyPair("SM2");

	/**
	 * 生成SM2算法的密钥对
	 * 
	 * @return
	 */
	public static RSAKey genSM2Key() {
		try {
			X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");// SM2默认曲线 
			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进制格式,Q值发给前端
			ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
			String publicKeyHex = Hex.toHexString(ecPoint.getEncoded(false));
			System.out.println("Public Key :" + publicKeyHex);
			return new RSAKey(publicKeyHex, privateKeyHex);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 生成SM2算法的密钥对 - hutool生成的密钥对前端无法识别, 使用网上提供的代码生成
	 * 
	 * @return
	 */
	@Deprecated
	public static RSAKey genSM2Key_bak() {
		String publickey = Hex.toHexString(pair.getPublic().getEncoded());
		String privatekey = Hex.toHexString(pair.getPrivate().getEncoded());
		System.out.println("publickey-->" + publickey);
		System.out.println("privatekey-->" + privatekey);
		return new RSAKey(publickey, privatekey);
	}

}
package com.geoway.privilege.utils.crypto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 非对称算法密钥
 * 
 * @author 吕晓飞
 * @date 2022-08-31 17:32
 * @version 1.0
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RSAKey {

	/**
	 * 公钥16进制, 用来加密
	 */
	private String publicKey;

	/**
	 * 私钥16进制, 用来解密
	 */
	private String privateKey;

}

新建两个txt文件, 改名为public_key.pem和private_key.pem将生成的公钥和私钥粘贴到文件里保存
将这两个文件放到maven工程的src/main/resources/sm2/目录下

package com.geoway.privilege.utils.crypto;

import org.bouncycastle.crypto.engines.SM2Engine;

import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;

/**
 * 国密sm2算法<br>
 * 最初无法解密前端传递的数据 详见https://gitee.com/dromara/hutool/issues/I3AEPJ <br>
 * 需要前端加密的数据是否是04开头, 如果不是需要手动加上04<br>
 * 参考 https://blog.csdn.net/ww_1997/article/details/115379258
 * 
 * @author 吕晓飞
 * @date 2022-08-18 15:50
 * @version 1.0
 */
public class SM2Util {

	/**
	 * 公钥
	 */
	private static String puclicKey = null;

	/**
	 * 私钥
	 */
	private static String privateKey = null;

	/**
	 * 国密sm2算法
	 */
	private static SM2 sm2 = null;

	static {
		puclicKey = ResourceUtil.readUtf8Str("sm2/public_key.pem");
		privateKey = ResourceUtil.readUtf8Str("sm2/private_key.pem");
		sm2 = SmUtil.sm2(privateKey, puclicKey);
		sm2.usePlainEncoding();
		// 加密方式
		// https://blog.csdn.net/weixin_44724660/article/details/122319132
		// 1 - C1C3C2,0 - C1C2C3,默认为1, 与前端保持一致, 设置为C1C2C3
		sm2.setMode(SM2Engine.Mode.C1C2C3);
	}

	/**
	 * 加密字符串
	 *
	 * @param dataStr 原始数据字符串
	 * @return java.lang.String 加密后的16进制字符串
	 */
	public static String encode(String dataStr) {
		return sm2.encryptHex(dataStr, KeyType.PublicKey);
	}

	/**
	 * 解密字符串
	 *
	 * @param encrypedHexStr 加密后的16进制字符串
	 * @return java.lang.String 解密后的字符串
	 */
	public static String decode(String encrypedHexStr) {
		if (!encrypedHexStr.startsWith("04")) {
			encrypedHexStr = "04" + encrypedHexStr;
		}
		return sm2.decryptStr(encrypedHexStr, KeyType.PrivateKey);
	}

}

前端

引入依赖

npm install --save sm-crypto
const sm2 = require('sm-crypto').sm2;

// 公钥 - 用来加密 - 由后端生成发送给前端
let publicKey  = "0463462d2611966c08430219d64b2b1166807951bee2f9b41a615f1d20c3e701a5fe2c239454b7646161b6b3e14ee0c8b36d44f6fa4727e8a0b04180ebf3c6a127";
// 私钥 - 用来解密 - 由后端生成发送给前端
let privateKey = "1776f049d4bddea7829a8dcade066d96798cf720fe142e5a1b3b9f7263e8fe16";

// 验证公钥
let verifyResult = sm2.verifyPublicKey(publicKey);
console.log(verifyResult);

// 1-C1C3C2 / 0-C1C2C3,默认为1, 与后端保持一致, 这里我们设为0 -C1C2C3
const cipherMode = 0;

// 要加密的字符串
let str = "admin";

// 加密
let encryptData = sm2.doEncrypt(str, publicKey, cipherMode);
console.log(encryptData);

// 解密
let decryptData = sm2.doDecrypt(encryptData, privateKey, cipherMode);
console.log(decryptData);

前端一般只需要加密, 所以只需要配置下公钥就行, 私钥出于安全考虑可以不作声明

标签:加密传输,hutool,String,解决方案,sm2,SM2,org,import,crypto
From: https://www.cnblogs.com/iminifly/p/16720715.html

相关文章