OpenApi请求体加密
加密说明:
- 采取主动使用加密的策略,当需要对openApi接口进行加密时需在请求头中增加加密类型securityType,例如securityType=AES,只有请求头中增加加密类型的接口才会采取对应类型的加密策略。
除了【单点登录SSO】【企业openApi登陆】接口,其余接口都会对返回数据进行整体加密- 加密策略:先对返回的数据进行AES加密,然后再进行base64编码,即可得到加密后的数据
- 解密策略:先对加密数据进行base64解码,然后AES解密
时序图:
秘钥处理逻辑说明
从每刻获取的密钥需通过特殊处理后方可正常使用,具体操作如下:
String key = new String(Arrays.copyOf(Base64.encodeBase64String("{从每刻获取的密钥}".getBytes()).getBytes(), 16))
加解密工具AESUtil:
package com.maycur.common.util;
import com.maycur.common.constant.I18NMessage;
import com.maycur.common.exception.NAckException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Base64Utils;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
public class AESUtil {
private static final String TRANSFORM_CBC_PKCS5 = "AES/CBC/PKCS5Padding";
private static final Logger logger = LoggerFactory.getLogger(AESUtil.class);
/**
* 基于CBC工作模式的AES加密
*
* @param value 待加密字符串
* @param key 秘钥
*/
public static String encryptCbcMode(final String value, String key) {
if (StringUtils.isNotBlank(value)) {
final SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
//初始化向量器
final IvParameterSpec ivParameterSpec = new IvParameterSpec(Arrays.copyOfRange(key.getBytes(), 0, 16));
try {
Cipher encipher = Cipher.getInstance(TRANSFORM_CBC_PKCS5);
//加密模式
encipher.init(Cipher.ENCRYPT_MODE, keySpec, ivParameterSpec);
//使用AES加密
byte[] encrypted = encipher.doFinal(value.getBytes(StandardCharsets.UTF_8));
//然后转成BASE64返回
return Base64.encodeBase64String(encrypted);
} catch (Exception e) {
logger.warn("使用AES加密失败, errorMsg:{}", e.getMessage(), e);
throw new NAckException(I18NMessage.MESSAGE_ENT_SECRET_ENCRYPT);
}
}
return value;
}
/**
* 基于CBC工作模式的AES解密
*
* @param encryptedStr AES加密之后的字符串
* @param key 秘钥
*/
public static String decryptCbcMode(final String encryptedStr, String key) {
if (StringUtils.isNotBlank(encryptedStr)) {
final SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
//初始化向量器
final IvParameterSpec ivParameterSpec = new IvParameterSpec(Arrays.copyOfRange(key.getBytes(), 0, 16));
try {
Cipher encipher = Cipher.getInstance(TRANSFORM_CBC_PKCS5);
//设定加密模式
encipher.init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec);
//用BASE64解密
byte[] encryptedBytes = Base64.decodeBase64(encryptedStr);
//用AES解密
byte[] originalBytes = encipher.doFinal(encryptedBytes);
return new String(originalBytes);
} catch (Exception e) {
logger.warn("使用AES解密失败, errorMsg:{}", e.getMessage(), e);
throw new NAckException(I18NMessage.MESSAGE_ENT_SECRET_DECRYPT);
}
}
return null;
}
public static void main(String[] args) {
String value = "{\"test\":\"测试待加密数据\"}";
byte[] bytes = Arrays.copyOf(Base64Utils.encodeToString("DTEC180818128U4MCS".getBytes()).getBytes(), 16);
String key = new String(bytes);
System.out.println(key);
System.out.println(key.getBytes().length);
String encryptValue = encryptCbcMode(value, key);
System.out.println(encryptValue);
String decryptValue = decryptCbcMode(encryptValue, key);
System.out.println(decryptValue);
}
public static void main(String[] args) {
String value = "{\n" +
" \"length\": 100,\n" +
" \"start\": 200,\n" +
" \"keyword\": \"\"\n" +
"}";
//"DTEC180818128U4MCS" 配置的密钥
byte[] bytes = Arrays.copyOf(Base64Utils.encodeToString("DTEC180818128U4MCS".getBytes()).getBytes(), 16);
//实际加密使用的密钥
String key = new String(bytes);
System.out.println(key);
System.out.println(key.getBytes().length);
String encryptValue = encryptCbcMode(value, key);
System.out.println(encryptValue);
String decryptValue = decryptCbcMode(encryptValue, key);
System.out.println(decryptValue);
}
}