This topic provides Java code examples that demonstrate how to use Key Management Service (KMS) SDK to manage encryption keys and perform cryptographic operations. The examples cover two authentication methods: AccessKey-based access over a public or Virtual Private Cloud (VPC) endpoint, and client key-based access through an application access point (AAP).
Key concepts
Before you work with the code examples, familiarize yourself with the following KMS concepts:
| Concept | Description |
|---|---|
| Customer master key (CMK) | A primary encryption key that you create and manage in KMS. CMKs are used to encrypt data directly or to generate data keys for envelope encryption. |
| Data key | A key generated by KMS that you use to encrypt large volumes of data locally. The GenerateDataKey operation returns both a plaintext data key and a ciphertext copy encrypted under a specified CMK. |
| Public endpoint vs. VPC endpoint | You can access KMS through a public endpoint over the internet, or through a VPC endpoint for private network access within a Virtual Private Cloud (VPC). |
| Application access point (AAP) | An access control mechanism in KMS that enables applications to authenticate using a client key instead of an AccessKey pair. |
Prerequisites
Before you run the code examples, ensure that the following requirements are met:
JDK 8 or later is installed.
Maven or Gradle is installed for dependency management.
An Alibaba Cloud account is created and KMS is activated.
A RAM user is created with the required KMS permissions. For security, do not use your Alibaba Cloud account AccessKey pair directly.
At least one CMK exists in the target region (required for Example 1).
The AccessKey pair is stored in the
ALIBABA_CLOUD_ACCESS_KEY_IDandALIBABA_CLOUD_ACCESS_KEY_SECRETenvironment variables. For more information, see Credentials.
Add SDK dependencies
Add the KMS SDK for Java and the Alibaba Cloud core SDK to your project. The following table lists the required dependencies.
| Dependency | Group ID | Artifact ID | Version |
|---|---|---|---|
| Alibaba Cloud core SDK | com.aliyun | aliyun-java-sdk-core | 4.5.2 |
| KMS SDK | com.aliyun | aliyun-java-sdk-kms | 2.15.0 |
For more information about SDK versions, see SDK overview.
Maven
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.2</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-kms</artifactId>
<version>2.15.0</version>
</dependency>Gradle
implementation 'com.aliyun:aliyun-java-sdk-core:4.5.2'
implementation 'com.aliyun:aliyun-java-sdk-kms:2.15.0'Configure the KMS endpoint
The KMS endpoint determines how the SDK connects to the service. For more information, see Make API requests.
| Access method | Configuration |
|---|---|
| Public endpoint | Specify only the region ID. The SDK automatically resolves the public endpoint for that region. |
| VPC endpoint | Explicitly specify the VPC endpoint to access KMS from within a Virtual Private Cloud (VPC). |
Example 1: Access KMS over a public endpoint or a VPC endpoint
This example demonstrates how to create a KMS client and call common operations such as listing CMKs, describing a key, generating a data key, encrypting data, and decrypting data.
The AccessKey pair of an Alibaba Cloud account has permissions on all API operations. Using the AccessKey pair to perform operations is a high-risk operation. We recommend that you use a RAM user to call API operations or perform routine O&M. We recommend that you do not save the AccessKey ID and AccessKey secret in your project code. Otherwise, the AccessKey pair may be leaked and the security of all resources within your account may be compromised. In this example, the AccessKey pair is stored in the ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variables. For more information about how to configure authentication, see Credentials.
If the data that you want to encrypt contains special characters <>&, we recommend that you set FormatType to XML to decrypt the data. This helps prevent errors caused by character escaping during decryption. For example, specify decReq.setAcceptFormat(FormatType.XML).
Step 1: Create a KMS client wrapper
The following KmsClient class provides two factory methods for creating a KMS client and wraps six common KMS operations.
| Factory method | Access type | Description |
|---|---|---|
getClientForPublicEndpoint | Public endpoint | The SDK automatically resolves the public endpoint based on the region ID. |
getClientForVpcEndpoint | VPC endpoint | Use this method when your application runs inside a VPC. Requires an explicit endpoint URL. |
Wrapped operations:
| Method | Description |
|---|---|
CreateKey | Creates a CMK in KMS. |
DescribeKey | Queries the metadata of a CMK. |
ListKey | Lists CMKs in the current region with pagination. |
GenerateDataKey | Generates a data key encrypted under a specified CMK. |
Encrypt | Encrypts plaintext using the specified CMK. |
Decrypt | Decrypts ciphertext that was encrypted by KMS. |
package com.aliyun.kms.samples;
import java.util.*;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.*;
// Current KMS SDK version: 2016-01-20
import com.aliyuncs.kms.model.v20160120.*;
import com.aliyuncs.kms.model.v20160120.ListKeysResponse.Key;
import com.aliyuncs.profile.*;
public class KmsClient
{
private DefaultAcsClient kmsClient;
/**
* Creates a KMS client that connects through the public endpoint.
* The SDK automatically resolves the public endpoint based on the region ID.
*
* @param regionId the region where KMS is deployed, for example, cn-hangzhou
* @param accessKeyId the AccessKey ID for authentication
* @param accessKeySecret the AccessKey secret for authentication
* @return a KmsClient instance configured for public endpoint access
*/
public static KmsClient getClientForPublicEndpoint(String regionId, String accessKeyId, String accessKeySecret) {
/**
* Construct an Alibaba Cloud client:
* Set RegionId, AccessKeyId and AccessKeySecret
*/
IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
DefaultAcsClient client = new DefaultAcsClient(profile);
return new KmsClient(client);
}
/**
* Creates a KMS client that connects through a VPC endpoint.
* Use this method when your application runs inside a Virtual Private Cloud (VPC).
*
* @param regionId the region where KMS is deployed
* @param accessKeyId the AccessKey ID for authentication
* @param accessKeySecret the AccessKey secret for authentication
* @param endpoint the VPC endpoint, for example, kms-vpc.cn-hangzhou.aliyuncs.com
* @return a KmsClient instance configured for VPC endpoint access
*/
public static KmsClient getClientForVpcEndpoint(String regionId, String accessKeyId, String accessKeySecret, String endpoint) {
// Specify a VPC endpoint.
DefaultProfile.addEndpoint(regionId, "kms", endpoint);
IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
HttpClientConfig clientConfig = HttpClientConfig.getDefault();
profile.setHttpClientConfig(clientConfig);
DefaultAcsClient client = new DefaultAcsClient(profile);
return new KmsClient(client);
}
private KmsClient(DefaultAcsClient acsClient) {
this.kmsClient = acsClient;
}
/**
* Creates a CMK in KMS.
*
* @param keyDesc a description for the CMK
* @param keyUsage the intended use of the CMK, for example, ENCRYPT/DECRYPT
* @return CreateKeyResponse containing the metadata of the new CMK
* @throws ClientException if the request fails
*/
public CreateKeyResponse CreateKey(String keyDesc, String keyUsage) throws ClientException {
final CreateKeyRequest ckReq = new CreateKeyRequest();
ckReq.setProtocol(ProtocolType.HTTPS);
ckReq.setAcceptFormat(FormatType.JSON);
ckReq.setMethod(MethodType.POST);
ckReq.setDescription(keyDesc);
ckReq.setKeyUsage(keyUsage);
final CreateKeyResponse response = kmsClient.getAcsResponse(ckReq);
return response;
}
/**
* Queries the metadata of a CMK.
*
* @param keyId the globally unique ID of the CMK
* @return DescribeKeyResponse containing the CMK metadata
* @throws ClientException if the request fails
*/
public DescribeKeyResponse DescribeKey(String keyId) throws ClientException {
final DescribeKeyRequest decKeyReq = new DescribeKeyRequest();
decKeyReq.setProtocol(ProtocolType.HTTPS);
decKeyReq.setAcceptFormat(FormatType.JSON);
decKeyReq.setMethod(MethodType.POST);
decKeyReq.setKeyId(keyId);
final DescribeKeyResponse decKeyRes = kmsClient.getAcsResponse(decKeyReq);
return decKeyRes;
}
/**
* Lists CMKs in the current region with pagination.
*
* @param pageNumber the page number to retrieve (starting from 1)
* @param pageSize the number of CMKs to return per page
* @return ListKeysResponse containing the paginated list of CMKs
* @throws ClientException if the request fails
*/
public ListKeysResponse ListKey(int pageNumber, int pageSize) throws ClientException {
final ListKeysRequest listKeysReq = new ListKeysRequest();
listKeysReq.setProtocol(ProtocolType.HTTPS);
listKeysReq.setAcceptFormat(FormatType.JSON);
listKeysReq.setMethod(MethodType.POST);
listKeysReq.setPageNumber(pageNumber);
listKeysReq.setPageSize(pageSize);
final ListKeysResponse listKeysRes = kmsClient.getAcsResponse(listKeysReq);
return listKeysRes;
}
/**
* Generates a data key that is encrypted under a specified CMK.
* Returns both the plaintext data key and its ciphertext copy.
*
* @param keyId the ID of the CMK used to encrypt the data key
* @param keyDesc the key spec, for example, AES_256
* @param numOfBytes the length of the data key in bytes
* @return GenerateDataKeyResponse containing the plaintext and ciphertext data key
* @throws ClientException if the request fails
*/
public GenerateDataKeyResponse GenerateDataKey(String keyId, String keyDesc, int numOfBytes) throws ClientException {
final GenerateDataKeyRequest genDKReq = new GenerateDataKeyRequest();
genDKReq.setProtocol(ProtocolType.HTTPS);
genDKReq.setAcceptFormat(FormatType.JSON);
genDKReq.setMethod(MethodType.POST);
/**
* Set parameters according to the KMS API documentation:
* 1. KeyId
* 2. KeySpec
* 3. NumberOfBytes
*/
genDKReq.setKeySpec(keyDesc);
genDKReq.setKeyId(keyId);
genDKReq.setNumberOfBytes(numOfBytes);
final GenerateDataKeyResponse genDKRes = kmsClient.getAcsResponse(genDKReq);
return genDKRes;
}
/**
* Encrypts plaintext using the specified CMK.
*
* @param keyId the ID of the CMK used for encryption
* @param plainText the plaintext data to encrypt
* @return EncryptResponse containing the ciphertext blob
* @throws ClientException if the request fails
*/
public EncryptResponse Encrypt(String keyId, String plainText) throws ClientException {
final EncryptRequest encReq = new EncryptRequest();
encReq.setProtocol(ProtocolType.HTTPS);
encReq.setAcceptFormat(FormatType.JSON);
encReq.setMethod(MethodType.POST);
encReq.setKeyId(keyId);
encReq.setPlaintext(plainText);
final EncryptResponse encResponse = kmsClient.getAcsResponse(encReq);
return encResponse;
}
/**
* Decrypts ciphertext that was encrypted by KMS.
*
* @param cipherBlob the ciphertext blob to decrypt
* @return DecryptResponse containing the recovered plaintext
* @throws ClientException if the request fails
*/
public DecryptResponse Decrypt(String cipherBlob) throws ClientException {
final DecryptRequest decReq = new DecryptRequest();
decReq.setProtocol(ProtocolType.HTTPS);
decReq.setAcceptFormat(FormatType.JSON);
decReq.setMethod(MethodType.POST);
decReq.setCiphertextBlob(cipherBlob);
final DecryptResponse decResponse = kmsClient.getAcsResponse(decReq);
return decResponse;
}
}Step 2: Call KMS operations
The following KmsSample class uses the KmsClient wrapper to demonstrate five operations: listing CMKs, describing a CMK, generating a data key, encrypting plaintext, and decrypting ciphertext.
This sample requires your Alibaba Cloud account to have at least one CMK in the China (Hangzhou) region.
The
KmsClient.getClientForPublicEndpointmethod connects through the public endpoint.The
KmsClient.getClientForVpcEndpointmethod connects through the VPC endpoint.
package com.aliyun.kms.samples;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.google.gson.Gson;
import java.util.*;
import com.aliyuncs.kms.model.v20160120.*;
import com.aliyuncs.kms.model.v20160120.ListKeysResponse.Key;
public class KmsSample {
public static void main(String[] args) {
String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
KmsClient kmsClient = KmsClient.getClientForPublicEndpoint("cn-hangzhou", accessKeyId, accessKeySecret);
//KmsClient kmsClient = KmsClient.getClientForVpcEndpoint("cn-hangzhou-vpc", accessKeyId, accessKeySecret, "kms-vpc.cn-hangzhou.aliyuncs.com");
String keyId = null;
String plainText = "hello world";
String cipherBlob = null;
/* List all CMKs in your account */
try {
final ListKeysResponse listKeysRes = kmsClient.ListKey(1, 100);
/**
* Parse the response
*/
System.out.println("TotalCount: " + listKeysRes.getTotalCount());
System.out.println("PageNumber: " + listKeysRes.getPageNumber());
System.out.println("PageSize: " + listKeysRes.getPageSize());
List<Key> keys = listKeysRes.getKeys();
Iterator<Key> iterator = keys.iterator();
while (iterator.hasNext()) {
keyId = iterator.next().getKeyId();
System.out.println("KeyId: " + keyId);
}
System.out.println("List all CMKs success!\n");
} catch (ClientException eResponse) {
System.out.println("Failed.");
System.out.println("Error code: " + eResponse.getErrCode());
System.out.println("Error message: " + eResponse.getErrMsg());
}
/* Describe the CMK */
try {
final DescribeKeyResponse decKeyRes = kmsClient.DescribeKey(keyId);
/**
* Parse the response
*/
System.out.println("DescribeKey Response: ");
DescribeKeyResponse.KeyMetadata meta = decKeyRes.getKeyMetadata();
System.out.println("KeyId: " + meta.getKeyId());
System.out.println("Description: " + meta.getDescription());
System.out.println("KeyState: " + meta.getKeyState());
System.out.println("KeyUsage: " + meta.getKeyUsage());
System.out.println("===========================================");
System.out.println("Describe the CMK success!");
System.out.println("===========================================\n");
} catch (ClientException eResponse) {
System.out.println("Failed.");
System.out.println("Error code: " + eResponse.getErrCode());
System.out.println("Error message: " + eResponse.getErrMsg());
}
/* Generate a data key */
/**
* Request and process the response
*/
try {
final GenerateDataKeyResponse genDKResponse = kmsClient.GenerateDataKey(keyId, "AES_256", 64);
/**
* Parse the response
*/
System.out.println("CiphertextBlob: " + genDKResponse.getCiphertextBlob());
System.out.println("KeyId: " + genDKResponse.getKeyId());
System.out.println("Plaintext: " + genDKResponse.getPlaintext());
System.out.println("===========================================");
System.out.println("Generate data key success!");
System.out.println("===========================================\n");
} catch (ClientException eResponse) {
System.out.println("Failed.");
System.out.println("Error code: " + eResponse.getErrCode());
System.out.println("Error message: " + eResponse.getErrMsg());
}
/**
* Encrypt the plaintext and obtain the ciphertext
*/
try {
EncryptResponse encResponse = kmsClient.Encrypt(keyId, plainText);
cipherBlob = encResponse.getCiphertextBlob();
System.out.println("CiphertextBlob: " + cipherBlob);
System.out.println("KeyId: " + encResponse.getKeyId());
System.out.println("===========================================");
System.out.println("Encrypt the plaintext success!");
System.out.println("===========================================\n");
} catch (ClientException eResponse) {
System.out.println("Failed.");
System.out.println("Error code: " + eResponse.getErrCode());
System.out.println("Error message: " + eResponse.getErrMsg());
}
/**
* Decrypt the ciphertext and verify that the result matches the original plaintext.
*/
try {
DecryptResponse decResponse = kmsClient.Decrypt(cipherBlob);
System.out.println("Plaintext: " + decResponse.getPlaintext());
String verifyPlainText = decResponse.getPlaintext();
int isMatch = verifyPlainText.compareTo(plainText);
System.out.println("KeyId: " + decResponse.getKeyId());
System.out.println("===========================================");
System.out.printf("Decrypt the ciphertext success, result " + (isMatch == 0 ? "match" : "mismatch" + "\n"));
System.out.println("===========================================\n");
} catch (ClientException eResponse) {
System.out.println("Failed.");
System.out.println("Error code: " + eResponse.getErrCode());
System.out.println("Error message: " + eResponse.getErrMsg());
}
}
}Example 2: Access Secrets Manager by using a client key-based AAP
If you use KMS SDK for Java to access Secrets Manager through a client key-based application access point (AAP), you can use the following code. For more information, see Bind a client key to the AAP.
This example consists of three classes:
| Class | Purpose |
|---|---|
ClientKeySample | Main sample class. Creates a KMS client that authenticates using a client key file and its password. |
ClientKeyUtils | Utility class. Reads a client key JSON file, extracts the private key from the embedded PKCS12 data, and returns a credentials provider. |
ClientKeyCredentialsProvider | Credentials provider. Implements AlibabaCloudCredentialsProvider to supply key-pair credentials to the SDK client. |
ClientKeySample (main class)
The following ClientKeySample class shows how to create a KMS client that authenticates using a client key file and its password.
package com.aliyuncs.kms.sample;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.auth.AlibabaCloudCredentialsProvider;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.kms.clientkey.utils.ClientKeyUtils;
import java.io.IOException;
public class ClientKeySample {
public static void main(String[] args) throws IOException {
String clientKeyPath = "<client-key-file-path>";
String password = System.getenv("<client-key-password-env-name>");
AlibabaCloudCredentialsProvider provider = ClientKeyUtils.getCredentialsProvider(clientKeyPath, password);
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou");
IAcsClient kmsClient = new DefaultAcsClient(profile, provider);
// invoke kmsClient
}
}ClientKeyUtils (utility class)
The ClientKeyUtils class reads a client key JSON file, extracts the private key from the embedded PKCS12 data, and returns a credentials provider.
package com.aliyuncs.kms.clientkey.utils;
import com.aliyuncs.auth.AlibabaCloudCredentialsProvider;
import com.aliyuncs.kms.auth.ClientKeyCredentialsProvider;
import com.aliyuncs.auth.KeyPairCredentials;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import java.io.*;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.Base64;
import java.util.Enumeration;
public class ClientKeyUtils {
private final static String PKCS12 = "PKCS12";
private final static Gson gson = new Gson();
private ClientKeyUtils() {
// do nothing
}
/**
* Builds a credentials provider from a client key file.
*
* @param clientKeyFileName the path to the client key JSON file
* @param password the password for the PKCS12 private key
* @return an AlibabaCloudCredentialsProvider backed by the client key
* @throws IOException if the file cannot be read or the key is invalid
*/
public static AlibabaCloudCredentialsProvider getCredentialsProvider(String clientKeyFileName, String password) throws IOException {
try (Reader reader = new InputStreamReader(new FileInputStream(clientKeyFileName), "utf-8")) {
ClientKeyInfo clientKeyInfo = gson.fromJson(reader, ClientKeyInfo.class);
if (clientKeyInfo != null) {
byte[] pk12 = Base64.getDecoder().decode(clientKeyInfo.getPrivateKeyData());
try {
String privateKey = getPrivateKeyPemFromPk12(pk12, password);
return new ClientKeyCredentialsProvider(new KeyPairCredentials(clientKeyInfo.getKeyId(), privateKey));
} catch (Exception e) {
throw new IOException(e);
}
} else {
throw new IOException("ClientKey is invalid");
}
}
}
private static String getPrivateKeyPemFromPk12(byte[] pk12, String password) throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException, UnrecoverableKeyException {
KeyStore keyStore = KeyStore.getInstance(PKCS12);
keyStore.load(new ByteArrayInputStream(pk12), password.toCharArray());
Enumeration<String> e = keyStore.aliases();
String alias = e.nextElement();
PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, password.toCharArray());
return Base64.getEncoder().encodeToString(privateKey.getEncoded());
}
}
class ClientKeyInfo {
@SerializedName("KeyId")
private String keyId;
@SerializedName("PrivateKeyData")
private String privateKeyData;
public String getKeyId() {
return this.keyId;
}
public void setKeyId(String keyId) {
this.keyId = keyId;
}
public String getPrivateKeyData() {
return this.privateKeyData;
}
public void setPrivateKeyData(String privateKeyData) {
this.privateKeyData = privateKeyData;
}
}ClientKeyCredentialsProvider (credentials provider)
The ClientKeyCredentialsProvider class implements AlibabaCloudCredentialsProvider to supply key-pair credentials to the SDK client.
package com.aliyuncs.kms.auth;
import com.aliyuncs.auth.AlibabaCloudCredentials;
import com.aliyuncs.auth.AlibabaCloudCredentialsProvider;
import com.aliyuncs.auth.KeyPairCredentials;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
public class ClientKeyCredentialsProvider implements AlibabaCloudCredentialsProvider {
private KeyPairCredentials keyPairCredentials;
public ClientKeyCredentialsProvider() {
}
public ClientKeyCredentialsProvider(KeyPairCredentials keyPairCredentials) {
this.keyPairCredentials = keyPairCredentials;
}
@Override
public AlibabaCloudCredentials getCredentials() throws ClientException, ServerException {
return this.keyPairCredentials;
}
}What's next
View additional sample code for KMS SDK in different programming languages and scenarios in the open source code repository.
For a complete list of KMS API operations, see List of operations by function.
Learn how to implement envelope encryption to protect data that exceeds the size limit for direct encryption.
Explore integration with other Alibaba Cloud services such as OSS server-side encryption and RDS Transparent Data Encryption (TDE).