加解密小量數據
場景說明
當有少量數據(例如:口令、證書、電話號碼等)需要加解密時,用戶可以通過密鑰管理服務(Key Management Service,KMS)界面使用在線工具加解密數據,或者調用KMS的API接口使用指定的用戶主密鑰直接加密、解密數據。
約束條件
當前支持不大于4KB的小數據加解密。
在線工具加解密
步驟 1 單擊目標自定義密鑰的別名,進入密鑰詳細信息在線工具加密數據頁面。
步驟 2 在“加密”文本框中輸入待加密的數據。
步驟 3 單擊“執行”,右側文本框顯示加密后的密文數據。
解密數據
說明加密數據時,使用當前指定的密鑰加密數據。
用戶可單擊“清除”,清除已輸入的數據。
用戶可單擊“復制到剪切板”拷貝加密后的密文數據,并保存到本地文件中。
步驟 4 解密數據時,可單擊任意“啟用”狀態的非默認密鑰別名,進入該密鑰的在線工具頁面。
步驟 5 單擊“解密”,在左側文本框中數據待解密的密文數據。
說明在線工具自動識別并使用數據被加密時使用的密鑰解密數據。
若該密鑰已被刪除,會導致解密失敗。
步驟 6 單擊“執行”,右側文本框中顯示解密后的明文數據。
說明用戶可直接單擊“復制到剪切板”拷貝解密后的明文數據,并保存到本地文件中。
調用API接口加解密
以保護服務器HTTPS證書為例,采用調用KMS的API接口方式進行說明,如圖所示。
保護服務器HTTPS證書

流程說明如下:
- 用戶需要在KMS中創建一個用戶主密鑰。
- 用戶調用KMS的“encrypt-data”接口,使用指定的用戶主密鑰將明文證書加密為密文證書。
- 用戶在服務器上部署密文證書。
- 當服務器需要使用證書時,調用KMS的“decrypt-data”接口,將密文證書解密為明文證書。
由于控制臺輸入的加密原文會經過一次Base64轉碼后才傳至后端,所以當調用API接口解密密文的時候,返回的明文就是加密原文經過Base64轉碼得到的字符串,故API加密密文后需要調用API進行解密,若使用控制臺解密API加密密文則會產生亂碼。
加解密大量數據
場景說明
當有大量數據(例如:照片、視頻或者數據庫文件等)需要加解密時,用戶可采用信封加密方式加解密數據,無需通過網絡傳輸大量數據即可完成數據加解密。
加密和解密原理
大量數據加密

說明用戶需要在KMS中創建一個用戶主密鑰。
用戶調用KMS的“create-datakey”接口創建數據加密密鑰。用戶得到一個明文的數據加密密鑰和一個密文的數據加密密鑰。其中密文的數據加密密鑰是由指定的用戶主密鑰加密明文的數據加密密鑰生成的。
用戶使用明文的數據加密密鑰來加密明文文件,生成密文文件。
用戶將密文的數據加密密鑰和密文文件一同存儲到持久化存儲設備或服務中。
大量數據解密

說明用戶從持久化存儲設備或服務中讀取密文的數據加密密鑰和密文文件。
用戶調用KMS的“decrypt-datakey”接口,使用對應的用戶主密鑰(即生成密文的數據加密密鑰時所使用的用戶主密鑰)來解密密文的數據加密密鑰,取得明文的數據加密密鑰。
若對應的用戶主密鑰被誤刪除,會導致解密失敗。因此,需要妥善管理好用戶主密鑰。
用戶使用明文的數據加密密鑰來解密密文文件。
加密和解密的API
您可以調用以下API,在本地對數據進行加解密。
| API名稱 | 說明 |
|---|---|
| 創建數據密鑰 | 創建數據密鑰。 |
| 解密數據密鑰 | 用指定的主密鑰解密數據密鑰。 |
加密本地文件
步驟1 通過控制臺,創建用戶主密鑰。
步驟2 請準備基礎認證信息。
- ACCESS_KEY: 帳號Access Key
- SECRET_ACCESS_KEY: 帳號Secret Access Key
- PROJECT_ID:項目ID
- KMS_ENDPOINT: KMS服務訪問終端地址。
步驟3 加密本地文件。
示例代碼中:
- 用戶主密鑰:控制臺創建的密鑰ID。
- 明文數據文件:FirstPlainFile.jpg。
- 輸出的密文數據文件:SecondEncryptFile.jpg。
import com.ctyun.sdk.core.auth.BasicCredentials;
import com.ctyun.sdk.kms.v1.KmsClient;
import com.ctyun.sdk.kms.v1.model.CreateDatakeyRequest;
import com.ctyun.sdk.kms.v1.model.CreateDatakeyRequestBody;
import com.ctyun.sdk.kms.v1.model.CreateDatakeyResponse;
import com.ctyun.sdk.kms.v1.model.DecryptDatakeyRequest;
import com.ctyun.sdk.kms.v1.model.DecryptDatakeyRequestBody;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.security.SecureRandom;
/**
* 使用數據密鑰(DEK)進行文件加解密
* 激活assert語法,請在VM_OPTIONS中添加-ea
*/
public class FileStreamEncryptionExample {
private static final String ACCESS_KEY = "<AccessKey>";
private static final String SECRET_ACCESS_KEY = "<SecretAccessKey>";
private static final String PROJECT_ID = "<ProjectID>";
private static final String KMS_ENDPOINT = "<KmsEndpoint>";
// KMS服務接口版本信息,當前固定為v1.0
private static final String KMS_INTERFACE_VERSION = "v1.0";
/**
* AES算法相關標識:
* - AES_KEY_BIT_LENGTH: AES256密鑰比特長度
* - AES_KEY_BYTE_LENGTH: AES256密鑰字節長度
* - AES_ALG: AES256算法,本例分組模式使用GCM,填充使用PKCS5Padding
* - AES_FLAG: AES算法標識
* - GCM_TAG_LENGTH: GCM TAG長度
* - GCM_IV_LENGTH: GCM 初始向量長度
*/
private static final String AES_KEY_BIT_LENGTH = "256";
private static final String AES_KEY_BYTE_LENGTH = "32";
private static final String AES_ALG = "AES/GCM/PKCS5Padding";
private static final String AES_FLAG = "AES";
private static final int GCM_TAG_LENGTH = 16;
private static final int GCM_IV_LENGTH = 12;
public static void main(final String[] args) {
// 您在控制臺創建的用戶主密鑰ID
final String keyId = args[0];
encryptFile(keyId);
}
/**
* 使用數據密鑰加解密文件實例
*
* @param keyId 用戶主密鑰ID
*/
static void encryptFile(String keyId) {
// 1.準備訪問認證信息
final BasicCredentials auth = new BasicCredentials().withAk(ACCESS_KEY).withSk(SECRET_ACCESS_KEY)
.withProjectId(PROJECT_ID);
// 2.初始化SDK,傳入認證信息及KMS訪問終端地址
final KmsClient kmsClient = KmsClient.newBuilder().withCredential(auth).withEndpoint(KMS_ENDPOINT).build();
// 3.組裝創建數據密鑰請求信息
final CreateDatakeyRequest createDatakeyRequest = new CreateDatakeyRequest().withVersionId(KMS_INTERFACE_VERSION)
.withBody(new CreateDatakeyRequestBody().withKeyId(keyId).withDatakeyLength(AES_KEY_BIT_LENGTH));
// 4.創建數據密鑰
final CreateDatakeyResponse createDatakeyResponse = kmsClient.createDatakey(createDatakeyRequest);
// 5.接收創建的數據密鑰信息
// 密文密鑰與KeyId建議保存在本地,方便解密數據時獲取明文密鑰
// 明文密鑰在創建后立即使用,使用前需要將16進制明文密鑰轉換成byte數組
final String cipherText = createDatakeyResponse.getCipherText();
final byte[] plainKey = hexToBytes(createDatakeyResponse.getPlainText());
// 6.準備待加密的文件
// inFile 待加密的原文件
// outEncryptFile 加密后的文件
final File inFile = new File("FirstPlainFile.jpg");
final File outEncryptFile = new File("SecondEncryptFile.jpg");
// 7.使用AES算法進行加密時,可以創建初始向量
final byte[] iv = new byte[GCM_IV_LENGTH];
final SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(iv);
// 8.對文件進行加密,并存儲加密后的文件
doFileFinal(Cipher.ENCRYPT_MODE, inFile, outEncryptFile, plainKey, iv);
}
/**
* 對文件進行加解密
*
* @param cipherMode 加密模式,可選值為Cipher.ENCRYPT_MODE或者Cipher.DECRYPT_MODE
* @param infile 待加解密的文件
* @param outFile 加解密后的文件
* @param keyPlain 明文密鑰
* @param iv 初始化向量
*/
static void doFileFinal(int cipherMode, File infile, File outFile, byte[] keyPlain, byte[] iv) {
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(infile));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outFile))) {
final byte[] bytIn = new byte[(int) infile.length()];
final int fileLength = bis.read(bytIn);
assert fileLength > 0;
final SecretKeySpec secretKeySpec = new SecretKeySpec(keyPlain, AES_FLAG);
final Cipher cipher = Cipher.getInstance(AES_ALG);
final GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * Byte.SIZE, iv);
cipher.init(cipherMode, secretKeySpec, gcmParameterSpec);
final byte[] bytOut = cipher.doFinal(bytIn);
bos.write(bytOut);
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
}
解密本地文件
步驟1 請準備基礎認證信息。
- ACCESS_KEY: 帳號Access Key
- SECRET_ACCESS_KEY: 帳號Secret Access Key
- PROJECT_ID: 項目ID
- KMS_ENDPOINT: KMS服務訪問終端地址。
步驟2 解密本地文件。
示例代碼中:
- 用戶主密鑰:控制臺創建的密鑰ID。
- 輸出的密文數據文件:SecondEncryptFile.jpg。
- 加密后再解密的數據文件:ThirdDecryptFile.jpg。
import com.ctyun.sdk.core.auth.BasicCredentials;
import com.ctyun.sdk.kms.v1.KmsClient;
import com.ctyun.sdk.kms.v1.model.CreateDatakeyRequest;
import com.ctyun.sdk.kms.v1.model.CreateDatakeyRequestBody;
import com.ctyun.sdk.kms.v1.model.CreateDatakeyResponse;
import com.ctyun.sdk.kms.v1.model.DecryptDatakeyRequest;
import com.ctyun.sdk.kms.v1.model.DecryptDatakeyRequestBody;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.security.SecureRandom;
/**
* 使用數據密鑰(DEK)進行文件加解密
* 激活assert語法,請在VM_OPTIONS中添加-ea
*/
public class FileStreamEncryptionExample {
private static final String ACCESS_KEY = "<AccessKey>";
private static final String SECRET_ACCESS_KEY = "<SecretAccessKey>";
private static final String PROJECT_ID = "<ProjectID>";
private static final String KMS_ENDPOINT = "<KmsEndpoint>";
// KMS服務接口版本信息,當前固定為v1.0
private static final String KMS_INTERFACE_VERSION = "v1.0";
/**
* AES算法相關標識:
* - AES_KEY_BIT_LENGTH: AES256密鑰比特長度
* - AES_KEY_BYTE_LENGTH: AES256密鑰字節長度
* - AES_ALG: AES256算法,本例分組模式使用GCM,填充使用PKCS5Padding
* - AES_FLAG: AES算法標識
* - GCM_TAG_LENGTH: GCM TAG長度
* - GCM_IV_LENGTH: GCM 初始向量長度
*/
private static final String AES_KEY_BIT_LENGTH = "256";
private static final String AES_KEY_BYTE_LENGTH = "32";
private static final String AES_ALG = "AES/GCM/PKCS5Padding";
private static final String AES_FLAG = "AES";
private static final int GCM_TAG_LENGTH = 16;
private static final int GCM_IV_LENGTH = 12;
public static void main(final String[] args) {
// 您在控制臺創建的用戶主密鑰ID
final String keyId = args[0];
// 創建數據密鑰時,響應的密文數據密鑰
final String cipherText = args[1];
decryptFile(keyId, cipherText);
}
/**
* 使用數據密鑰加解密文件實例
*
* @param keyId 用戶主密鑰ID
* @param cipherText 密文數據密鑰
*/
static void decryptFile(String keyId,String cipherText) {
// 1.準備訪問認證信息
final BasicCredentials auth = new BasicCredentials().withAk(ACCESS_KEY).withSk(SECRET_ACCESS_KEY)
.withProjectId(PROJECT_ID);
// 2.初始化SDK,傳入認證信息及KMS訪問終端地址
final KmsClient kmsClient = KmsClient.newBuilder().withCredential(auth).withEndpoint(KMS_ENDPOINT).build();
// 3.準備待加密的文件
// inFile 待加密的文件
// outEncryptFile 加密后的文件
// outDecryptFile 加密后再解密的文件
final File inFile = new File("FirstPlainFile.jpg");
final File outEncryptFile = new File("SecondEncryptFile.jpg");
final File outDecryptFile = new File("ThirdDecryptFile.jpg");
// 4.使用AES算法進行解密時,初始向量需要與加密時保持一致,此處僅為占位。
final byte[] iv = new byte[GCM_IV_LENGTH];
// 5.組裝解密數據密鑰的請求,其中cipherText為創建數據密鑰時返回的密文數據密鑰。
final DecryptDatakeyRequest decryptDatakeyRequest = new DecryptDatakeyRequest()
.withVersionId(KMS_INTERFACE_VERSION).withBody(new DecryptDatakeyRequestBody()
.withKeyId(keyId).withCipherText(cipherText).withDatakeyCipherLength(AES_KEY_BYTE_LENGTH));
// 6.解密數據密鑰,并對返回的16進制明文密鑰換成byte數組
final byte[] decryptDataKey = hexToBytes(kmsClient.decryptDatakey(decryptDatakeyRequest).getDataKey());
// 7.對文件進行解密,并存儲解密后的文件
// 句末的iv為加密示例中創建的初始向量
doFileFinal(Cipher.DECRYPT_MODE, outEncryptFile, outDecryptFile, decryptDataKey, iv);
// 8.比對原文件和加密后再解密的文件
assert getFileSha256Sum(inFile).equals(getFileSha256Sum(outDecryptFile));
}
/**
* 對文件進行加解密
*
* @param cipherMode 加密模式,可選值為Cipher.ENCRYPT_MODE或者Cipher.DECRYPT_MODE
* @param infile 待加解密的文件
* @param outFile 加解密后的文件
* @param keyPlain 明文密鑰
* @param iv 初始化向量
*/
static void doFileFinal(int cipherMode, File infile, File outFile, byte[] keyPlain, byte[] iv) {
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(infile));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outFile))) {
final byte[] bytIn = new byte[(int) infile.length()];
final int fileLength = bis.read(bytIn);
assert fileLength > 0;
final SecretKeySpec secretKeySpec = new SecretKeySpec(keyPlain, AES_FLAG);
final Cipher cipher = Cipher.getInstance(AES_ALG);
final GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * Byte.SIZE, iv);
cipher.init(cipherMode, secretKeySpec, gcmParameterSpec);
final byte[] bytOut = cipher.doFinal(bytIn);
bos.write(bytOut);
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
/**
* 十六進制字符串轉byte數組
*
* @param hexString 十六進制字符串
* @return byte數組
*/
static byte[] hexToBytes(String hexString) {
final int stringLength = hexString.length();
assert stringLength > 0;
final byte[] result = new byte[stringLength / 2];
int j = 0;
for (int i = 0; i < stringLength; i += 2) {
result[j++] = (byte) Integer.parseInt(hexString.substring(i, i + 2), 16);
}
return result;
}
/**
* 計算文件SHA256摘要
*
* @param file 文件
* @return SHA256摘要
*/
static String getFileSha256Sum(File file) {
int length;
MessageDigest sha256;
byte[] buffer = new byte[1024];
try {
sha256 = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e.getMessage());
}
try (FileInputStream inputStream = new FileInputStream(file)) {
while ((length = inputStream.read(buffer)) != -1) {
sha256.update(buffer, 0, length);
}
return new BigInteger(1, sha256.digest()).toString(16);
} catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
}
}