[Oracle Cloud] SDK を使って簡単にファイルや文字列を暗号化する Client-Side Encryption 

# はじめに

Oracle Cloud Infrastructure(以下OCI) の SDK には、Client-Side Encryption (CSE)の機能があります。CSE では、自動的に OCI Vault と連携しデータ暗号化キーを生成し、指定のファイルを暗号化してくれます。通常であれば、自分たちでデータ暗号化キーの生成から、実際の暗号化まで実装しないといけない部分を、SDK ライブラリ側で行ってくれます。CSE についてドキュメントは[こちら](https://docs.cloud.oracle.com/en-us/iaas/Content/API/Concepts/clientsideencryption.htm) に書いています。

ドキュメントを見てもいまいちよく分からない部分があったため、実際にやってみました。



# ソースコード

CSE のソースコードです。基本的にはドキュメントに書いているソースコードそのままです。

```java
package com.example;

import com.oracle.bmc.ConfigFileReader;
import com.oracle.bmc.auth.AuthenticationDetailsProvider;
import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider;
import com.oracle.bmc.encryption.KmsMasterKey;
import com.oracle.bmc.encryption.KmsMasterKeyProvider;
import com.oracle.bmc.encryption.OciCrypto;
import com.oracle.bmc.encryption.OciCryptoInputStream;
import org.apache.commons.io.IOUtils;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * Hello world!
 *
 */
public class App {
    public static void main(String[] args) throws IOException {
        System.out.println("Start!");

        final String vaultId = "ocid1.vault.oc1.ap-tokyo-1.brp274vvaabe6.abxhiljry2zsxsysuhslu55yda2r6476epy2xpgzyhuruvrkicumn4up5ula";
        final String masterKeyId = "ocid1.key.oc1.ap-tokyo-1.brp274vvaabe6.abxhiljre3ayxcxxr66zjuoyyjh2ld76dvkf7ogl4dgk6cd4okgbkvv5fi7q";
        final String region = "ap-tokyo-1";
        final String filePath = "/home/opc/workdir/test.txt";

        // final String configurationFilePath = "~/.oci/config";
        // final String profile = "DEFAULT";

        final ConfigFileReader.ConfigFile configFile = ConfigFileReader.parseDefault();

        final AuthenticationDetailsProvider provider = new ConfigFileAuthenticationDetailsProvider(configFile);

        // Create Key provider
        KmsMasterKey kmsMasterKey = new KmsMasterKey(provider, region, vaultId, masterKeyId);
        KmsMasterKeyProvider kmsMasterKeyProvider = new KmsMasterKeyProvider(kmsMasterKey);

        OciCrypto ociCrypto = new OciCrypto();

        FileInputStream fileInputStreamText = new FileInputStream(filePath);
        FileOutputStream fileOutputStreamEnc = new FileOutputStream(filePath + ".encrypted");

        // Create encryption stream
        OciCryptoInputStream inputCipherStreamEncrypt = ociCrypto.createEncryptingStream(kmsMasterKeyProvider,
                fileInputStreamText, getSampleContext());

        // Encrypt data
        IOUtils.copy(inputCipherStreamEncrypt, fileOutputStreamEnc);
        fileOutputStreamEnc.close();
        inputCipherStreamEncrypt.close();

        System.out.println("Encrypted file: " + filePath + ".encrypted");
        ////////////////////////////////////////////////////////////////////////////////
        FileInputStream fileInputStreamEnc = new FileInputStream(filePath + ".encrypted");
        FileOutputStream fileOutputStreamText = new FileOutputStream(filePath + ".decrypted");

        // Create decryption stream
        kmsMasterKeyProvider = new KmsMasterKeyProvider(provider);
        OciCryptoInputStream inputCipherStreamDecrypt = ociCrypto.createDecryptingStream(kmsMasterKeyProvider,
                fileInputStreamEnc);

        // Decrypt data
        IOUtils.copy(inputCipherStreamDecrypt, fileOutputStreamText);
        fileOutputStreamText.close();
        kmsMasterKey.close();

        System.out.println("Decrypted file: " + filePath + ".decrypted");

        System.out.println("End!");
    }

    private static Map<String, String> getSampleContext() {
        Map<String, String> context = new HashMap<String, String>();
        context.put("Key1", "Value1");
        context.put("Key2", "Value2");
        return context;
    }
}
```



次の流れで処理を行っています

- `/home/opc/workdir/test.txt` を SDK の `com.oracle.bmc.encryption.OciCrypto;`パッケージで暗号化
- 暗号化すると、FileOutputStream が返ってくる
- FileOutputStreamを、`/home/opc/workdir/test.txt.encrypted` に保存
- 暗号化したファイルを復号化して、`/home/opc/workdir/test.txt.decrypted` に保存



# 実際に実行した結果

このように暗号化されます

```
[opc@java01 workdir]$ ls -la /home/opc/workdir/
total 16
drwxrwxr-x.  2 opc opc   74 Nov 21 10:47 .
drwx------. 16 opc opc 4096 Nov 21 10:47 ..
-rw-rw-r--.  1 opc opc   49 Nov 21 10:47 test.txt
-rw-rw-r--.  1 opc opc   49 Nov 21 10:47 test.txt.decrypted
-rw-rw-r--.  1 opc opc  723 Nov 21 10:47 test.txt.encrypted
[opc@java01 workdir]$
```



事前に用意したテストファイルと、復号化されたファイルの中身は同じです

```
[opc@java01 workdir]$ cat test.txt
Hello I am test file for Client Side Encryption!
[opc@java01 workdir]$ cat test.txt.decrypted
Hello I am test file for Client Side Encryption!
[opc@java01 workdir]$
```



暗号化されたファイルを見てみましょう。
... 暗号化はされているのですが、平文で読める文字がなにやら書かれています。`additionalAuthenticatedData` はソースコード内で指定しているので、削除可能です。

`encryptedDataKeys` は注意が必要で、暗号化したリージョン、OCI Vault の OCID, Masterkey の OCID, データ暗号化キー(暗号化) がそのまま書かれています。もちろんこれだけで復号化出来るわけではなく、適切な IAM Policy などが必要ですが、ちょっと気になりますね。

```
[opc@java01 workdir]$ cat test.txt.encrypted
�{"encryptedContentFormat":0,"algorithmId":0,"additionalAuthenticatedData":"{\"Key2\":\"Value2\",\"Key1\":\"Value1\"}","encryptedDataKeys":[{"region":"ap-tokyo-1","vaultId":"ocid1.vault.oc1.ap-tokyo-1.brp274vvaabe6.abxhiljry2zsxsysuhslu55yda2r6476epy2xpgzyhuruvrkicumn4up5ula","masterKeyId":"ocid1.key.oc1.ap-tokyo-1.brp274vvaabe6.abxhiljre3ayxcxxr66zjuoyyjh2ld76dvkf7ogl4dgk6cd4okgbkvv5fi7q","encryptedDataKey":"QZq1J7cKlNHpACGCckTuFhaugxRQSUoS4MHgDYE/NOiYDfAhbul5jj6ApFlbn1EfPqCknAg9oR0/gAWBdOqqTaBh4uvz1AAAAAA="}],"iv":"3UWrJEo576UFCNJ0WH2BUxwOyr16lXtSLjwNgO4QXxzKago7vYN3XhSOjZNB/mZSEWf7C/fRG1n+Bvrjd11k5wciqlL2FC+p1WXU3C�PGo�ӣ��dPW1���mt��IX�F�e1��H�.��A�垙���:s��ч�qQ�T^�8
```



はい、というわけで、SDK についている暗号化ライブラリの動作確認が出来ました。



# 参考URL

クライアント側の暗号化
https://docs.cloud.oracle.com/en-us/iaas/Content/API/Concepts/clientsideencryption.htm

Python サンプルコード Client Side Encryption (暗号化して、Object Storage に格納)
https://github.com/oracle/oci-python-sdk/blob/master/examples/client_side_encryption/encrypt_in_object_storage.py

Java サンプルコード : Client Side Encryption (暗号化するだけ)
https://github.com/oracle/oci-java-sdk/blob/master/bmc-examples/src/main/java/client_side_encryption/StreamEncryptionExample.java

Java サンプルコード : Object Storage に Put
https://github.com/oracle/oci-java-sdk/blob/master/bmc-examples/src/main/java/UploadObjectExample.java