Docs Menu

Client-Side Field Level Encryption

On this page

  • Overview
  • Installation
  • mongodb-crypt
  • mongocryptd
  • Examples
  • Automatic Encryption and Decryption
  • Explicit Encryption and Decryption
  • Explicit Encryption and Auto Decryption

In this guide, you can learn how to install and use Client-Side Field Level Encryption (CSFLE) in the MongoDB Java driver.

CSFLE allows you to encrypt specific data fields within a document with your MongoDB client application before sending the data to the server. Starting in MongoDB 4.2 Enterprise, you can perform this client-side encryption automatically.

With CSFLE, your client application encrypts fields client-side without requiring any server-side configuration or directives. CSFLE is useful for situations in which applications must guarantee that unauthorized parties, including server administrators, cannot read the encrypted data.

This guide is a quick introduction to CSFLE using the Java driver. For in-depth information on how CSFLE works, see the CSFLE reference documentation. For a real-world scenario and implementation, see our CSFLE Guide.

To get started with CSFLE in your client application, you need

  • the MongoDB Java driver
  • mongodb-crypt
  • mongocryptd if using automatic encryption (Enterprise or Atlas)

The mongodb-crypt binding is available as a separate JAR. Add it to your project using your desired dependency management tool.

mongocryptd is a binary run as a daemon / process that is used for automatic encryption. mongodb-crypt communicates with mongocryptd to automatically encrypt the information specified by a user-provided JSON Schema.

For more detailed information on mongocryptd, see the mongocryptd reference documentation

The examples on this page use a local key, but you can also use integrated support for cloud-based key management services from AWS, Azure, and GCP. Each example program execution creates a new master key in memory and drops the test.coll collection.

Tip

In the examples, the in-memory master key is lost when the application finishes running. If you'd like to retain and decrypt documents from previous runs, you can save the local master key to a file for reuse and remove the logic to drop the collection.

Warning

MongoDB recommends using local key management only for testing purposes, and using a remote key management service for production.

The following example shows how to configure the AutoEncryptionSettings instance to create a new key and set the JSON schema map.

The data in the encryptedField field is automatically encrypted before insertion, and decrypted when calling find() on the client side. Querying this collection from a client that isn't configured for CSFLE will return the document in encrypted form.

The full source is available at ClientSideEncryptionAutoEncryptionSettingsTour.java

Note

Auto encryption requires MongoDB Enterprise or Atlas.

import com.mongodb.AutoEncryptionSettings;
import com.mongodb.ClientEncryptionSettings;
import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.vault.DataKeyOptions;
import com.mongodb.client.vault.ClientEncryption;
import com.mongodb.client.vault.ClientEncryptions;
import org.bson.BsonBinary;
import org.bson.BsonDocument;
import org.bson.Document;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class ClientSideEncryptionAutoEncryptionSettingsTour {
/**
* Run this main method to see the output of this quick example.
*
* Requires the mongodb-crypt library in the class path and mongocryptd on the system path.
* Assumes the schema has already been created in MongoDB.
*
* @param args ignored args
*/
public static void main(final String[] args) {
// This would have to be the same master key as was used to create the encryption key
final byte[] localMasterKey = new byte[96];
new SecureRandom().nextBytes(localMasterKey);
Map<String, Map<String, Object>> kmsProviders = new HashMap<String, Map<String, Object>>() {{
put("local", new HashMap<String, Object>() {{
put("key", localMasterKey);
}});
}};
String keyVaultNamespace = "admin.datakeys";
ClientEncryptionSettings clientEncryptionSettings = ClientEncryptionSettings.builder()
.keyVaultMongoClientSettings(MongoClientSettings.builder()
.applyConnectionString(new ConnectionString("mongodb://localhost"))
.build())
.keyVaultNamespace(keyVaultNamespace)
.kmsProviders(kmsProviders)
.build();
ClientEncryption clientEncryption = ClientEncryptions.create(clientEncryptionSettings);
BsonBinary dataKeyId = clientEncryption.createDataKey("local", new DataKeyOptions());
final String base64DataKeyId = Base64.getEncoder().encodeToString(dataKeyId.getData());
final String dbName = "test";
final String collName = "coll";
AutoEncryptionSettings autoEncryptionSettings = AutoEncryptionSettings.builder()
.keyVaultNamespace(keyVaultNamespace)
.kmsProviders(kmsProviders)
.schemaMap(new HashMap<String, BsonDocument>() {{
put(dbName + "." + collName,
// Need a schema that references the new data key
BsonDocument.parse("{"
+ " properties: {"
+ " encryptedField: {"
+ " encrypt: {"
+ " keyId: [{"
+ " \"$binary\": {"
+ " \"base64\": \"" + base64DataKeyId + "\","
+ " \"subType\": \"04\""
+ " }"
+ " }],"
+ " bsonType: \"string\","
+ " algorithm: \"AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic\""
+ " }"
+ " }"
+ " },"
+ " \"bsonType\": \"object\""
+ "}"));
}}).build();
MongoClientSettings clientSettings = MongoClientSettings.builder()
.autoEncryptionSettings(autoEncryptionSettings)
.build();
MongoClient mongoClient = MongoClients.create(clientSettings);
MongoCollection<Document> collection = mongoClient.getDatabase("test").getCollection("coll");
collection.drop(); // Clear old data
collection.insertOne(new Document("encryptedField", "9876564321"));
System.out.println(collection.find().first().toJson());
// release resources
mongoClient.close();
}
}

The prior example demonstrated the automatic CSFLE feature. If your version of MongoDB does not offer automatic CSFLE, you can perform manual client-side field level encryption, which we call explicit encryption. This method does not require or use mongocryptd. The ClientEncryption class contains methods you can use to perform explicit encryption.

This example prints out the document in encrypted form, and prints out the explicitly decrypted field value to demonstrate functionality.

The full source is available from ClientSideEncryptionExplicitEncryptionAndDecryptionTour.java

// This would have to be the same master key as was used to create the encryption key
final byte[] localMasterKey = new byte[96];
new SecureRandom().nextBytes(localMasterKey);
Map<String, Map<String, Object>> kmsProviders = new HashMap<String, Map<String, Object>>() {{
put("local", new HashMap<String, Object>() {{
put("key", localMasterKey);
}});
}};
MongoClientSettings clientSettings = MongoClientSettings.builder().build();
MongoClient mongoClient = MongoClients.create(clientSettings);
// Set up the key vault for this example
MongoNamespace keyVaultNamespace = new MongoNamespace("encryption.testKeyVault");
MongoCollection<Document> keyVaultCollection = mongoClient
.getDatabase(keyVaultNamespace.getDatabaseName())
.getCollection(keyVaultNamespace.getCollectionName());
keyVaultCollection.drop();
// Ensure that two data keys cannot share the same keyAltName.
keyVaultCollection.createIndex(Indexes.ascending("keyAltNames"),
new IndexOptions().unique(true)
.partialFilterExpression(Filters.exists("keyAltNames")));
MongoCollection<Document> collection = mongoClient.getDatabase("test").getCollection("coll");
collection.drop(); // Clear old data
// Create the ClientEncryption instance
ClientEncryptionSettings clientEncryptionSettings = ClientEncryptionSettings.builder()
.keyVaultMongoClientSettings(MongoClientSettings.builder()
.applyConnectionString(new ConnectionString("mongodb://localhost"))
.build())
.keyVaultNamespace(keyVaultNamespace.getFullName())
.kmsProviders(kmsProviders)
.build();
ClientEncryption clientEncryption = ClientEncryptions.create(clientEncryptionSettings);
BsonBinary dataKeyId = clientEncryption.createDataKey("local", new DataKeyOptions());
// Explicitly encrypt a field
BsonBinary encryptedFieldValue = clientEncryption.encrypt(new BsonString("123456789"),
new EncryptOptions("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic").keyId(dataKeyId));
collection.insertOne(new Document("encryptedField", encryptedFieldValue));
Document doc = collection.find().first();
System.out.println(doc.toJson());
// Explicitly decrypt the field
System.out.println(
clientEncryption.decrypt(new BsonBinary(doc.get("encryptedField", Binary.class).getData()))
);

Although automatic encryption requires MongoDB Enterprise or MongoDB Atlas, automatic decryption is available in all MongoDB versions greater than or equal to 4.2.

To configure automatic decryption, set bypassAutoEncryption(true) in the autoEncryptionSettings builder.

The following example prints the inserted document out in unencrypted form. The document is automatically decrypted because autoEncryptionSettings have been configured.

The full source is available at ClientSideEncryptionExplicitEncryptionOnlyTour.java.

...
MongoClientSettings clientSettings = MongoClientSettings.builder()
.autoEncryptionSettings(AutoEncryptionSettings.builder()
.keyVaultNamespace(keyVaultNamespace.getFullName())
.kmsProviders(kmsProviders)
.bypassAutoEncryption(true)
.build())
.build();
MongoClient mongoClient = MongoClients.create(clientSettings);
...
// Explicitly encrypt a field
BsonBinary encryptedFieldValue = clientEncryption.encrypt(new BsonString("123456789"),
new EncryptOptions("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic").keyId(dataKeyId));
collection.insertOne(new Document("encryptedField", encryptedFieldValue));
// Automatically decrypts the encrypted field.
System.out.println(collection.find().first().toJson());
Give Feedback
© 2021 MongoDB, Inc.

About

  • Careers
  • Legal Notices
  • Privacy Notices
  • Security Information
  • Trust Center
© 2021 MongoDB, Inc.