Couchbase Server Java SDK解説: フィールドレベルの暗号化


Couchbase Server　Java SDKを使用して、JSONドキュメントの特定のフィールドを暗号化および復号化することができます。


CouchbaseのJava SDK暗号化ライブラリは、独自の暗号化コンポーネントを実装するためのフレームワークを提供します。


## ライブラリ

フィールドレベルの暗号化機能は、エンタープライズサブスクリプションライセンス契約により、提供されるオプションのライブラリとして提供されています。

暗号化ライブラリを使用するには、プロジェクト構成ファイルに明示的に含める必要があります。
Mavenのdependency(依存関係)セクションを例示します。


```xml
<dependency>
    <groupId>com.couchbase.client</groupId>
    <artifactId>couchbase-encryption</artifactId>
    <version>${version}</version>
</dependency>
```
## 使用法

### 構成

フィールドレベルの暗号化を有効にするには、`ClusterEnvironment`に`CryptoManager`を指定します。

```java
KeyStore javaKeyStore = KeyStore.getInstance("MyKeyStoreType");
FileInputStream fis = new java.io.FileInputStream("keyStoreName");
char[] password = { 'a', 'b', 'c' };
javaKeyStore.load(fis, password);
Keyring keyring = new KeyStoreKeyring(javaKeyStore, keyName -> "swordfish");

// AES-256 authenticated with HMAC SHA-512. Requires a 64-byte key.
AeadAes256CbcHmacSha512Provider provider = AeadAes256CbcHmacSha512Provider.builder().keyring(keyring).build();

CryptoManager cryptoManager = DefaultCryptoManager.builder().decrypter(provider.decrypter())
    .defaultEncrypter(provider.encrypterForKey("myKey")).build();

ClusterEnvironment env = ClusterEnvironment.builder().cryptoManager(cryptoManager).build();

Cluster cluster = Cluster.connect("localhost",
    ClusterOptions.clusterOptions("username", "password").environment(env));
```


### データバインディングの例

データクラスの暗号化するフィールドに、@Encryptedアノーテーションを付けます。

```java
public class Employee {
  @Encrypted
  private boolean replicant;

  // alternatively you could annotate the getter or setter
  public boolean isReplicant() {
    return replicant;
  }

  public void setReplicant(boolean replicant) {
    this.replicant = replicant;
  }
}
```

`Employee`レコードを作成してCouchbaseに保存してみます。

```java
Employee employee = new Employee();
employee.setReplicant(true);
collection.upsert("employee:1234", employee); // encrypts the "replicant" field
```

`JsonObject`のフィールドが暗号化されていることを確認するために、ドキュメントとして取得します。

```java
JsonObject encrypted = collection.get("employee:1234").contentAsObject(); // does not decrypt anything

System.out.println(encrypted);
```

`contentAsObject()`メソッドでは、何も復号化しないため、出力は次のようになります。

```java
{
  "encrypted$replicant": {
    "alg": "AEAD_AES_256_CBC_HMAC_SHA512",
    "ciphertext": "xwcxyUyZ.....",
    "kid": "myKey"
  }
}
```

次に、データバインディングを使用してデータを読み取ります。

```java
Employee readItBack = collection.get("employee:1234").contentAs(Employee.class); // decrypts the "replicant" field

System.out.println(readItBack.isReplicant());
```

最後の行では`true`が出力されます。

### 操作モード

2つの操作モードが利用可能です：

- Jacksonデータバインディング中の透過的な暗号化/復号化

- JsonObjectCryptoを使用した手動フィールド編集

#### カスタムObjectMapperの使用

データバインディング中に暗号化/復号化を有効にするコードは、`EncryptionModule`というJacksonモジュールとしてパッケージ化されています。


ドキュメントをシリアル化するときに独自にカスタマイズした`ObjectMapper`を提供する場合は、`ObjectMapper`に、カスタマイズを行った`CryptoManager`を用いて初期化した`EncryptionModule`クラスを`ObjectMapper`に登録します。


フィールドレベルの暗号化をサポートする独自の(`ObjectMapper`に基づく)カスタムJSONシリアライザーを使用するようにクラスター環境を構成する方法を紹介します。


```java
// CryptoManager cryptoManager = createMyCryptoManager();
KeyStore javaKeyStore = KeyStore.getInstance("MyKeyStoreType");
FileInputStream fis = new java.io.FileInputStream("keyStoreName");
char[] ksPassword = { 'a', 'b', 'c' };
javaKeyStore.load(fis, ksPassword);
Keyring keyring = new KeyStoreKeyring(javaKeyStore, keyName -> "swordfish");


// AES-256 authenticated with HMAC SHA-512. Requires a 64-byte key.
AeadAes256CbcHmacSha512Provider provider = AeadAes256CbcHmacSha512Provider.builder().keyring(keyring).build();
CryptoManager cryptoManager = DefaultCryptoManager.builder().decrypter(provider.decrypter())
    .defaultEncrypter(provider.encrypterForKey("myKey")).build();

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JsonValueModule()); // for JsonObject
mapper.registerModule(new EncryptionModule(cryptoManager));

// Here you can register more modules, add mixins, enable features, etc.

ClusterEnvironment env = ClusterEnvironment.builder().cryptoManager(cryptoManager)
    .jsonSerializer(JacksonJsonSerializer.create(mapper)).build();

Cluster cluster = Cluster.connect(connectionString,
    ClusterOptions.clusterOptions(username, password).environment(env));
```

#### JsonObjectCrypto
復号化するフィールドをさらに制御する必要がある場合、またはCouchbaseの`JsonObject`ツリーモデルを使用することを望む場合、`JsonObjectCrypto`インスタンスを使用して、`JsonObject`の暗号化されたフィールド値を読み書きできます。

```java
JsonObject document = JsonObject.create();
JsonObjectCrypto crypto = document.crypto(collection);

crypto.put("locationOfBuriedTreasure", "Between palm trees");

// This displays the encrypted form of the field
System.out.println(document);

collection.upsert("treasureMap", document);

JsonObject readItBack = collection.get("treasureMap").contentAsObject();
JsonObjectCrypto readItBackCrypto = crypto.withObject(readItBack);
System.out.println(readItBackCrypto.getString("locationOfBuriedTreasure"));
```

### 暗号化キーの作成
このライブラリに含まれているAEAD_AES_256_CBC_HMAC_SHA512アルゴリズムは、64バイト長の暗号化キーを使用します。

以下は、暗号化キーを含むJavaキーストアファイルを作成する方法を示す例です。

```java
KeyStore keyStore = KeyStore.getInstance("JCEKS");
keyStore.load(null); // initialize new empty key store

// Generate 64 random bytes
SecureRandom random = new SecureRandom();
byte[] keyBytes = new byte[64];
random.nextBytes(keyBytes);

// Add a new key called "my-key" to the key store
KeyStoreKeyring.setSecretKey(keyStore, "my-key", keyBytes, "protection-password".toCharArray());

// Write the key store to disk
try (OutputStream os = new FileOutputStream("MyKeystoreFile.jceks")) {
  keyStore.store(os, "integrity-password".toCharArray());
}
```

上記で作成したファイル(`MyKeystoreFile.jceks`)を使用して、フィールドレベル暗号化で使用するためのキーストアを作成する方法は次のとおりです。

```java
KeyStore keyStore = KeyStore.getInstance("JCEKS");
try (InputStream is = new FileInputStream("MyKeystoreFile.jceks")) {
  keyStore.load(is, "integrity-password".toCharArray());
}

KeyStoreKeyring keyring = new KeyStoreKeyring(keyStore, keyName -> "protection-password");

```

### 参考情報

[Field Level Encryption from the Java SDK](https://docs.couchbase.com/java-sdk/current/howtos/encrypting-using-sdk.html)

[Field Level Encryption](https://docs.couchbase.com/java-sdk/current/concept-docs/encryption.html)