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 createKeyPair() throws NoSuchAlgorithmException { ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); keyPairGenerator.init(new ECKeyGenerationParameters(getECDomainParameters(), SecureRandom.getInstance(KeyConstant.ALGORITHM))); AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair(); Map 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"); } }