Alibaba Cloud にデプロイされた IT 資産の機密情報を暗号化する必要があります。 エンベロープ暗号化では、Key Management Service (KMS) によって生成されたデータキーを使用して、大量のローカルデータを暗号化できます。 Key Management Service (KMS) の対応する暗号化操作を呼び出して、オンラインでデータキーペアを生成し、そのデータキーペアを使用してローカルデータを暗号化および復号化できます。 この暗号化メカニズムは、エンベロープ暗号化と呼ばれます。

シナリオ

エンベロープ暗号化は、以下のような多くのシナリオで使用できますが、これらに限定されません。
  • ビジネスデータファイルの暗号化
  • ローカルディスクに保存されているすべてのデータの暗号化
このドキュメントでは、エンベロープ暗号化を使用してローカルファイルを暗号化および復号化する方法について説明します。

エンベロープ暗号化の仕組み

KMS を使用して Customer Master Key (CMK) を作成し、CMK を使用してデータキーペアを生成します。次に、プレーンテキストデータキーを使用してローカルファイルを暗号化します。 エンベロープ暗号化は、大量のデータの暗号化に適しています。 次の図は、エンベロープ暗号化手順の全体を示しています。
  • エンベロープ暗号化操作手順 :
    1. KMS コンソールを使用するか、CreateKey 操作を呼び出して CMK を作成します。
    2. KMS の GenerateDataKey 操作を呼び出して、データキーペアを生成します。 KMS は、データキーペア (プレーンテキストデータキーと暗号文データキー) を返します。
    3. プレーンテキストデータキーを使用してローカルファイルを暗号化し、RAM (Random Access Memory) に格納されているプレーンテキストデータキーを削除します。
    4. 暗号文データキーと暗号化されたデータファイルをストレージデバイスまたはサービスに保存します。
  • エンベロープ復号化操作手順 :
    1. ローカルデバイスまたはサービスから暗号文データキーを取得します。
    2. KMS の復号操作を呼び出して、暗号文データキーを復号します。 データキーのプレーンテキストのコピーが返されます。
    3. プレーンテキストデータキーを使用してローカルファイルを復号し、RAM に保存されているプレーンテキストデータキーを削除します。

関連 API 操作

次の KMS API 操作を呼び出して、ローカルデータを暗号化および復号化できます。
操作 説明
CreateKey CMK を作成します。
CreateAlias CMK にエイリアスを割り当てます。
GenerateDataKey データキーを生成し、指定された CMK を使用してデータキーを暗号化してから、プレーンテキストデータキーと暗号文データキーを返します。
Decrypt GenerateDataKey 操作を呼び出して生成された暗号文データキーなど、KMS によって暗号化されたデータを復号します。 CMK を指定する必要はありません。

ローカルファイルの暗号化と復号化

  • エンベロープ暗号化
    1. CMK を作成します。
      $ aliyun kms CreateKey
      {
        "KeyMetadata": {
          "CreationDate": "2019-04-08T07:45:54Z",
          "Description": "",
          "KeyId": "1234abcd-12ab-34cd-56ef-12345678****",
          "KeyState": "Enabled",
          "KeyUsage": "ENCRYPT/DECRYPT",
          "DeleteDate": "",
          "Creator": "111122223333",
          "Arn": "acs:kms:cn-hangzhou:111122223333:key/1234abcd-12ab-34cd-56ef-12345678****",
          "Origin": "Aliyun_KMS",
          "MaterialExpireTime": ""
        },
        "RequestId": "2a37b168-9fa0-4d71-aba4-2077dd9e80df"
      }
    2. CMK にエイリアスを割り当てます。
      エイリアスは CMK のオプションです。 CMK にエイリアスがない場合、その ID を使用できます。
      $ aliyun kms CreateAlias --AliasName alias/Apollo/WorkKey --KeyId 1234abcd-12ab-34cd-56ef-1234567890ab
      この例では、Apollo/WorkKey は、データキーの暗号化に使用される Apollo プロジェクトの CMK を指定します。 CMK のエイリアスは WorkKey です。 つまり、alias/Apollo/WorkKey を指定して CMK WorkKey を使用し、データキーを暗号化できます。
    3. ローカルデータファイルを暗号化します。
      サンプルコード:
      • CMK:CMK のエイリアスは、alias/Apollo/WorkKey です 。
      • プレーンテキストデータファイル: ./data/sales.csv
      • 暗号文データファイル: ./data/sales.csv.cipher
      #! /usr/bin/env python
      # coding=utf-8
      
      import json
      import base64
      
      from Crypto.Cipher import AES
      
      from aliyunsdkcore import client
      from aliyunsdkkms.request.v20160120 import GenerateDataKeyRequest
      
      def KmsGenerateDataKey(client, key_alias):
          request = GenerateDataKeyRequest.GenerateDataKeyRequest()
          request.set_accept_format('JSON')
          request.set_KeyId(key_alias)
          request.set_NumberOfBytes(32)
          response = json.loads(client.do_action(request))
      
          datakey_encrypted = response["CiphertextBlob"]
          datakey_plaintext = response["Plaintext"]
          return (datakey_plaintext, datakey_encrypted)
      
      def ReadTextFile(in_file):
        file = open(in_file, 'r')
        content = file.read()
        file.close()
        return content
      
      def WriteTextFile(out_file, lines):
        file = open(out_file, 'w')
        for ln in lines:
          file.write(ln)
          file.write('\n')
        file.close()
      
      # Out file format (text)
      # Line 1: b64 encoded data key
      # Line 2: b64 encoded IV
      # Line 3: b64 encoded ciphertext
      # Line 4: b64 encoded authentication tag
      def LocalEncrypt(datakey_plaintext, datakey_encrypted, in_file, out_file):
        data_key_binary = base64.b64decode(datakey_plaintext)
        cipher = AES.new(data_key_binary, AES.MODE_EAX)
      
        in_content = ReadTextFile(in_file)
        ciphertext, tag = cipher.encrypt_and_digest(in_content)
      
        lines = [datakey_encrypted, base64.b64encode(cipher.nonce), base64.b64encode(ciphertext), base64.b64encode(tag)];
        WriteTextFile(out_file, lines)
      
      clt = client.AcsClient('Access-Key-Id','Access-Key-Secret','Region-Id')
      
      key_alias = 'alias/Apollo/WorkKey'
      
      in_file = './data/sales.csv'
      out_file = './data/sales.csv.cipher'
      
      # Generate Data Key
      datakey = KmsGenerateDataKey(clt, key_alias)
      
      # Locally Encrypt the sales record
      LocalEncrypt(datakey[0], datakey[1], in_file, out_file)
  • エンベロープ復号化

    ローカルファイルを復号します。

    サンプルコード:
    • 暗号文データファイル: ./data/sales.csv.cipher
    • プレーンテキストデータファイル: ./data/decrypted_sales.csv
    #! /usr/bin/env python
    #coding=utf-8
    
    import json
    import base64
    
    from Crypto.Cipher import AES
    
    from aliyunsdkcore import client
    from aliyunsdkkms.request.v20160120 import DecryptRequest
    
    def KmsDecrypt(client, ciphertext):
      request = DecryptRequest.DecryptRequest()
      request.set_accept_format('JSON')
      request.set_CiphertextBlob(ciphertext)
      response = json.loads(clt.do_action(request))
      return response.get("Plaintext")
    
    def ReadTextFile(in_file):
      file = open(in_file, 'r')
      lines = []
      for ln in file:
        lines.append(ln)
      file.close()
      return lines
    
    def WriteTextFile(out_file, content):
      file = open(out_file, 'w')
      file.write(content)
      file.close()
    
    def LocalDecrypt(datakey, iv, ciphertext, tag, out_file):
      cipher = AES.new(datakey, AES.MODE_EAX, iv)
      data = cipher.decrypt_and_verify(ciphertext, tag).decode('utf-8')
      WriteTextFile(out_file, data)
    
    clt = client.AcsClient('Access-Key-Id','Access-Key-Secret','Region-Id')
    
    in_file = './data/sales.csv.cipher'
    out_file = './data/decrypted_sales.csv'
    
    # Read encrypted file
    in_lines = ReadTextFile(in_file)
    
    # Decrypt data key
    datakey = KmsDecrypt(clt, in_lines[0])
    
    # Locally decrypt the sales record
    LocalDecrypt(
      base64.b64decode(datakey),
      base64.b64decode(in_lines[1]), # IV
      base64.b64decode(in_lines[2]), # Ciphertext
      base64.b64decode(in_lines[3]), # Authentication tag
      out_file
      )