国密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);
}

所有代码在这里,源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

链诸葛

真爱了。

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

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

打赏作者

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

抵扣说明:

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

余额充值