Python SDKでOCI Vaultを操作する① - ファイル暗号 - 

OCI Vaultを実際のアプリケーションや運用に組み込んだ使い方をする場合は、OCI SDKが必要になる場合が多いかと思います。Pythonは、Githubにサンプルコードがあるので、基本的な使い方に関して参考になるかと思います。

https://github.com/oracle/oci-python-sdk

このサンプルコードを参考にしつつ、もう少し実践的にVaultを操作するPythonコードを紹介します。

## データ暗号鍵でファイルを暗号化する
Vaultに格納したマスター暗号鍵を使用し、直接データの暗号化をVault自身で実行することは可能ですが、データサイズが4KBと制限があります。例えば、4KB以上のファイルを暗号化したい場合には、マスター暗号鍵から生成したデータ暗号鍵を使用して、クライアント自身で暗号化するという方法が可能です。

```
#データ暗号鍵でファイルを暗号化するサンプルコード

import oci,sys,os
from Crypto.Cipher import AES

config = oci.config.from_file("~/.oci/config","DEFAULT")

# Management Endpoint 
key_management_client = oci.key_management.KmsManagementClient(
    config, "<Vaultの管理エンドポイント>")

# Cryptographic Endpoint:
key_crypto_client = oci.key_management.KmsCryptoClient(
    config, "<Vaultの暗号エンドポイント>")

# Master Key ID
Masterkey_id="<マスター暗号鍵のOCID>"

def encrpy(plaintext): 

    # データ暗号鍵の生成
    key_shape = oci.key_management.models.KeyShape(algorithm="AES", length=24)
    generate_dek_details = oci.key_management.models.GenerateKeyDetails(
        include_plaintext_key=True,
        key_id=Masterkey_id,
        key_shape=key_shape)

    gen_key_response = key_crypto_client.generate_data_encryption_key(generate_dek_details)
    print("** マスター暗号鍵からデータ暗号鍵を生成 **")
    print("データ暗号鍵1(平文) -> " + gen_key_response.data.plaintext)
    print("データ暗号鍵2(マスター鍵で暗号済) -> " + gen_key_response.data.ciphertext)
    print("※※データ暗号鍵1は実際の暗号/復号で必要。ただし、そのまま保存はせず、保存はデータ暗号鍵2を用いる")
    print("")

    # 暗号キーはバイト型が必要
    ciphertext = bytes(gen_key_response.data.plaintext,'utf-8')

    # 平文ファイル読み込み (readしたデータはByte型にエンコード)
    filepath=os.getcwd()
    with open(filepath + "\\" + plaintext,"r", encoding="utf-8") as file:
        data = file.read()
    plain_data = data.encode()    

    print("** ファイル暗号化実行 **")  

    # データ暗号鍵でファイルを暗号化
    cipher = AES.new(ciphertext,AES.MODE_EAX)
    encrypted_data = cipher.encrypt(plain_data)

    # ファイル書き込み 
    with open(filepath + "\\encrypted_" + plaintext,"wb") as binary_file:
        binary_file.write(encrypted_data)  
    
    print("平文ファイル -> " +  plaintext )
    print("暗号ファイル -> " + "encrypted_" + plaintext)
    print("")
   
encrpy(sys.argv[1])
```

コード内のVaultの管理エンドポイント、Vaultの暗号エンドポイント、マスター暗号鍵のOICDは、ターゲットのVaultの詳細情報から取得して追記して下さい。
また、サンプルコードはencdemo.pyとして保存し、暗号化したいテキストファイルをカレントディレクトリに一つ用意します。

```
#実行例
$ python encdemo.py sampledata.txt   
** マスター暗号鍵からデータ暗号鍵を生成 **
データ暗号鍵1(平文) -> dhs6Jb7DRFRzqqYtJl7LymJ5FvDL7jn+
データ暗号鍵2(マスター鍵で暗号済) -> IQgbt5pYsg9TALzkXkOQxzqdZkNoQWAgxu0WTAZ3A9OqM3lFpYK4Bqwv4HStQi4Ff8AXOgemp/X/v5ec0REAAAAA     
※※データ暗号鍵1は実際の暗号/復号で必要。ただし、そのまま保存はせず、保存はデータ暗号鍵2を用いる

** ファイル暗号化実行 **
平文ファイル -> sampledata.txt
暗号ファイル -> encrypted_sampledata.txt
```
実行後には、"encrypted_"のファイル名がついた暗号化ファイルが作成されます。
コード内のデータ暗号鍵の生成でinclude_plaintext_key=Trueと指定している箇所がありますが、これは暗号鍵の平文の生成を指定しています。データ暗号鍵(平文)は実際の暗号/復号処理に必要なのですが、そのまま保管するのは危険なので、処理が終わったら破棄し、データ暗号鍵(暗号済)のものをファイルと一緒に保管します。
ファイルを復号する場合は、データ暗号鍵(暗号済)をVaultのマスター暗号鍵に復号してもらうことで、ファイルの復号に必要なデータ暗号鍵(平文)を入手します。

##ファイルを復号する

以下のファイルをコードを追記します。※ encrpy(sys.argv[1])の前

```
    #復号処理
    print("** 復号処理 **")
    
    # 暗号化ファイル読み込み (Byte型でRead)
    with open(filepath + "\\encrypted_" + plaintext,"rb") as binary_file:
        data = binary_file.read()

    # 復号処理 (復号後 -> UTF-8にデコード)
    cipher_dec = AES.new(ciphertext, AES.MODE_EAX,cipher.nonce)
    deciphered_bytes  = cipher_dec.decrypt(encrypted_data)
    decrypted_data = deciphered_bytes.decode('utf-8') 

    # ファイル書き込み (ファイルTypeでwrite)
    with open(filepath + "\\decrypted_" + plaintext,"w") as file:
        file.write(decrypted_data)
    print("復号ファイル -> " + "decrypted_" + plaintext)
```

もう一回実行します。


```
$ python encdemo.py sampledata.txt 
** マスター暗号鍵からデータ暗号鍵を生成 **
データ暗号鍵1(平文) -> dhs6Jb7DRFRzqqYtJl7LymJ5FvDL7jn+
データ暗号鍵2(マスター鍵で暗号済) -> IQgbt5pYsg9TALzkXkOQxzqdZkNoQWAgxu0WTAZ3A9OqM3lFpYK4Bqwv4HStQi4Ff8AXOgemp/X/v5ec0REAAAAA     
※※データ暗号鍵1は実際の暗号/復号で必要。ただし、そのまま保存はせず、保存はデータ暗号鍵2を用いる

** ファイル暗号化実行 **
平文ファイル -> sampledata.txt
暗号ファイル -> encrypted_sampledata.txt

** 復号処理 **
復号ファイル -> decrypted_sampledata.txt
```

コードを追記して実行すると、暗号化したファイルを読み込んで、再度復号する処理を実行し、"decrypted_"のついた復号ファイルを作成します。元のファイルと相違ないか確認してください。
サンプルコードでは暗号->復号を一連で動作させているので省略していますが、本来では、データ暗号鍵(暗号済)をマスタ暗号鍵で復号して、ファイル復号に必要なデータ暗号鍵(平文)を取得する必要があります。(ややここしい）

コードを流しながら確認すると、Vaultのマスター暗号鍵とデータ暗号鍵の関係性が理解しやすいと思います。