Couchbase Server Java SDKを使用して、JSONドキュメントの特定のフィールドを暗号化および復号化することができます。
CouchbaseのJava SDK暗号化ライブラリは、独自の暗号化コンポーネントを実装するためのフレームワークを提供します。
ライブラリ
フィールドレベルの暗号化機能は、エンタープライズサブスクリプションライセンス契約により、提供されるオプションのライブラリとして提供されています。
暗号化ライブラリを使用するには、プロジェクト構成ファイルに明示的に含める必要があります。
Mavenのdependency(依存関係)セクションを例示します。
<dependency>
<groupId>com.couchbase.client</groupId>
<artifactId>couchbase-encryption</artifactId>
<version>${version}</version>
</dependency>
使用法
構成
フィールドレベルの暗号化を有効にするには、ClusterEnvironment
にCryptoManager
を指定します。
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アノーテーションを付けます。
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に保存してみます。
Employee employee = new Employee();
employee.setReplicant(true);
collection.upsert("employee:1234", employee); // encrypts the "replicant" field
JsonObject
のフィールドが暗号化されていることを確認するために、ドキュメントとして取得します。
JsonObject encrypted = collection.get("employee:1234").contentAsObject(); // does not decrypt anything
System.out.println(encrypted);
contentAsObject()
メソッドでは、何も復号化しないため、出力は次のようになります。
{
"encrypted$replicant": {
"alg": "AEAD_AES_256_CBC_HMAC_SHA512",
"ciphertext": "xwcxyUyZ.....",
"kid": "myKey"
}
}
次に、データバインディングを使用してデータを読み取ります。
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シリアライザーを使用するようにクラスター環境を構成する方法を紹介します。
// 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
の暗号化されたフィールド値を読み書きできます。
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キーストアファイルを作成する方法を示す例です。
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
)を使用して、フィールドレベル暗号化で使用するためのキーストアを作成する方法は次のとおりです。
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");