The MongoDB Synchronous Driver for Java providing blocking I/O patterns for database operations
—
Client-side field level encryption for sensitive data with data key management, automatic and explicit encryption, and queryable encryption support for maintaining privacy while enabling queries.
Factory class for creating ClientEncryption instances with configuration for key management services and encryption options.
/**
* Factory for creating ClientEncryption instances
*/
public final class ClientEncryptions {
/**
* Creates a client encryption instance with specified options
* @param clientEncryptionSettings configuration for encryption operations
* @return ClientEncryption instance for key management and field encryption
*/
public static ClientEncryption create(ClientEncryptionSettings clientEncryptionSettings);
}Usage Examples:
import com.mongodb.client.vault.ClientEncryption;
import com.mongodb.client.vault.ClientEncryptions;
import com.mongodb.ClientEncryptionSettings;
import com.mongodb.MongoClientSettings;
// Configure encryption settings
Map<String, Map<String, Object>> kmsProviders = new HashMap<>();
Map<String, Object> localMasterKey = new HashMap<>();
localMasterKey.put("key", localMasterKeyBytes);
kmsProviders.put("local", localMasterKey);
ClientEncryptionSettings encryptionSettings = ClientEncryptionSettings.builder()
.keyVaultMongoClientSettings(MongoClientSettings.builder()
.applyConnectionString(new ConnectionString("mongodb://localhost:27017"))
.build())
.keyVaultNamespace("encryption.__keyVault")
.kmsProviders(kmsProviders)
.build();
ClientEncryption clientEncryption = ClientEncryptions.create(encryptionSettings);Primary interface for client-side field level encryption operations including data key management and field encryption/decryption.
/**
* Interface for client-side field level encryption operations
*/
public interface ClientEncryption extends AutoCloseable {
/**
* Creates a new data key for encryption
* @param kmsProvider the key management service provider name
* @return BsonBinary containing the data key ID
*/
BsonBinary createDataKey(String kmsProvider);
/**
* Creates a new data key with additional options
* @param kmsProvider the key management service provider name
* @param dataKeyOptions additional options for data key creation
* @return BsonBinary containing the data key ID
*/
BsonBinary createDataKey(String kmsProvider, DataKeyOptions dataKeyOptions);
/**
* Deletes a data key from the key vault
* @param id the data key ID to delete
* @return DeleteResult indicating the outcome of the delete operation
*/
DeleteResult deleteKey(BsonBinary id);
/**
* Encrypts a value using client-side field level encryption
* @param value the value to encrypt as BsonValue
* @param options encryption options including algorithm and key
* @return BsonBinary containing the encrypted value
*/
BsonBinary encrypt(BsonValue value, EncryptOptions options);
/**
* Decrypts an encrypted value
* @param encryptedValue the encrypted value as BsonBinary
* @return BsonValue containing the decrypted value
*/
BsonValue decrypt(BsonBinary encryptedValue);
/**
* Encrypts an expression for queryable encryption
* @param expression the expression to encrypt as Bson
* @param options encryption options for the expression
* @return BsonDocument containing the encrypted expression
*/
BsonDocument encryptExpression(Bson expression, EncryptOptions options);
/**
* Retrieves a data key by its ID
* @param id the data key ID
* @return BsonDocument containing the data key information
*/
BsonDocument getKey(BsonBinary id);
/**
* Retrieves all data keys
* @return FindIterable for iterating over all data keys
*/
FindIterable<BsonDocument> getKeys();
/**
* Adds an alternate name to a data key
* @param id the data key ID
* @param keyAltName the alternate name to add
* @return BsonDocument containing the updated data key
*/
BsonDocument addKeyAltName(BsonBinary id, String keyAltName);
/**
* Removes an alternate name from a data key
* @param id the data key ID
* @param keyAltName the alternate name to remove
* @return BsonDocument containing the updated data key or null if no change
*/
BsonDocument removeKeyAltName(BsonBinary id, String keyAltName);
/**
* Retrieves a data key by its alternate name
* @param keyAltName the alternate name to search for
* @return BsonDocument containing the data key or null if not found
*/
BsonDocument getKeyByAltName(String keyAltName);
/**
* Re-wraps multiple data keys with new encryption
* @param filter filter to select which data keys to re-wrap
* @return RewrapManyDataKeyResult containing information about the operation
*/
RewrapManyDataKeyResult rewrapManyDataKey(Bson filter);
/**
* Re-wraps multiple data keys with new encryption and options
* @param filter filter to select which data keys to re-wrap
* @param options options for the re-wrap operation
* @return RewrapManyDataKeyResult containing information about the operation
*/
RewrapManyDataKeyResult rewrapManyDataKey(Bson filter, RewrapManyDataKeyOptions options);
/**
* Creates an encrypted collection with queryable encryption
* @param database the database to create the collection in
* @param collectionName the name of the collection to create
* @param createCollectionOptions options for collection creation
* @param createEncryptedCollectionParams parameters for encrypted collection setup
* @return BsonDocument containing the created collection information
*/
BsonDocument createEncryptedCollection(MongoDatabase database,
String collectionName,
CreateCollectionOptions createCollectionOptions,
CreateEncryptedCollectionParams createEncryptedCollectionParams);
/**
* Closes the client encryption instance and releases resources
*/
void close();
}Usage Examples:
import com.mongodb.client.model.vault.DataKeyOptions;
import com.mongodb.client.model.vault.EncryptOptions;
import org.bson.BsonString;
import org.bson.BsonInt32;
try (ClientEncryption clientEncryption = ClientEncryptions.create(encryptionSettings)) {
// Create a data key for field encryption
BsonBinary dataKeyId = clientEncryption.createDataKey("local");
System.out.println("Created data key: " + dataKeyId);
// Create data key with alternate name
DataKeyOptions keyOptions = new DataKeyOptions()
.keyAltNames(Arrays.asList("customer-ssn-key", "pii-key"));
BsonBinary namedKeyId = clientEncryption.createDataKey("local", keyOptions);
// Encrypt sensitive data
EncryptOptions encryptOptions = new EncryptOptions("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic")
.keyId(dataKeyId);
BsonString sensitiveValue = new BsonString("123-45-6789");
BsonBinary encryptedSSN = clientEncryption.encrypt(sensitiveValue, encryptOptions);
// Store encrypted value in document
Document customer = new Document("name", "John Doe")
.append("ssn", encryptedSSN)
.append("email", "john@example.com");
collection.insertOne(customer);
// Retrieve and decrypt
Document retrievedCustomer = collection.find(Filters.eq("name", "John Doe")).first();
BsonBinary encryptedValue = retrievedCustomer.get("ssn", BsonBinary.class);
BsonValue decryptedSSN = clientEncryption.decrypt(encryptedValue);
System.out.println("Decrypted SSN: " + decryptedSSN.asString().getValue());
}Comprehensive data key lifecycle management including creation, rotation, and organization.
// Advanced data key creation with AWS KMS
Map<String, Object> awsKmsProviders = new HashMap<>();
Map<String, Object> awsCredentials = new HashMap<>();
awsCredentials.put("accessKeyId", "AWS_ACCESS_KEY_ID");
awsCredentials.put("secretAccessKey", "AWS_SECRET_ACCESS_KEY");
awsKmsProviders.put("aws", awsCredentials);
// Create data key with AWS KMS
DataKeyOptions awsKeyOptions = new DataKeyOptions()
.keyAltNames(Arrays.asList("customer-data-key"))
.masterKey(new BsonDocument()
.append("region", new BsonString("us-east-1"))
.append("key", new BsonString("arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012")));
BsonBinary awsDataKeyId = clientEncryption.createDataKey("aws", awsKeyOptions);
// Key rotation - create new key and re-encrypt data
BsonBinary newKeyId = clientEncryption.createDataKey("local");
// Find documents with old encrypted data
FindIterable<Document> documentsToReEncrypt = collection.find(
Filters.exists("encryptedField")
);
for (Document doc : documentsToReEncrypt) {
BsonBinary oldEncryptedValue = doc.get("encryptedField", BsonBinary.class);
BsonValue decryptedValue = clientEncryption.decrypt(oldEncryptedValue);
// Re-encrypt with new key
EncryptOptions newEncryptOptions = new EncryptOptions("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic")
.keyId(newKeyId);
BsonBinary newEncryptedValue = clientEncryption.encrypt(decryptedValue, newEncryptOptions);
// Update document
collection.updateOne(
Filters.eq("_id", doc.getObjectId("_id")),
Updates.set("encryptedField", newEncryptedValue)
);
}
// Delete old key after re-encryption
clientEncryption.deleteKey(dataKeyId);Support for encrypted fields that can still be queried efficiently.
// Create encrypted collection with queryable encryption
CreateCollectionOptions collectionOptions = new CreateCollectionOptions();
// Define encrypted fields for queryable encryption
BsonDocument encryptedFields = new BsonDocument()
.append("fields", new BsonArray(Arrays.asList(
new BsonDocument()
.append("path", new BsonString("ssn"))
.append("bsonType", new BsonString("string"))
.append("keyId", dataKeyId)
.append("queries", new BsonDocument()
.append("queryType", new BsonString("equality"))),
new BsonDocument()
.append("path", new BsonString("salary"))
.append("bsonType", new BsonString("int"))
.append("keyId", dataKeyId)
.append("queries", new BsonDocument()
.append("queryType", new BsonString("range"))
.append("sparsity", new BsonInt64(1))
.append("min", new BsonInt32(30000))
.append("max", new BsonInt32(200000)))
)));
CreateEncryptedCollectionParams encryptedParams = new CreateEncryptedCollectionParams(
kmsProviders
).encryptedFields(encryptedFields);
BsonDocument createdCollection = clientEncryption.createEncryptedCollection(
database, "employees", collectionOptions, encryptedParams
);
// Query encrypted fields (requires properly configured MongoClient)
MongoCollection<Document> encryptedCollection = database.getCollection("employees");
// Equality query on encrypted field
Document employee = encryptedCollection.find(Filters.eq("ssn", "123-45-6789")).first();
// Range query on encrypted field
FindIterable<Document> highEarners = encryptedCollection.find(
Filters.gte("salary", 100000)
);Setting up automatic client-side field level encryption for seamless operation.
// Configure automatic encryption
Map<String, BsonDocument> schemaMap = new HashMap<>();
schemaMap.put("myapp.customers", new BsonDocument()
.append("bsonType", new BsonString("object"))
.append("properties", new BsonDocument()
.append("ssn", new BsonDocument()
.append("encrypt", new BsonDocument()
.append("bsonType", new BsonString("string"))
.append("algorithm", new BsonString("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"))
.append("keyId", new BsonArray(Arrays.asList(dataKeyId)))))
.append("creditCard", new BsonDocument()
.append("encrypt", new BsonDocument()
.append("bsonType", new BsonString("string"))
.append("algorithm", new BsonString("AEAD_AES_256_CBC_HMAC_SHA_512-Random"))
.append("keyId", new BsonArray(Arrays.asList(dataKeyId)))))));
// Create MongoClient with automatic encryption
AutoEncryptionSettings autoEncryptionSettings = AutoEncryptionSettings.builder()
.keyVaultNamespace("encryption.__keyVault")
.kmsProviders(kmsProviders)
.schemaMap(schemaMap)
.build();
MongoClientSettings clientSettings = MongoClientSettings.builder()
.applyConnectionString(new ConnectionString("mongodb://localhost:27017"))
.autoEncryptionSettings(autoEncryptionSettings)
.build();
try (MongoClient encryptedClient = MongoClients.create(clientSettings)) {
MongoDatabase db = encryptedClient.getDatabase("myapp");
MongoCollection<Document> customers = db.getCollection("customers");
// Fields are automatically encrypted on insert
Document customer = new Document("name", "Jane Smith")
.append("ssn", "987-65-4321") // Encrypted deterministically
.append("creditCard", "4111-1111-1111-1111") // Encrypted randomly
.append("email", "jane@example.com"); // Not encrypted
customers.insertOne(customer);
// SSN can be queried (deterministic encryption)
Document found = customers.find(Filters.eq("ssn", "987-65-4321")).first();
// Credit card is automatically decrypted on retrieval
System.out.println("Customer: " + found.getString("name"));
System.out.println("Email: " + found.getString("email"));
// SSN and creditCard are automatically decrypted
}Proper error handling and security best practices for encryption operations.
try (ClientEncryption clientEncryption = ClientEncryptions.create(encryptionSettings)) {
// Handle encryption errors
try {
BsonBinary encrypted = clientEncryption.encrypt(
new BsonString("sensitive-data"),
encryptOptions
);
} catch (MongoEncryptionException e) {
if (e.getMessage().contains("key not found")) {
// Handle missing encryption key
System.err.println("Encryption key not found: " + e.getMessage());
// Create new key or use alternate key
} else {
// Handle other encryption errors
System.err.println("Encryption failed: " + e.getMessage());
throw e;
}
}
// Handle decryption errors
try {
BsonValue decrypted = clientEncryption.decrypt(encryptedValue);
} catch (MongoEncryptionException e) {
if (e.getMessage().contains("not encrypted")) {
// Value might not be encrypted
System.warn("Attempted to decrypt non-encrypted value");
return originalValue;
} else {
System.err.println("Decryption failed: " + e.getMessage());
throw e;
}
}
// Key management best practices
// Regular key rotation
scheduleKeyRotation(clientEncryption, TimeUnit.DAYS.toMillis(90));
// Secure key storage
storeKeySecurely(dataKeyId, "customer-ssn-key");
// Audit encrypted operations
auditEncryptionOperation("encrypt", "customer.ssn", dataKeyId);
} catch (Exception e) {
// Ensure sensitive data is not logged
System.err.println("Encryption operation failed: " + sanitizeErrorMessage(e.getMessage()));
throw e;
}
// Performance optimization for bulk operations
private void bulkEncryptFields(List<Document> documents, ClientEncryption encryption) {
// Pre-create encrypt options to avoid repeated object creation
EncryptOptions deterministicOptions = new EncryptOptions("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic")
.keyId(dataKeyId);
EncryptOptions randomOptions = new EncryptOptions("AEAD_AES_256_CBC_HMAC_SHA_512-Random")
.keyId(dataKeyId);
for (Document doc : documents) {
// Encrypt deterministic fields (queryable)
if (doc.containsKey("ssn")) {
BsonString ssn = new BsonString(doc.getString("ssn"));
doc.put("ssn", encryption.encrypt(ssn, deterministicOptions));
}
// Encrypt random fields (higher security)
if (doc.containsKey("notes")) {
BsonString notes = new BsonString(doc.getString("notes"));
doc.put("notes", encryption.encrypt(notes, randomOptions));
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-mongodb--mongodb-driver-sync