SM256 JS JAVA 前后端加解迷 整套奉献
前后端js和java的解密加密请看
https://www.cnblogs.com/BoyTNT/p/13086321.html
后端基于以上链接中的java 解密增加加密代码
package com.lb.base.commons.base.utils.crypto.client;
import com.lb.base.commons.base.exception.ServiceException;
import com.lb.base.commons.base.utils.crypto.CryptoPsCode;
import com.lb.base.commons.base.utils.crypto.bo.CryptoBO;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;
/**
* @author tangzedong.programmer@gamil.com
* @apiNote SM2加密的变种,可以用于前端加密的解密
* @since 2020/10/24 10:44
*/
@Slf4j
public class SM2P256CryptoPsCodeClient implements CryptoPsCode {
private static final String ALGORITHM = "sm2p256v1";
private ECDomainParameters domainParameters;
public SM2P256CryptoPsCodeClient() {
X9ECParameters sm2ECParameters = GMNamedCurves.getByName(ALGORITHM);
domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
}
/**
* 生成私钥公钥
*
* @return 私钥公钥
*/
@Override
public CryptoBO generateKey() {
try {
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));
return new CryptoBO().setPubKey(publicKeyHex).setPriKey(privateKeyHex);
} catch (Exception e) {
throw new ServiceException(e, "生成公钥私钥失败!");
}
}
/**
* 加密密码
*
* @param psCode 明文密码
* @param publicKey 公钥
* @return 加密后的密码
*/
@Override
public String cryptoPsCode(String psCode, String publicKey) {
try {
//提取公钥点
ECPoint pukPoint = domainParameters.getCurve().decodePoint(hexString2byte(publicKey));
// 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
ECPublicKeyParameters pubKey = new ECPublicKeyParameters(pukPoint, domainParameters);
SM2Engine sm2Engine = new SM2Engine();
sm2Engine.init(true, new ParametersWithRandom(pubKey, new SecureRandom()));
byte[] in = Base64.getEncoder().encode(psCode.getBytes(StandardCharsets.UTF_8));
return Hex.toHexString(sm2Engine.processBlock(in, 0, in.length));
} catch (Exception e) {
log.error("加密失败!", e);
throw new ServiceException(e, "加密失败!");
}
}
/**
* @param hexString 16进制字符串 如:"33d20046" 转换为 0x33 0xD2 0x00 0x46
* @return
* @Title: hexString2byte
* @Description: 16进制字符串转字节数组
* @since: 0.0.1
*/
public static byte[] hexString2byte(String hexString) {
if (null == hexString || hexString.length() % 2 != 0 || hexString.contains("null")) {
return null;
}
byte[] bytes = new byte[hexString.length() / 2];
for (int i = 0; i < hexString.length(); i += 2) {
bytes[i / 2] = (byte) (Integer.parseInt(hexString.substring(i, i + 2), 16) & 0xff);
}
return bytes;
}
public static void main(String[] args) {
String priKey = "962a8fe61218485d8e55d77bbe381f2f6e228367fcfd083834117b867e4b107";
String pubKey = "04e71a4d21bc6ec2e1e5a404ef014845153b4a5882f2cdff5450bb62398363d5c261e5cbc4f4f0c23a64e06d506e0c043162d2dcc5bf9eedb5c24aa1313c438d3f";
SM2P256CryptoPsCodeClient client = new SM2P256CryptoPsCodeClient();
String psCode = client.cryptoPsCode("123abc..", pubKey);
System.out.println("======cipher======:" + psCode);
psCode = client.decryptPsCode(psCode, priKey);
System.out.println("======psCode======:" + psCode);
}
/**
* 解密密码
*
* @param cipher 密码
* @param priKey 秘钥
* @return 解密后密码明文
*/
@Override
public String decryptPsCode(String cipher, String priKey) {
try {
//JS加密产生的密文
byte[] cipherDataByte = Hex.decode(cipher);
//刚才的私钥Hex,先还原私钥
ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(new BigInteger(priKey, 16), domainParameters);
//用私钥解密
SM2Engine sm2Engine = new SM2Engine();
sm2Engine.init(false, privateKeyParameters);
//processBlock得到Base64格式,记得解码
return new String(Base64.getDecoder().decode(sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length)));
} catch (Exception e) {
log.error("数据完整性被破坏!", e);
throw new ServiceException(e, "数据完整性被破坏!");
}
}
}