Using Alibaba Cloud KMS to Simulate Data Encryption

Overview

In this era, we are concerned about data security.

We need to do a security method to protect the data, one of the solutions is using KMS from Alibaba Cloud.

KMS stands for Key Management Service, which is a secure and easy-to-use management service provided by Alibaba Cloud.

It can allow you to use keys securely, without having to spend a great deal to protect the CIA (Confidentiality, Integrity, and Availability) of our keys.

Prerequisites

  • Alibaba Cloud Console/CLI
  • Cloud Resources (ECS, KMS)
  • Python

Implementation

Currently we have already default keys on KMS.

To implement the simulation, we need to configure the identities for our account first with CLI.

After that, we can try to see our keys with CLI by

To describe we can use this command

$ aliyun kms DescribeKey –KeyId <<YOUR KEY ID>>

We can see some KeyMetadata and RequestID.

Let’s test to encrypt our data which only filled by this texts “This is a test plaintext”.

It will result the CiphertextBlob which can be used to recognized the data or decrypt our data.

To decrypt, we just need to execute this

$ aliyun kms Decrypt –CiphertextBlob <<YOUR CIPHERTEXTBLOB>>

We can see the decrypted data plaintext as “This is a test plaintext”.

We are also able to return the plaintext and ciphertext off our dataKey by

$ aliyun kms GenerateDataKey –KeyId YOUR-KEY-ID

Now, we want to try to simulate data encryption of KMS between client and server with Python SDK.

Here is the encryption procedure:

  1. Create a CMK (Customer Master Key).
  2. Call the KMS GenerateDataKey interface to generate data keys.
  3. Use the plaintext data key to encrypt the file and generate a ciphertext file.
  4. Save the ciphertext data key and the ciphertext file.

Here is decryption procedure:

  1. Read the ciphertext data key and the ciphertext file.
  2. Call the KMS Decrypt interface to decrypt the ciphertext data key to obtain the plaintext data key.
  3. Use the plaintext data key to decrypt the file.

Please install these dependencies first.

$ pip3 install flask # micro web framework written in Python

$ pip3 install aliyun-python-sdk-kms # dependency package of alibaba cloud kms

$ pip3 install pycrypto # additional dependency for our program

Update this file, by change “clock” on time.clock() to “perf_counter”.

After that, create file .vimrc and update the file by add text “set paste”

For our server, create file server.py and fill with this code

from flask import Flask,request
from aliyunsdkcore import client
from aliyunsdkkms.request.v20160120 import GenerateDataKeyRequest
from aliyunsdkkms.request.v20160120 import DecryptRequest
import json,base64
from Crypto.Cipher import AES

app = Flask(__name__)

accesskeyid = "<<YOUR KEY ACCESS ID>>"
accesssecret = "<<YOUR KEY ACCESS SECRET>>"
keyid = "<<YOUR KEY ID>>"
regionid = "us-west-1"

def createdatakey():
    clt = client.AcsClient(accesskeyid, accesssecret, regionid)
    genrequest = GenerateDataKeyRequest.GenerateDataKeyRequest()

    genrequest.set_KeyId(keyid);
    genrequest.set_KeySpec("AES_256") # or AES_128
    genrequest.set_accept_format("json")
    genrequest.set_protocol_type("https")
    genresp = clt.do_action_with_exception(genrequest)

    datakeydict = json.loads(genresp)
    datakey = base64.b64decode(datakeydict["Plaintext"]) #here we got the datakey with plaintext
    cipherdatakey = datakeydict["CiphertextBlob"] # here we got encrypted datakey

    return cipherdatakey

def decryptdata(ciphertext, cipherdatakey):
    clt = client.AcsClient(accesskeyid, accesssecret, regionid)
    decrequest = DecryptRequest.DecryptRequest()
    decrequest.set_CiphertextBlob(cipherdatakey)
    decrequest.set_accept_format("json")
    decrequest.set_protocol_type("https")

    decresp = clt.do_action_with_exception(decrequest)
    plaintext = json.loads(decresp)
    datakey = base64.b64decode(plaintext["Plaintext"])  # get plaintext datakey back

    cipherfile = base64.b64decode(ciphertext)
    iv = cipherfile[:AES.block_size]
    aes = AES.new(datakey,AES.MODE_CBC, iv)
    return aes.decrypt(cipherfile[AES.block_size:]).decode('utf-8') #use datakey to decrypt the content of file: cipherfile.txt and print it out

@app.route('/')
def index():
    return 'Hello Flask!\n'

@app.route('/applyDataKey')
def applyDataKey():
    return createdatakey() + "\n"

@app.route("/sendEncryptedData",methods = ['GET',"POST"])
def sendEncryptedData():
    if request.method == "POST":
        ciphertext = request.form["ciphertext"]
        cipherdatakey = request.form["cipherdatakey"]
        print ("After decryption:" + decryptdata(ciphertext, cipherdatakey))
        return "decryptdata success"
    return "decryptdata fail, Methods is error"

if __name__ == '__main__':
    app.run(host='0.0.0.0',port=80)

Nb. Update accesskeyid, accesssecret, keyid and regionid.

And for client, create file named client.py and fill with this code.

#!/usr/bin/python
#coding:utf-8
import sys,requests,json
from aliyunsdkcore import client
from aliyunsdkkms.request.v20160120 import DecryptRequest
from Crypto.Cipher import AES
from Crypto import Random
import base64

accesskeyid = "YOUR KEY ACCESS ID"
accesssecret = "YOUR KEY ACCESS SECRET"
regionid = "us-west-1"

def aes256pad(s):
    return s + (32 - len(s) % 32) * chr(32 - len(s) % 32)

def send(ciphertext, cipherdatakey):
    url = "http://<<YOUR IP>>/sendEncryptedData"
    payload={'ciphertext': ciphertext,
             'cipherdatakey': cipherdatakey}
    files=[
    ]
    headers = {}
    response = requests.request("POST", url, headers=headers, data=payload, files=files)
    print(response.text)

if __name__ == "__main__":
    content = sys.argv[1]
    cipherdatakey = sys.argv[2]

    clt = client.AcsClient(accesskeyid, accesssecret, regionid)
    decrequest = DecryptRequest.DecryptRequest()
    decrequest.set_CiphertextBlob(cipherdatakey)
    decrequest.set_accept_format("json")
    decrequest.set_protocol_type("https")

    decresp = clt.do_action_with_exception(decrequest)
    plaintext = json.loads(decresp)
    datakey = base64.b64decode(plaintext["Plaintext"])  # get plaintext datakey back

    iv = Random.new().read(AES.block_size)
    cipher = AES.new(datakey, AES.MODE_CBC, iv) #use daatakey to initiate an object
    filedata =aes256pad(content)
    cipherfile = base64.b64encode(iv + cipher.encrypt(filedata)) #encrypt the content
    print(cipherfile)
    send(str(cipherfile, encoding="utf-8"), cipherdatakey)

Nb. Update accesskeyid, accesssecret, yourIP, and regionid.

Run python3 server.py

Our public IP is 47.88.94.217, we can access it directly

Let’s try to obtain data key ciphertext on URI http://$host/applyDataKey

To decrypt

And we can check it from the server log.

Reference

Labex.io

Published by boy.suganda

My name is Boy Suganda Sinaga. I worked as Site Reliability Engineer (SRE) at Shipper Indonesia. I'm still developing my skill, both hard-skill and soft-skill. Let's work together, to bring better future for others.

Leave a Reply

Your email address will not be published. Required fields are marked *