package com.dji.sample.droneairport.utils.SM2;
|
|
import org.bouncycastle.asn1.gm.GMNamedCurves;
|
import org.bouncycastle.asn1.x9.X9ECParameters;
|
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
import org.bouncycastle.crypto.InvalidCipherTextException;
|
import org.bouncycastle.crypto.engines.SM2Engine;
|
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.crypto.params.ParametersWithRandom;
|
import org.bouncycastle.math.ec.ECPoint;
|
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
|
import org.bouncycastle.util.encoders.Hex;
|
|
import java.io.IOException;
|
import java.io.UnsupportedEncodingException;
|
import java.math.BigInteger;
|
import java.security.NoSuchAlgorithmException;
|
import java.security.SecureRandom;
|
import java.util.HashMap;
|
import java.util.Map;
|
|
/**
|
* SM2公钥密码算法(非对称算法)
|
* SM2椭圆曲线公钥密码算法是我国自主设计的公钥密码算法。
|
* 包括SM2-1椭圆曲线数字签名算法;SM2-2椭圆曲线密钥交换协议;SM2-3椭圆曲线公钥加密算法,分别用于实现数字签名密钥协商和数据加密等功能。
|
* SM2算法与RSA算法不同的是,SM2算法是基于椭圆曲线上点群离散对数难题,相对于RSA算法,256位的SM2密码强度已经比2048位的RSA密码强度要高。
|
*/
|
public class SecretCommon {
|
|
//获取椭圆曲线
|
public static synchronized ECDomainParameters getECDomainParameters() {
|
X9ECParameters sm2ECParameters = GMNamedCurves.getByName(KeyConstant.GM_NAME_CURVE);
|
return new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
|
}
|
|
/**
|
* get key pair
|
*/
|
public static Map<String, String> createKeyPair() throws NoSuchAlgorithmException {
|
ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
|
keyPairGenerator.init(new ECKeyGenerationParameters(getECDomainParameters(), SecureRandom.getInstance(KeyConstant.ALGORITHM)));
|
AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();
|
Map<String, String> map = new HashMap<>();
|
BigInteger bigInteger = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
|
map.put(KeyConstant.PRIVATE_KEY, ByteUtils.toHexString(bigInteger.toByteArray()));
|
// 把公钥放入map中,默认压缩公钥
|
// 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥,04的时候,可以去掉前面的04
|
ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
|
map.put(KeyConstant.PUBLIC_KEY, ByteUtils.toHexString(ecPoint.getEncoded(false)));
|
return map;
|
}
|
|
/**
|
* 加密
|
* @param plainText 需加密的明文字符串
|
* @param publicKey 公钥
|
* @param modeType base:标准;bc:BC模式
|
*/
|
public static String encrypt(String plainText, String publicKey, ModeTypeEnum modeType) throws IOException, InvalidCipherTextException {
|
return encrypt(plainText.getBytes(), publicKey, modeType.getMode());
|
}
|
|
/**
|
* 加密
|
* @param plainByte 需加密的明文字节数组
|
* @param publicKey 公钥
|
* @param mode 加密模式 ModeTypeEnum
|
*/
|
public static String encrypt(byte[] plainByte, String publicKey, SM2Engine.Mode mode) throws IOException, InvalidCipherTextException {
|
ECDomainParameters domainParameters = getECDomainParameters();
|
//提取公钥点
|
ECPoint ecPoint = domainParameters.getCurve().decodePoint(ByteUtils.fromHexString(publicKey));
|
// 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
|
ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(ecPoint, domainParameters);
|
SM2Engine sm2Engine = new SM2Engine(mode);
|
sm2Engine.init(true, new ParametersWithRandom(publicKeyParameters, new SecureRandom()));
|
return ByteUtils.toHexString(sm2Engine.processBlock(plainByte, 0, plainByte.length));
|
}
|
|
/**
|
* 解密
|
* @param cipherText 需加密的字符串
|
* @param privateKey 私钥
|
* @param modeType base:标准;bc:BC模式
|
*/
|
public static String decrypt(String cipherText, String privateKey, ModeTypeEnum modeType) throws InvalidCipherTextException, UnsupportedEncodingException {
|
return decrypt(Hex.decode(cipherText), privateKey, modeType.getMode());
|
}
|
|
/**
|
* 解密
|
* @param cipherDataByte 密文字节数组
|
* @param privateKeyHex 私钥
|
* @param mode 解密模式 ModeTypeEnum
|
*/
|
public static String decrypt(byte[] cipherDataByte, String privateKeyHex, SM2Engine.Mode mode) throws InvalidCipherTextException, UnsupportedEncodingException {
|
// 将 HEX 私钥转换为 BigInteger
|
BigInteger bigInteger = new BigInteger(privateKeyHex, 16);
|
|
// 创建 EC 私钥参数
|
ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(bigInteger, getECDomainParameters());
|
|
// 初始化 SM2 引擎
|
SM2Engine sm2Engine = new SM2Engine(mode);
|
sm2Engine.init(false, privateKeyParameters);
|
|
// 解密
|
byte[] decryptedBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
|
|
// 将解密后的字节数组转换为 UTF-8 字符串
|
return new String(decryptedBytes, "UTF-8");
|
}
|
|
}
|