信封加密
何为信封加密,大概意思就是一批数据可以装在一个信封里进行安全传输,何为安全传输,就是加密密钥和加密的数据是分开存储的,获取任何一个都无法进行解密操作。
流程如下:
- 信封加密实例版本参考如下:
package com.qdum.smsservice.config;
import com.aliyun.dkms.gcs.openapi.models.Config;
import com.aliyun.dkms.gcs.sdk.Client;
import com.aliyun.dkms.gcs.sdk.models.*;
import com.aliyun.tea.TeaException;
import com.qdum.smsservice.common.model.BaseDto;
import com.qdum.smsservice.domain.AdvanceGenerateDataKeyInfo;
import com.qdum.smsservice.web.rest.errors.ErrorCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ResourceUtils;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.FileNotFoundException;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
/**
* @author Mr.sunql
* @description
* kms 实例版本
* @date Created in15:34 2024/8/19
*/
public class KmsAdvanceClient {
private static final Logger log = LoggerFactory.getLogger(KmsAdvanceClient.class);
private static String endpoint = "kst-8988888888.cryptoservice.kms.aliyuncs.com";
private static String clientKeyPass = "af6fe64e58553b4599c965653a090b47";
private static Client client;
private static final int GCM_IV_LENGTH = 12;
private static final int GCM_TAG_LENGTH = 16;
private static final String iv_base64 = "KYJOxtYbd3Rmn5zB";
/**
* 初始化client 链接
* @return
*/
public static Client getKmsClient(){
String clientKeyFilePath = null;
String cafilePath=null;
try {
clientKeyFilePath = ResourceUtils.getFile("classpath:kms/clientKey.json").getPath();
cafilePath=ResourceUtils.getFile("classpath:kms/ca.pem").getPath();
client = new Client(new Config()
.setProtocol("https")
.setEndpoint(endpoint)
.setCaFilePath(cafilePath) // 设置CA证书文件路径,还支持设置CA证书内容,请根据需要选择。
.setClientKeyFile(clientKeyFilePath)//设置应用身份凭证文件路径,还支持设置应用身份凭证内容,请根据需要选择。
.setPassword(clientKeyPass));
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}catch (Exception e) {
e.printStackTrace();
}
log.info("获取连接 kmsClient=>{}",client);
return client;
}
/**
* 生成密钥
* @param keyId
* @return
*/
public static AdvanceGenerateDataKeyInfo advanceGenerateData(String keyId){
Client kmsClient = KmsAdvanceClient.getKmsClient();
AdvanceGenerateDataKeyRequest advanceGenerateDataKeyRequest=new AdvanceGenerateDataKeyRequest();
advanceGenerateDataKeyRequest.setKeyId(keyId);
advanceGenerateDataKeyRequest.setNumberOfBytes(32);
AdvanceGenerateDataKeyResponse advanceGenerateDataKeyResponse=null;
AdvanceGenerateDataKeyInfo advanceGenerateDataKeyInfo=new AdvanceGenerateDataKeyInfo();
try {
advanceGenerateDataKeyResponse = kmsClient.advanceGenerateDataKey(advanceGenerateDataKeyRequest);
log.info("KeyId:{} ,Plaintext:{} ,CiphertextBlob: {} ,Iv: {}",advanceGenerateDataKeyResponse.getKeyId(),advanceGenerateDataKeyResponse.getPlaintext(),Arrays.toString(advanceGenerateDataKeyResponse.getCiphertextBlob()),Arrays.toString(advanceGenerateDataKeyResponse.getIv()));
advanceGenerateDataKeyInfo.setIv(Base64.getEncoder().withoutPadding().encodeToString(advanceGenerateDataKeyResponse.getIv()));
advanceGenerateDataKeyInfo.setAlgorithm(advanceGenerateDataKeyResponse.getAlgorithm());
advanceGenerateDataKeyInfo.setKeyVersionId(advanceGenerateDataKeyResponse.getKeyVersionId());
advanceGenerateDataKeyInfo.setCiphertextBlob(Base64.getEncoder().withoutPadding().encodeToString(advanceGenerateDataKeyResponse.ciphertextBlob));
advanceGenerateDataKeyInfo.setRequestId(advanceGenerateDataKeyResponse.getRequestId());
advanceGenerateDataKeyInfo.setKeyId(advanceGenerateDataKeyResponse.getKeyId());
advanceGenerateDataKeyInfo.setPlaintext(Base64.getEncoder().withoutPadding().encodeToString(advanceGenerateDataKeyResponse.plaintext));
} catch (TeaException e) {
log.error("code: {} ,message: {},requestId:{}", ((TeaException) e).getCode(),e.getMessage(),((TeaException) e).getData().get("requestId"));
e.printStackTrace();
} catch (Exception e) {
log.error("advanceGenerateData err:{}", e.getMessage());
e.printStackTrace();
}
return advanceGenerateDataKeyInfo;
}
/**
* 信封加密
* @param plaintext 待加密的明文
* @param base64PlainDataKey 明文密钥
* @return
*/
public static String advanceEncrypt(String plaintext,String base64PlainDataKey) {
byte[] data = plaintext.getBytes(StandardCharsets.UTF_8);
byte[] iv = null; // 加密初始向量,解密时也需要传入
byte[] cipherText = null; // 密文
try {
iv = new byte[GCM_IV_LENGTH];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
iv = Base64.getDecoder().decode(iv_base64);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(Base64.getDecoder().decode(base64PlainDataKey), "AES");
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmParameterSpec);
cipherText = cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return Base64.getEncoder().withoutPadding().encodeToString(cipherText);
}
/**
* 解密数据
* @param keyId
* @param base64DataKeyIv 初始向量
* @param base64EncryptedDataKey 密钥密文
* @param base64CipherText base64加密内容
* @return
*/
public static String advanceDecrypt(String keyId,String base64DataKeyIv, String base64EncryptedDataKey,String base64CipherText) {
Client kmsClient = KmsAdvanceClient.getKmsClient();
byte[] plainDataKey = null;
byte[] decryptedData=null;
try {
DecryptRequest decryptRequest = new DecryptRequest()
.setKeyId(keyId)
.setCiphertextBlob(Base64.getDecoder().decode(base64EncryptedDataKey))
.setIv(Base64.getDecoder().decode(base64DataKeyIv));
DecryptResponse decryptResponse = kmsClient.decrypt(decryptRequest);
//先获取数据密钥的明文
plainDataKey = decryptResponse.getPlaintext();
//再进行本地解密数据
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(plainDataKey, "AES");
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, Base64.getDecoder().decode(iv_base64));
cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec);
decryptedData = cipher.doFinal(Base64.getDecoder().decode(base64CipherText));
} catch (TeaException e) {
log.info("code: {} ,message: {} ,requestId: {}", ((TeaException) e).getCode(), e.getMessage(), ((TeaException) e).getData().get("requestId"));
e.printStackTrace();
throw new RuntimeException(e);
} catch (Exception e) {
log.info("advanceDecrypt err: {}", e.getMessage());
e.printStackTrace();
throw new RuntimeException(e);
}
return new String(decryptedData, StandardCharsets.UTF_8);
}
}