国密SM2前端js加密,后端加密解密,publicKey转ECPublicKeyParameters,privateKey转ECPrivateKeyParameters

关于SM2

SM2算法是中国密码学研究所(中国国家加密管理局)发布的一种非对称加密算法,适用于数字签名、密钥交换和公钥加密等场景。该算法基于椭圆曲线密码学,使用椭圆曲线上的点进行运算。

SM2算法的主要特点如下:

安全性高:SM2算法基于椭圆曲线离散对数问题,具有较高的安全性。
算法效率高:SM2算法的计算量相对较小,适合在资源受限的环境中使用。
适用性广泛:SM2算法可用于数字签名、密钥交换和公钥加密等多种密码应用场景。
算法标准化:SM2算法已被国际电信联盟(ITU-T)和国际标准化组织(ISO)认可为国际标准。

SM2算法的应用场景

安全通信:SM2算法可用于加密电子邮件、即时通讯等通信内容,保护通信的机密性和完整性。

数字签名:在电子合同、电子票据等场景中,SM2算法可用于生成和验证数字签名,确保文件的不可否认性和真实性。

身份认证:SM2算法可用于实现安全的身份认证机制,如在电子政务、金融服务等领域。

数据保护:在数据存储、传输过程中,SM2算法可用于保护数据的安全性,防止数据泄露。

引入jar包依赖

<!-- SM2加密 -->
<dependency>
	<groupId>org.bouncycastle</groupId>
	<artifactId>bcprov-jdk15on</artifactId>
	<version>1.65</version>
</dependency>

生成 SM2 公私钥对

公私钥只需要在第一次使用时生成,保存,后期直接使用即可。

public static X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
public static ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
		
public static String publicKey = "041620e22b3389db4ec89233a2cba7f7efed06cea1990e82fe5c27f85d41f1b44802f05b125391663bc9809a2e5bc86444139d1cb15c4939189e6386e6a865a3b5";
		
//私钥,用来解密
public static String privateKey = "9c3e9ba372448da70b387529acb6f271eb7c25e2e3cca315678c770dcf3b9739";
/**
 * 生成公私钥
 * @return
 * @throws Exception
 */
public static String[] key() throws Exception{
	String[] key = new String[2];
	
	ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
	keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG")));
	AsymmetricCipherKeyPair keyPair = keyPairGenerator.generateKeyPair();

	//私钥
	BigInteger privatekey = ((ECPrivateKeyParameters) keyPair.getPrivate()).getD();
	String privateKey = privatekey.toString(16);
	key[0] = privateKey;
	
	//公钥
	ECPoint ecPoint = ((ECPublicKeyParameters) keyPair.getPublic()).getQ();
	String publicKey = Hex.toHexString(ecPoint.getEncoded(false));
	key[1] = publicKey;
	return key;
}

公钥用来加密,私钥用来解密,加密可以在前端使用js加密,也可以在用端加密。

前端js加密

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SM2加密</title>
<script src="./js/jquery-2.1.1.js"></script>
<script src="./js/crypto-js.js"></script>
<script src="./js/sm2.js"></script>
<script type="text/javascript">
	var privateKey = "9c3e9ba372448da70b387529acb6f271eb7c25e2e3cca315678c770dcf3b9739";
	//公钥,用来加密
	var pubkeyHex = "041620e22b3389db4ec89233a2cba7f7efed06cea1990e82fe5c27f85d41f1b44802f05b125391663bc9809a2e5bc86444139d1cb15c4939189e6386e6a865a3b5";
	//加密,每次加密得到的加密串都不一样
	function encrypt() {
		var cipher = sm2Encrypt($('#password').val(), pubkeyHex, 0);
		$('#cipher').val(cipher);
	}
</script>
</head>
<body>
	<input id="initData" name="initData" type="text" placeholder="原始数据" />
	<input id="cipher" name="cipher" type="text" placeholder="加密数据" />
	<button type="button" id="btn_submit" onclick="encrypt()">
		<span>加密</span>
	</button>
</body>
</html>

后端加密

加密时需要将公钥串转换为ECPublicKeyParameters。

//提取公钥点
ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(publicKey));
ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);
/**
 * 数据加密
 * @param clearData
 * @return
 */
public static String encrypt(String clearData) {
	String cipher = "";
	byte[] in = clearData.getBytes();
   
	//提取公钥点
	ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(publicKey));
	ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);

	//用公钥加密
	SM2Engine sm2Engine = new SM2Engine();
	sm2Engine.init(true, new ParametersWithRandom(publicKeyParameters, new SecureRandom()));

	byte[] arrayOfBytes = null;
	try {
		arrayOfBytes = sm2Engine.processBlock(in, 0, in.length);
		cipher = Hex.toHexString(arrayOfBytes);
	} catch (Exception e) {
		e.printStackTrace();
	}
	return cipher;

}

后端解密

针对js加密和后端加密,在解密时会有一点不同的地方。

解密时需要将密钥串转换为privateKeyParameters。

BigInteger privateKeyD = new BigInteger(privateKey, 16);
ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);

针对前端js加密数据进行解密

/**
 * 解密,如果内容并非使用SM2加密或者加密内容被篡改或者内容是普通内容,解密会异常
 * 前端js方式加密,后端解密后需要Base64.getDecoder().decode
 * @param cipherData
 * @return
 */
public static String decryptForJS(String cipherData) {

	String clear = "";
	byte[] cipherDataByte = Hex.decode(cipherData);
	
	BigInteger privateKeyD = new BigInteger(privateKey, 16);
	ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);
	
	//用私钥解密
	SM2Engine sm2Engine = new SM2Engine();
	sm2Engine.init(false, privateKeyParameters);

	byte[] arrayOfBytes;
	try {
		arrayOfBytes = Base64.getDecoder().decode(sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length));
		//得到明文
		clear = new String(arrayOfBytes);
	} catch (InvalidCipherTextException e) {
		e.printStackTrace();
	}
	return clear;
}

针对后端加密数据进行解密

/**
 * 解密,如果内容并非使用SM2加密或者加密内容被篡改或者内容是普通内容,解密会异常
 * @param cipherData
 * @return
 */
public static String decrypt(String cipherData) {

	String clear = "";
	byte[] cipherDataByte = Hex.decode(cipherData);
	
	BigInteger privateKeyD = new BigInteger(privateKey, 16);
	ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);
	
	//用私钥解密
	SM2Engine sm2Engine = new SM2Engine();
	sm2Engine.init(false, privateKeyParameters);

	byte[] arrayOfBytes;
	try {
		arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
		//得到明文
		clear = new String(arrayOfBytes);
	} catch (InvalidCipherTextException e) {
		e.printStackTrace();
	}
	return clear;
}

数据加解密测试

public static void main(String[] args) {
	String data = "Hi SM2";
	String cipher = encrypt(data);
	System.out.println(cipher);
	String clear = decrypt(cipher);
	System.out.println(clear);
	//前端加密生成的加密串
	cipher = "041c0a87b68d195ee5528b0265a2bae2fd5c214c7dc3d3310612d02df2cdaf563ed74f4d98c69bd4acf79bdf1b0e562c01bec241b277560c083bd3e323d0bb3a384d64a7cb93fab1613b8e96d243078b7ba583b92fedd7a3eeab53c70a5b4af4ef1326722fbaf1078b53e4b3a0";
	clear = SM2Utils.decryptForJS(cipher);
	System.out.println(clear);
}

所有代码在这里,源码

参考资源链接:[Vue与SpringBoot实现SM2/3/4前后端联调加解](https://wenku.youkuaiyun.com/doc/vvbtpdkd1d?utm_source=wenku_answer2doc_content) 在构建一个需要数据加密交互的Web应用时,确保使用安全的加密算法至关重要。特别是对于那些需要遵守中家标准(GM标准)的应用,例如使用SM2、SM3和SM4算法进行数据加密和解。以下是一个具体实现的示例: 首先,确保在Vue前端和SpringBoot后端都已经引入了支持算法的第三方库。例如,在前端使用npm安装SM-Crypto库: ```bash npm install --save sm-crypto ``` 在Vue前端,创建一个加密模块,用于加密用户数据: ```javascript // 前端加密模块 import SM from 'sm-crypto'; import { encryptSM2, decryptSM2 } from './sm2Tools'; const keyPair = SM.KeyPair.fromRandom(); // 生成随机钥对 const publicKey = keyPair.getPublicKey(); // 获取公钥用于加密 const privateKey = keyPair.getPrivateKey(); // 获取私钥用于解 export function encryptSM2(data) { return encryptSM2(data, publicKey); } export function decryptSM2(encryptedData) { return decryptSM2(encryptedData, privateKey); } function encryptSM2(data, publicKey) { const cipher = new SM.Cipher('sm2'); cipher.setPublicKey(publicKey); return cipher.doEncrypt(data); } function decryptSM2(encryptedData, privateKey) { const cipher = new SM.Cipher('sm2'); cipher.setPrivateKey(privateKey); return cipher.doDecrypt(encryptedData); } ``` 在SpringBoot后端,创建相应的控制器和加密工具类以处理加密和解请求: ```java // 后端加密工具类 import cn.gmssl.sm2.*; import cn.gmssl.sm4.*; ***ponent; @Component public class EncryptionUtils { private KeyPair keyPair = KeyPair.generateRandom(); // 生成随机钥对 private String publicKey = keyPair.getPublicKey(); // 获取公钥 private String privateKey = keyPair.getPrivateKey(); // 获取私钥 public String encryptSM2(String data) { // 加密数据 } public String decryptSM2(String encryptedData) { // 解数据 } } // 后端控制器 @RestController public class DataController { private final EncryptionUtils encryptionUtils; @Autowired public DataController(EncryptionUtils encryptionUtils) { this.encryptionUtils = encryptionUtils; } @PostMapping( 参考资源链接:[Vue与SpringBoot实现SM2/3/4前后端联调加解](https://wenku.youkuaiyun.com/doc/vvbtpdkd1d?utm_source=wenku_answer2doc_content)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

链诸葛

真爱了。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值