传输加密
更新时间: 2024-12-04 15:46:07
加密方法说明
使用非对称加密算法和对称加密算法混合模式,在支持对大量数据加解密的同时,保证了加解密速度,安全性更高,主要应用于一些用户信息、敏感信息加密的安全性要求比较高的场景。
- SM2:非对称加密算法,由公钥和私钥组成秘钥对。
- AES: 对称加密算法,使用AES秘钥。
加密流程如下所示:
API加密调用说明
header设置
若使用SM2 + AES加密,则需要在header中传入:
- sm2PublicKey(SM2公钥,由数据服务提供)
- encryptedAesKey(加密后的AES秘钥)
参数设置
在请求体中,需要传入加密后的密文cipherData:
- POST请求体示例:
{
"cipherData":"40de3124bb5f0d71703a320289752d75271986c9de05d98471ec7fa08019415c"
}
- GET请求参数示例
http://api路径?cipherData=
响应结构
API会对查询结果加密,包括结果集、分页参数等,加密信息在data结构中,字段名为”cipherData“。
{
"code": 0,
"cost": 56,
"data": {
"cipherData": "f131c649c5ce319dea7f4c4b1255dce9e775eca3285af06a4492b79539c2bcd8e03794aea78d3a1c07c72003ecfe9bef0f028711ac6a1e9cbf4945c14a94858278da0a34d110e5e2905688efcfd6f04d94f98acd31ca7c2bc522da4ef403aff83932e90b19ebd19b2049209347766cebe45539b032e13753a2d66ab74df85b00e25bcbcd1d96cb97df8914b7272392b0d357eb8827190ce58e607cd92cf2867b5822d73ab0bb01ef6569e8b3b1f54779c89bfd2a782f73744df238d049e393f40b2b61bd5bc8a74582b14776194d7ef4cc26122e4abab37aff805bd345ca1812288cd846299c90d17a37950d683711bb4b2f640ad42bd6e1657a77ec0e49d7077977df413e659c5b873dcbbb24304d4eeaa8a80b747c1749ca348b9c1f245ea590bb19b0e9be430ea0e00d01e6b10da453abe176ac0350ca234d88903fef00bd8e8e3b8e025f347604eeedf38fedcaf8cd410bae3defb5c790a40e4e0f8cdbf3533fd1d97dbb3c8a1b6ec64a930745d758dfe7f762f769601b1774644b5d528e3b6523f4ef4a2884767426468f3e333f2085921f5ad6805d73d691fb662fd0e6b80653016ddbb3f9e361798521630141a398ae5e42d699c67bf3d1c1805063e504a5b6a93cd860613029b4772f315533aa38f0143146da19338c0c3fe55d8af4e7811aa1d2e33311f2c1f09910fe9589ccbc15c9e2ab67e436d66f12167cfaa70f028711ac6a1e9cbf4945c14a9485825b2c9550dbb548ad1a4daef5e4d7b064fad08c25196df5a7de8b4eccef97e3cb6f6114511e46f2785575e7292d82ee6a22e66446e577de47029a055f65f47008c54a6b6db7a6d6efefc3cf08bf3b8a22894015ede132cdbd59d8852d6e545d65495d4106030ef6178de7669cc3d318d33d90ac2013b443af54ae0f06037ae0ab57fd64190401dbe606a53c9fb3b11fbea17911cd896f54a7a4bcadee05ee6bdd3bb80f53cf6fe9a8c84a27645ebb35d21c00b651084428a87c53fcf6a8197e9f10dc3af6354f52c0c3e8d740b8e03f61918c161761292eed97ad810ca8b48ab334ff369d4a70c622420626398a062787efdbc2073ab6a83ab621e891fa678b5c"
},
"message": "success",
"desc": null,
"reqId": "0c99d7116f7d498ba9f28f5b04aedf2c"
}
加密解密代码示例
请求参数加密
public static void main(String[] args) throws Exception {
//GET请求参数明文
String content = "field1=100&field2=abc";
//POST请求明文
// String content = "{\"field1\":100,\"field2\":200}";
//生成AES主秘钥
String aesKey = AesUtil.genAESKey();
//AES加密,生成请求密文
String cipherData = AesUtil.encode(aesKey,content);
//应用管理——应用详情中的SM2公钥
String sm2PubKey = "033eae4b2981e6b4300b0d389528db789b3e003d4d2c605bdce5f992e78328c8fd";
//给AES主秘钥加密
String encryptedAesKey = SM2Util.encrypt(sm2PubKey,aesKey);
//将请求密文cipherData、AES主密钥密文encryptedAesKey放到请求header中
}
响应结果解密
public static void main(String[] args) throws Exception {
//加密后的响应结果
String responseCipherData = "40de3124bb5f0d71703a320289752d75271986c9de05d98471ec7fa08019415c";
//加密时生成的AES主秘钥
String aesKey = "uBdUx82vPHkDKb284d7NkjFoNcKWBuka";
//对响应密文解密
String content = AesUtil.decode(aesKey,responseCipherData);
}
加密工具类
- AES工具类
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
@Slf4j
public class AesUtil {
/**
生成AESKEY
*/
public static String genAESKey() throws NoSuchAlgorithmException {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = new SecureRandom();
kgen.init(256, secureRandom);
SecretKey key = kgen.generateKey();
return Base64.encodeBase64String(key.getEncoded());
}
/**
* AES加密
* @param aesKey
* @param data
* @return
*/
public static String encode(String aesKey, String data) throws Exception{
// 转换KEY
Key key = new SecretKeySpec(aesKey.getBytes("UTF-8"),"AES");
// 加密
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] result = cipher.doFinal(data.getBytes());
return Hex.encodeHexString(result);
}
/**
* AES解密
* @param aesKey
* @param data
* @return
*/
public static String decode(String aesKey, String data) throws Exception {
// 转换KEY
Key key = new SecretKeySpec(aesKey.getBytes("UTF-8"),"AES");
// 解密
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] result = cipher.doFinal(Hex.decodeHex(data));
return new String(result);
}
}
- SM2工具类
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.ECGenParameterSpec;
import javafx.util.Pair;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;
import org.springframework.stereotype.Component;
/**
* SM2加解密工具类
*/
@Slf4j
@Component
public class SM2Util {
private static BouncyCastleProvider provider;
// SM2曲线参数
private static X9ECParameters sm2ECParameters;
// Domain参数
static ECDomainParameters domainParameters;
private SM2Util() {
try {
provider = new BouncyCastleProvider();
sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(),
sm2ECParameters.getN());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* SM2算法生成密钥对
*
* @return 密钥对信息
*/
public static Pair<String, String> generateSm2KeyPair()
throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {
final ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
// 获取一个椭圆曲线类型的密钥对生成器
final KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", provider);
SecureRandom random = new SecureRandom();
// 使用SM2的算法区域初始化密钥生成器
kpg.initialize(sm2Spec, random);
// 获取密钥对
KeyPair keyPair = kpg.generateKeyPair();
BCECPrivateKey privateKey = (BCECPrivateKey) keyPair.getPrivate();
BCECPublicKey publicKey = (BCECPublicKey) keyPair.getPublic();
String pubKey = new String(Hex.encode(publicKey.getQ().getEncoded(true)));
String prvKey = privateKey.getD().toString(16);
return new Pair<>(pubKey, prvKey);
}
/**
* SM2加密算法
*
* @param publicKey 公钥
* @param data 明文数据
* @return 密文
*/
public static String encrypt(String publicKey, String data) {
//提取公钥点
ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(publicKey));
// 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint,
domainParameters);
SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
// 设置sm2为加密模式
sm2Engine.init(true, new ParametersWithRandom(publicKeyParameters, new SecureRandom()));
byte[] arrayOfBytes = null;
try {
byte[] in = data.getBytes();
arrayOfBytes = sm2Engine.processBlock(in, 0, in.length);
} catch (Exception e) {
log.error("SM2加密时出现异常:" + e.getMessage());
}
return Hex.toHexString(arrayOfBytes);
}
/**
* SM2解密算法
*
* @param privateKey 私钥
* @param cipherData 密文数据
* @return 明文
*/
public static String decrypt(String privateKey, String cipherData) {
// 使用BC库加解密时密文以04开头,传入的密文前面没有04则补上
if (!cipherData.startsWith("04")) {
cipherData = "04" + cipherData;
}
byte[] cipherDataByte = Hex.decode(cipherData);
BigInteger privateKeyD = new BigInteger(privateKey, 16);
ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD,
domainParameters);
// 新排序模式
SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
// 设置sm2为解密模式
sm2Engine.init(false, privateKeyParameters);
String result = "";
try {
byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
return new String(arrayOfBytes);
} catch (Exception e) {
log.error("SM2解密时出现异常:" + e.getMessage());
}
return result;
}
}