By Sai Sarath Chandra Alibaba Cloud Tech Share Author and Alibaba Cloud MVP
In this tutorial, we will explore how to use the Alibaba Cloud Key Management Service (KMS) to create, control, and manage your encryption keys on your mobile device.
Prerequsities:
• You need an Alibaba Cloud Account. If you need you can get one with $300 by signing up here.
• Need Android Studio 3.0.0
• Basic knowledge of Android/Java.
Tutorial:
1. Activate KMS Service
a.Please login to Alibaba Cloud and Navigate to console and Click on KMS Service.
b.Activate the service
c.Please make a note of the region you want to create the keys in. I created in the "Hangzhou" region.
2. Creating Android Project
a.Create an Android Project with the name you want. I gave the name "KMSSample".
b.Select the Min SDK and the Device compatibility, I am targeting the devices with minimum API level 19 and later. With only phones and tablets.
c.Select Empty activity and proceed further.
d.Keep all the defaults as shown click finish.
3. Setting up Code:
a.We have only one java file and the whole code related to application will be in one single file. We need to update the code in the MainActivity.java. We will go through the detailed walkthrough later. Please copy the below code into the MainActivity.java file
package sample.alibabacloud.kmssample;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.design.widget.TextInputEditText;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.FormatType;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.kms.model.v20160120.CreateKeyRequest;
import com.aliyuncs.kms.model.v20160120.CreateKeyResponse;
import com.aliyuncs.kms.model.v20160120.DecryptRequest;
import com.aliyuncs.kms.model.v20160120.DecryptResponse;
import com.aliyuncs.kms.model.v20160120.DescribeKeyRequest;
import com.aliyuncs.kms.model.v20160120.DescribeKeyResponse;
import com.aliyuncs.kms.model.v20160120.EncryptRequest;
import com.aliyuncs.kms.model.v20160120.EncryptResponse;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
static DefaultAcsClient kmsClient;
private static final String TAG = "MainActivity";
String regionId ;
String accessKeyId ;
String accessKeySecret ;
TextView output;
TextInputEditText userName,passWord,email,address;
Button eCredentials,dCredentials, eForm, dForm;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
regionId = getString(R.string.regionId);
accessKeyId = getString(R.string.AccessKey);
accessKeySecret = getString(R.string.AccessKeySecret);
output = findViewById(R.id.output);
userName = findViewById(R.id.userName);
passWord = findViewById(R.id.passWord);
email = findViewById(R.id.email);
address = findViewById(R.id.address);
eCredentials = findViewById(R.id.eCredentials);
dCredentials = findViewById(R.id.dCredentials);
eForm = findViewById(R.id.eForm);
dForm = findViewById(R.id.dForm);
eCredentials.setOnClickListener(this);
dCredentials.setOnClickListener(this);
eForm.setOnClickListener(this);
dForm.setOnClickListener(this);
Log.d(TAG, "===========================================");
Log.d(TAG, "KMS Service started");
Log.d(TAG, "===========================================\n");
/**
* RegionId: "cn-hangzhou" and "ap-southeast-1", eg. "cn-hangzhou"
*/
kmsClient = kmsClient(regionId, accessKeyId, accessKeySecret);
}
private static DefaultAcsClient kmsClient(String regionId, String accessKeyId, String accessKeySecret) {
/**
* Construct an Aliyun Client:
* Set RegionId, AccessKeyId and AccessKeySecret
*/
IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
DefaultAcsClient client = new DefaultAcsClient(profile);
return client;
}
private static 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;
}
private static 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;
}
private static 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;
}
private static 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;
}
@Override
public void onClick(View view) {
int id = view.getId();
if(id == R.id.eCredentials){
EncryptCredentials encryptCredentials = new EncryptCredentials();
encryptCredentials.execute(kmsClient);
}else if(id == R.id.dCredentials){
DecryptCredentials decryptCredentials = new DecryptCredentials(this);
decryptCredentials.execute(kmsClient);
}else if(id == R.id.eForm){
EncryptFormData encryptFormData = new EncryptFormData();
encryptFormData.execute(kmsClient);
}else if(id == R.id.dForm) {
DecryptFormData decryptFormData = new DecryptFormData(this);
decryptFormData.execute(kmsClient);
}
}
class EncryptCredentials extends AsyncTask<DefaultAcsClient,Void,Void>{
String keyId = null;
String cipherBlob = null;
@Override
protected Void doInBackground(DefaultAcsClient... defaultAcsClients) {
kmsClient = defaultAcsClients[0];
/*Create a Key*/
try {
final CreateKeyResponse response = CreateKey("testkey", "ENCRYPT/DECRYPT");
/**
* Parse response and do more further
*/
System.out.println(response.getKeyMetadata());
CreateKeyResponse.KeyMetadata meta = response.getKeyMetadata();
System.out.println("CreateTime: " + meta.getCreationDate());
System.out.println("Description: " + meta.getDescription());
System.out.println("KeyId: " + meta.getKeyId());
keyId = meta.getKeyId();
System.out.println("KeyState: " + meta.getKeyState());
System.out.println("KeyUsage: " + meta.getKeyUsage());
System.out.println("===========================================");
System.out.println("Create MasterKey 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());
}
/*Describe the Key */
try {
final DescribeKeyResponse decKeyRes = DescribeKey(keyId);
/**
* Parse response and do more further
*/
Log.d(TAG, "DescribeKey Response: ");
DescribeKeyResponse.KeyMetadata meta = decKeyRes.getKeyMetadata();
Log.d(TAG, "KeyId: " + meta.getKeyId());
Log.d(TAG, "Description: " + meta.getDescription());
Log.d(TAG, "KeyState: " + meta.getKeyState());
Log.d(TAG, "KeyUsage: " + meta.getKeyUsage());
Log.d(TAG, "===========================================");
Log.d(TAG, "Describe the MasterKey success!");
Log.d(TAG, "===========================================\n");
} catch (ClientException eResponse) {
Log.d(TAG, "Failed.");
Log.d(TAG, "Error code: " + eResponse.getErrCode());
Log.d(TAG, "Error message: " + eResponse.getErrMsg());
}
/**
* Encrypt the plain text and got a cipher one
*/
try {
EncryptResponse encResponse = Encrypt(keyId, getCredentials());
cipherBlob = encResponse.getCiphertextBlob();
Log.d(TAG, "CiphertextBlob: " + cipherBlob);
runOnUiThread(new Runnable() {
@Override
public void run() {
output.setText("The Encrypt Credentials are\n"+cipherBlob);
setEncryptCredentials(cipherBlob);
}
});
Log.d(TAG, "KeyId: " + encResponse.getKeyId());
Log.d(TAG, "===========================================");
Log.d(TAG, "Encrypt the plain text success!");
Log.d(TAG, "===========================================\n");
} catch (ClientException eResponse) {
Log.d(TAG, "Failed.");
Log.d(TAG, "Error code: " + eResponse.getErrCode());
Log.d(TAG, "Error message: " + eResponse.getErrMsg());
}
return null;
}
}
class DecryptCredentials extends AsyncTask<DefaultAcsClient,Void,Void>{
public MainActivity mainActivity;
public DecryptCredentials(MainActivity activity){
this.mainActivity = activity;
}
@Override
protected Void doInBackground(DefaultAcsClient... defaultAcsClients) {
try {
final DecryptResponse decResponse = Decrypt(mainActivity.getEncryptCredentials());
Log.d(TAG, "Plaintext: " + decResponse.getPlaintext());
String verifyPlainText = decResponse.getPlaintext();
runOnUiThread(new Runnable() {
@Override
public void run() {
output.setText("The Decrypt Credentials are \n"+decResponse.getPlaintext());
}
});
int isMatch = verifyPlainText.compareTo(mainActivity.getCredentials());
Log.d(TAG, "KeyId: " + decResponse.getKeyId());
Log.d(TAG, "===========================================");
Log.d(TAG, "Decrypt the cipher text success, result " + (isMatch == 0 ? "match" : "mismatch" + "\n"));
Log.d(TAG, "===========================================\n");
} catch (ClientException eResponse) {
Log.d(TAG, "Failed.");
Log.d(TAG, "Error code: " + eResponse.getErrCode());
Log.d(TAG, "Error message: " + eResponse.getErrMsg());
}
return null;
}
}
class EncryptFormData extends AsyncTask<DefaultAcsClient,Void,Void>{
String keyId = null;
String cipherBlob = null;
@Override
protected Void doInBackground(DefaultAcsClient... defaultAcsClients) {
kmsClient = defaultAcsClients[0];
/*Create a Key*/
try {
final CreateKeyResponse response = CreateKey("testkey", "ENCRYPT/DECRYPT");
/**
* Parse response and do more further
*/
System.out.println(response.getKeyMetadata());
CreateKeyResponse.KeyMetadata meta = response.getKeyMetadata();
System.out.println("CreateTime: " + meta.getCreationDate());
System.out.println("Description: " + meta.getDescription());
System.out.println("KeyId: " + meta.getKeyId());
keyId = meta.getKeyId();
System.out.println("KeyState: " + meta.getKeyState());
System.out.println("KeyUsage: " + meta.getKeyUsage());
System.out.println("===========================================");
System.out.println("Create MasterKey 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());
}
/*Describe the Key */
try {
final DescribeKeyResponse decKeyRes = DescribeKey(keyId);
/**
* Parse response and do more further
*/
Log.d(TAG, "DescribeKey Response: ");
DescribeKeyResponse.KeyMetadata meta = decKeyRes.getKeyMetadata();
Log.d(TAG, "KeyId: " + meta.getKeyId());
Log.d(TAG, "Description: " + meta.getDescription());
Log.d(TAG, "KeyState: " + meta.getKeyState());
Log.d(TAG, "KeyUsage: " + meta.getKeyUsage());
Log.d(TAG, "===========================================");
Log.d(TAG, "Describe the MasterKey success!");
Log.d(TAG, "===========================================\n");
} catch (ClientException eResponse) {
Log.d(TAG, "Failed.");
Log.d(TAG, "Error code: " + eResponse.getErrCode());
Log.d(TAG, "Error message: " + eResponse.getErrMsg());
}
/**
* Encrypt the plain text and got a cipher one
*/
try {
EncryptResponse encResponse = Encrypt(keyId, getFormData());
cipherBlob = encResponse.getCiphertextBlob();
Log.d(TAG, "CiphertextBlob: " + cipherBlob);
runOnUiThread(new Runnable() {
@Override
public void run() {
output.setText("The Encrypt Credentials are\n"+cipherBlob);
setEncryptedFormData(cipherBlob);
}
});
Log.d(TAG, "KeyId: " + encResponse.getKeyId());
Log.d(TAG, "===========================================");
Log.d(TAG, "Encrypt the plain text success!");
Log.d(TAG, "===========================================\n");
} catch (ClientException eResponse) {
Log.d(TAG, "Failed.");
Log.d(TAG, "Error code: " + eResponse.getErrCode());
Log.d(TAG, "Error message: " + eResponse.getErrMsg());
}
return null;
}
}
class DecryptFormData extends AsyncTask<DefaultAcsClient,Void,Void>{
private MainActivity mainActivity;
public DecryptFormData(MainActivity activity){
this.mainActivity = activity;
}
@Override
protected Void doInBackground(DefaultAcsClient... defaultAcsClients) {
try {
final DecryptResponse decResponse = Decrypt(mainActivity.getEncryptedFormData());
Log.d(TAG, "Plaintext: " + decResponse.getPlaintext());
String verifyPlainText = decResponse.getPlaintext();
runOnUiThread(new Runnable() {
@Override
public void run() {
output.setText("The Decrypt Credentials are \n"+decResponse.getPlaintext());
}
});
int isMatch = verifyPlainText.compareTo(mainActivity.getCredentials());
Log.d(TAG, "KeyId: " + decResponse.getKeyId());
Log.d(TAG, "===========================================");
Log.d(TAG, "Decrypt the cipher text success, result " + (isMatch == 0 ? "match" : "mismatch" + "\n"));
Log.d(TAG, "===========================================\n");
} catch (ClientException eResponse) {
Log.d(TAG, "Failed.");
Log.d(TAG, "Error code: " + eResponse.getErrCode());
Log.d(TAG, "Error message: " + eResponse.getErrMsg());
}
return null;
}
}
public String getCredentials(){
return userName.getText() + "\n" +passWord.getText();
}
public void setEncryptCredentials(String credentials){
SharedPreferences sharedPreferences = getSharedPreferences(getString(R.string.FILE_NAME),MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(getString(R.string.CREDENTIALS),credentials);
editor.apply();
}
public String getEncryptCredentials(){
SharedPreferences sharedPreferences = getSharedPreferences(getString(R.string.FILE_NAME),MODE_PRIVATE);
return sharedPreferences.getString(getString(R.string.CREDENTIALS), null);
}
public String getFormData(){
return userName.getText()+"\n"+passWord.getText()+"\n"+email.getText()+"\n"+address.getText();
}
public void setEncryptedFormData(String formData){
SharedPreferences sharedPreferences = getSharedPreferences(getString(R.string.FILE_NAME),MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(getString(R.string.FORM_DATA),formData);
editor.apply();
}
public String getEncryptedFormData(){
SharedPreferences sharedPreferences = getSharedPreferences(getString(R.string.FILE_NAME),MODE_PRIVATE);
return sharedPreferences.getString(getString(R.string.FORM_DATA), null);
}
}
b.We have only one activity_main.xml file which has the all the UI related code "activity_main.xml".Please copy the below code and paste in the corresponding activity file.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="12dp"
tools:context="sample.alibabacloud.kmssample.MainActivity">
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/userNameLayout"
android:layout_marginBottom="8dp">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/userName"
android:hint="Enter UserName"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:id="@+id/passWordLayout"
android:layout_below="@id/userNameLayout"
>
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/passWord"
android:hint="Enter Password"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:id="@+id/emailLayout"
android:layout_below="@id/passWordLayout">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress"
android:id="@+id/email"
android:hint="Enter Email"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:id="@+id/addressLayout"
android:layout_below="@id/emailLayout">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:id="@+id/address"
android:layout_height="wrap_content"
android:inputType="text"
android:hint="Enter Address"/>
</android.support.design.widget.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="@+id/btnLayout"
android:layout_marginBottom="12dp"
android:layout_below="@id/addressLayout">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/eCredentials"
android:text="Encrypt Credentials"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/dCredentials"
android:text="Decrypt \n Credentials"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/eForm"
android:text="Encrypt Form"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/dForm"
android:text="Decrypt Form"/>
</LinearLayout>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:layout_below="@id/btnLayout"
android:id="@+id/output"
android:textSize="14sp"
android:textColor="#000000"
android:text="The O/P is"/>
</RelativeLayout>
c.Now we need to udpate the strings.xml file with the relevant details.
<resources>
<string name="app_name">KMSSample</string>
<!-- Alibaba KMS Service details-->
<!-- Please replace this details with your own-->
<!--Public Endpoint-->
<string name="regionId">UPDATE YOUR REGION ID HERE Ex. cn-hangzhou</string>
<!-- Access ID -->
<string name="AccessKey">UPDATE YOUR ACCESS ID</string>
<!-- Access key Secret -->
<string name="AccessKeySecret">UPDATE YOUR ACCESS KEY HERE</string>
<string name="FILE_NAME">LOGIN_DETAILS</string>
<string name="CREDENTIALS">CREDENTIALS</string>
<string name="FORM_DATA">FORM_DATA</string>
</resources>
d.Make sure you downloading dependencies :
4. Building and Running the Code
a.We need to include 2 jars which ensures the proper functioning of the project
b.Download aliyun-java-sdk-core-3.2.8.jar from
http://central.maven.org/maven2/com/aliyun/aliyun-java-sdk-core/3.2.8/
c.Download aliyun-java-sdk-kms-2.4.0.jar from
http://central.maven.org/maven2/com/aliyun/aliyun-java-sdk-kms/2.4.0/
d.Add the jars into the libs folder in the projectview and add the jars to the dependencies
e.Add the following code into your app level gradle file.
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
defaultConfig {
applicationId "sample.alibabacloud.kmssample"
minSdkVersion 19
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
compile 'com.android.support:design:26.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
implementation files('libs/aliyun-java-sdk-kms-2.4.0.jar')
implementation files('libs/aliyun-java-sdk-core-3.2.8.jar')
}
and Make sure you build is successful.
f.Make sure you added the permission for Internet access to the Application in the AndroidManifest using the following line:
<uses-permission android:name="android.permission.INTERNET"/>
5. Code Level Explanation
a.In onCreate method we obtain references to all of the objects in the UI and create and add assign the onClickListener to all the buttons.
b.We have four Async Taks which which are responsible for the functionality
▪ Encrypt Credentials: Creates the key on the cloud and updates the and we use the corresponding key to encrypt the username and password. You the key will not be stored anywhere in your code
▪ Decrypt Credentials: Takes the cipherBlob and calls the decrypt API to decrypt the information and displays back the same on the screen. Escape characters like n r t are preserved, even after the decrypting, which enables us to have the formatted text encrypted.
▪ Encrypt Form Data: This class does the encryption of the complete form data this is primarily to demonstrate the uniqueness of the keys we are getting from the server.
▪ Decrypt Form Data: This class does the decryption of the form data. We are storing all the encrypted data in the sharedPreferences and we are fetching it when we are calling the Decrypt tasks.
Alibaba Cloud KMS service provides the awesome service of fetching the keys and deleting them at blazing speed. This provided the application high level of security.
You can see all the methods are self explanatory. If everything is done correctly all your compilation issues will go away and the application starts installing in by clicking the small play(run) button in the status bar of the android studio.
• You can see all the methods are self described.
• If everything is done correctly all your compilation issues will go away and the application starts installing in by clicking the small play(run) button in the status bar of the android studio.
I strongly recommend to clone the repo you will eliminate lot of manual errors and get this app running in minutes.
Please take a look at this repo for the final code repo and let me know if you face any issues or raise any pull requests for improvements.
Generation and Handling of Metadata Locks on RDS for MySQL Tables
2,599 posts | 762 followers
FollowYagr - July 8, 2020
Alibaba Clouder - January 29, 2018
Alibaba Cloud Community - November 12, 2024
Alibaba Container Service - May 16, 2024
Rupal_Click2Cloud - September 8, 2023
JDP - February 25, 2022
2,599 posts | 762 followers
FollowIndustry-standard hardware security modules (HSMs) deployed on Alibaba Cloud.
Learn MoreCreate, delete and manage encryption keys with Alibaba Cloud Key Management Service
Learn MoreProtect, backup, and restore your data assets on the cloud with Alibaba Cloud database services.
Learn MoreIdentify vulnerabilities and improve security management of Alibaba Cloud WAF and Anti-DDoS and with a fully managed security service
Learn MoreMore Posts by Alibaba Clouder