0
# Client-Side Field Level Encryption
1
2
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.
3
4
## Capabilities
5
6
### ClientEncryptions Factory
7
8
Factory class for creating ClientEncryption instances with configuration for key management services and encryption options.
9
10
```java { .api }
11
/**
12
* Factory for creating ClientEncryption instances
13
*/
14
public final class ClientEncryptions {
15
/**
16
* Creates a client encryption instance with specified options
17
* @param clientEncryptionSettings configuration for encryption operations
18
* @return ClientEncryption instance for key management and field encryption
19
*/
20
public static ClientEncryption create(ClientEncryptionSettings clientEncryptionSettings);
21
}
22
```
23
24
**Usage Examples:**
25
26
```java
27
import com.mongodb.client.vault.ClientEncryption;
28
import com.mongodb.client.vault.ClientEncryptions;
29
import com.mongodb.ClientEncryptionSettings;
30
import com.mongodb.MongoClientSettings;
31
32
// Configure encryption settings
33
Map<String, Map<String, Object>> kmsProviders = new HashMap<>();
34
Map<String, Object> localMasterKey = new HashMap<>();
35
localMasterKey.put("key", localMasterKeyBytes);
36
kmsProviders.put("local", localMasterKey);
37
38
ClientEncryptionSettings encryptionSettings = ClientEncryptionSettings.builder()
39
.keyVaultMongoClientSettings(MongoClientSettings.builder()
40
.applyConnectionString(new ConnectionString("mongodb://localhost:27017"))
41
.build())
42
.keyVaultNamespace("encryption.__keyVault")
43
.kmsProviders(kmsProviders)
44
.build();
45
46
ClientEncryption clientEncryption = ClientEncryptions.create(encryptionSettings);
47
```
48
49
### ClientEncryption Interface
50
51
Primary interface for client-side field level encryption operations including data key management and field encryption/decryption.
52
53
```java { .api }
54
/**
55
* Interface for client-side field level encryption operations
56
*/
57
public interface ClientEncryption extends AutoCloseable {
58
/**
59
* Creates a new data key for encryption
60
* @param kmsProvider the key management service provider name
61
* @return BsonBinary containing the data key ID
62
*/
63
BsonBinary createDataKey(String kmsProvider);
64
65
/**
66
* Creates a new data key with additional options
67
* @param kmsProvider the key management service provider name
68
* @param dataKeyOptions additional options for data key creation
69
* @return BsonBinary containing the data key ID
70
*/
71
BsonBinary createDataKey(String kmsProvider, DataKeyOptions dataKeyOptions);
72
73
/**
74
* Deletes a data key from the key vault
75
* @param id the data key ID to delete
76
* @return DeleteResult indicating the outcome of the delete operation
77
*/
78
DeleteResult deleteKey(BsonBinary id);
79
80
/**
81
* Encrypts a value using client-side field level encryption
82
* @param value the value to encrypt as BsonValue
83
* @param options encryption options including algorithm and key
84
* @return BsonBinary containing the encrypted value
85
*/
86
BsonBinary encrypt(BsonValue value, EncryptOptions options);
87
88
/**
89
* Decrypts an encrypted value
90
* @param encryptedValue the encrypted value as BsonBinary
91
* @return BsonValue containing the decrypted value
92
*/
93
BsonValue decrypt(BsonBinary encryptedValue);
94
95
/**
96
* Encrypts an expression for queryable encryption
97
* @param expression the expression to encrypt as Bson
98
* @param options encryption options for the expression
99
* @return BsonDocument containing the encrypted expression
100
*/
101
BsonDocument encryptExpression(Bson expression, EncryptOptions options);
102
103
/**
104
* Retrieves a data key by its ID
105
* @param id the data key ID
106
* @return BsonDocument containing the data key information
107
*/
108
BsonDocument getKey(BsonBinary id);
109
110
/**
111
* Retrieves all data keys
112
* @return FindIterable for iterating over all data keys
113
*/
114
FindIterable<BsonDocument> getKeys();
115
116
/**
117
* Adds an alternate name to a data key
118
* @param id the data key ID
119
* @param keyAltName the alternate name to add
120
* @return BsonDocument containing the updated data key
121
*/
122
BsonDocument addKeyAltName(BsonBinary id, String keyAltName);
123
124
/**
125
* Removes an alternate name from a data key
126
* @param id the data key ID
127
* @param keyAltName the alternate name to remove
128
* @return BsonDocument containing the updated data key or null if no change
129
*/
130
BsonDocument removeKeyAltName(BsonBinary id, String keyAltName);
131
132
/**
133
* Retrieves a data key by its alternate name
134
* @param keyAltName the alternate name to search for
135
* @return BsonDocument containing the data key or null if not found
136
*/
137
BsonDocument getKeyByAltName(String keyAltName);
138
139
/**
140
* Re-wraps multiple data keys with new encryption
141
* @param filter filter to select which data keys to re-wrap
142
* @return RewrapManyDataKeyResult containing information about the operation
143
*/
144
RewrapManyDataKeyResult rewrapManyDataKey(Bson filter);
145
146
/**
147
* Re-wraps multiple data keys with new encryption and options
148
* @param filter filter to select which data keys to re-wrap
149
* @param options options for the re-wrap operation
150
* @return RewrapManyDataKeyResult containing information about the operation
151
*/
152
RewrapManyDataKeyResult rewrapManyDataKey(Bson filter, RewrapManyDataKeyOptions options);
153
154
/**
155
* Creates an encrypted collection with queryable encryption
156
* @param database the database to create the collection in
157
* @param collectionName the name of the collection to create
158
* @param createCollectionOptions options for collection creation
159
* @param createEncryptedCollectionParams parameters for encrypted collection setup
160
* @return BsonDocument containing the created collection information
161
*/
162
BsonDocument createEncryptedCollection(MongoDatabase database,
163
String collectionName,
164
CreateCollectionOptions createCollectionOptions,
165
CreateEncryptedCollectionParams createEncryptedCollectionParams);
166
167
/**
168
* Closes the client encryption instance and releases resources
169
*/
170
void close();
171
}
172
```
173
174
**Usage Examples:**
175
176
```java
177
import com.mongodb.client.model.vault.DataKeyOptions;
178
import com.mongodb.client.model.vault.EncryptOptions;
179
import org.bson.BsonString;
180
import org.bson.BsonInt32;
181
182
try (ClientEncryption clientEncryption = ClientEncryptions.create(encryptionSettings)) {
183
184
// Create a data key for field encryption
185
BsonBinary dataKeyId = clientEncryption.createDataKey("local");
186
System.out.println("Created data key: " + dataKeyId);
187
188
// Create data key with alternate name
189
DataKeyOptions keyOptions = new DataKeyOptions()
190
.keyAltNames(Arrays.asList("customer-ssn-key", "pii-key"));
191
BsonBinary namedKeyId = clientEncryption.createDataKey("local", keyOptions);
192
193
// Encrypt sensitive data
194
EncryptOptions encryptOptions = new EncryptOptions("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic")
195
.keyId(dataKeyId);
196
197
BsonString sensitiveValue = new BsonString("123-45-6789");
198
BsonBinary encryptedSSN = clientEncryption.encrypt(sensitiveValue, encryptOptions);
199
200
// Store encrypted value in document
201
Document customer = new Document("name", "John Doe")
202
.append("ssn", encryptedSSN)
203
.append("email", "john@example.com");
204
205
collection.insertOne(customer);
206
207
// Retrieve and decrypt
208
Document retrievedCustomer = collection.find(Filters.eq("name", "John Doe")).first();
209
BsonBinary encryptedValue = retrievedCustomer.get("ssn", BsonBinary.class);
210
BsonValue decryptedSSN = clientEncryption.decrypt(encryptedValue);
211
212
System.out.println("Decrypted SSN: " + decryptedSSN.asString().getValue());
213
}
214
```
215
216
### Data Key Management
217
218
Comprehensive data key lifecycle management including creation, rotation, and organization.
219
220
```java { .api }
221
// Advanced data key creation with AWS KMS
222
Map<String, Object> awsKmsProviders = new HashMap<>();
223
Map<String, Object> awsCredentials = new HashMap<>();
224
awsCredentials.put("accessKeyId", "AWS_ACCESS_KEY_ID");
225
awsCredentials.put("secretAccessKey", "AWS_SECRET_ACCESS_KEY");
226
awsKmsProviders.put("aws", awsCredentials);
227
228
// Create data key with AWS KMS
229
DataKeyOptions awsKeyOptions = new DataKeyOptions()
230
.keyAltNames(Arrays.asList("customer-data-key"))
231
.masterKey(new BsonDocument()
232
.append("region", new BsonString("us-east-1"))
233
.append("key", new BsonString("arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012")));
234
235
BsonBinary awsDataKeyId = clientEncryption.createDataKey("aws", awsKeyOptions);
236
237
// Key rotation - create new key and re-encrypt data
238
BsonBinary newKeyId = clientEncryption.createDataKey("local");
239
240
// Find documents with old encrypted data
241
FindIterable<Document> documentsToReEncrypt = collection.find(
242
Filters.exists("encryptedField")
243
);
244
245
for (Document doc : documentsToReEncrypt) {
246
BsonBinary oldEncryptedValue = doc.get("encryptedField", BsonBinary.class);
247
BsonValue decryptedValue = clientEncryption.decrypt(oldEncryptedValue);
248
249
// Re-encrypt with new key
250
EncryptOptions newEncryptOptions = new EncryptOptions("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic")
251
.keyId(newKeyId);
252
BsonBinary newEncryptedValue = clientEncryption.encrypt(decryptedValue, newEncryptOptions);
253
254
// Update document
255
collection.updateOne(
256
Filters.eq("_id", doc.getObjectId("_id")),
257
Updates.set("encryptedField", newEncryptedValue)
258
);
259
}
260
261
// Delete old key after re-encryption
262
clientEncryption.deleteKey(dataKeyId);
263
```
264
265
### Queryable Encryption
266
267
Support for encrypted fields that can still be queried efficiently.
268
269
```java { .api }
270
// Create encrypted collection with queryable encryption
271
CreateCollectionOptions collectionOptions = new CreateCollectionOptions();
272
273
// Define encrypted fields for queryable encryption
274
BsonDocument encryptedFields = new BsonDocument()
275
.append("fields", new BsonArray(Arrays.asList(
276
new BsonDocument()
277
.append("path", new BsonString("ssn"))
278
.append("bsonType", new BsonString("string"))
279
.append("keyId", dataKeyId)
280
.append("queries", new BsonDocument()
281
.append("queryType", new BsonString("equality"))),
282
new BsonDocument()
283
.append("path", new BsonString("salary"))
284
.append("bsonType", new BsonString("int"))
285
.append("keyId", dataKeyId)
286
.append("queries", new BsonDocument()
287
.append("queryType", new BsonString("range"))
288
.append("sparsity", new BsonInt64(1))
289
.append("min", new BsonInt32(30000))
290
.append("max", new BsonInt32(200000)))
291
)));
292
293
CreateEncryptedCollectionParams encryptedParams = new CreateEncryptedCollectionParams(
294
kmsProviders
295
).encryptedFields(encryptedFields);
296
297
BsonDocument createdCollection = clientEncryption.createEncryptedCollection(
298
database, "employees", collectionOptions, encryptedParams
299
);
300
301
// Query encrypted fields (requires properly configured MongoClient)
302
MongoCollection<Document> encryptedCollection = database.getCollection("employees");
303
304
// Equality query on encrypted field
305
Document employee = encryptedCollection.find(Filters.eq("ssn", "123-45-6789")).first();
306
307
// Range query on encrypted field
308
FindIterable<Document> highEarners = encryptedCollection.find(
309
Filters.gte("salary", 100000)
310
);
311
```
312
313
### Automatic Encryption Configuration
314
315
Setting up automatic client-side field level encryption for seamless operation.
316
317
```java { .api }
318
// Configure automatic encryption
319
Map<String, BsonDocument> schemaMap = new HashMap<>();
320
schemaMap.put("myapp.customers", new BsonDocument()
321
.append("bsonType", new BsonString("object"))
322
.append("properties", new BsonDocument()
323
.append("ssn", new BsonDocument()
324
.append("encrypt", new BsonDocument()
325
.append("bsonType", new BsonString("string"))
326
.append("algorithm", new BsonString("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"))
327
.append("keyId", new BsonArray(Arrays.asList(dataKeyId)))))
328
.append("creditCard", new BsonDocument()
329
.append("encrypt", new BsonDocument()
330
.append("bsonType", new BsonString("string"))
331
.append("algorithm", new BsonString("AEAD_AES_256_CBC_HMAC_SHA_512-Random"))
332
.append("keyId", new BsonArray(Arrays.asList(dataKeyId)))))));
333
334
// Create MongoClient with automatic encryption
335
AutoEncryptionSettings autoEncryptionSettings = AutoEncryptionSettings.builder()
336
.keyVaultNamespace("encryption.__keyVault")
337
.kmsProviders(kmsProviders)
338
.schemaMap(schemaMap)
339
.build();
340
341
MongoClientSettings clientSettings = MongoClientSettings.builder()
342
.applyConnectionString(new ConnectionString("mongodb://localhost:27017"))
343
.autoEncryptionSettings(autoEncryptionSettings)
344
.build();
345
346
try (MongoClient encryptedClient = MongoClients.create(clientSettings)) {
347
MongoDatabase db = encryptedClient.getDatabase("myapp");
348
MongoCollection<Document> customers = db.getCollection("customers");
349
350
// Fields are automatically encrypted on insert
351
Document customer = new Document("name", "Jane Smith")
352
.append("ssn", "987-65-4321") // Encrypted deterministically
353
.append("creditCard", "4111-1111-1111-1111") // Encrypted randomly
354
.append("email", "jane@example.com"); // Not encrypted
355
356
customers.insertOne(customer);
357
358
// SSN can be queried (deterministic encryption)
359
Document found = customers.find(Filters.eq("ssn", "987-65-4321")).first();
360
361
// Credit card is automatically decrypted on retrieval
362
System.out.println("Customer: " + found.getString("name"));
363
System.out.println("Email: " + found.getString("email"));
364
// SSN and creditCard are automatically decrypted
365
}
366
```
367
368
### Error Handling and Best Practices
369
370
Proper error handling and security best practices for encryption operations.
371
372
```java { .api }
373
try (ClientEncryption clientEncryption = ClientEncryptions.create(encryptionSettings)) {
374
375
// Handle encryption errors
376
try {
377
BsonBinary encrypted = clientEncryption.encrypt(
378
new BsonString("sensitive-data"),
379
encryptOptions
380
);
381
} catch (MongoEncryptionException e) {
382
if (e.getMessage().contains("key not found")) {
383
// Handle missing encryption key
384
System.err.println("Encryption key not found: " + e.getMessage());
385
// Create new key or use alternate key
386
} else {
387
// Handle other encryption errors
388
System.err.println("Encryption failed: " + e.getMessage());
389
throw e;
390
}
391
}
392
393
// Handle decryption errors
394
try {
395
BsonValue decrypted = clientEncryption.decrypt(encryptedValue);
396
} catch (MongoEncryptionException e) {
397
if (e.getMessage().contains("not encrypted")) {
398
// Value might not be encrypted
399
System.warn("Attempted to decrypt non-encrypted value");
400
return originalValue;
401
} else {
402
System.err.println("Decryption failed: " + e.getMessage());
403
throw e;
404
}
405
}
406
407
// Key management best practices
408
409
// Regular key rotation
410
scheduleKeyRotation(clientEncryption, TimeUnit.DAYS.toMillis(90));
411
412
// Secure key storage
413
storeKeySecurely(dataKeyId, "customer-ssn-key");
414
415
// Audit encrypted operations
416
auditEncryptionOperation("encrypt", "customer.ssn", dataKeyId);
417
418
} catch (Exception e) {
419
// Ensure sensitive data is not logged
420
System.err.println("Encryption operation failed: " + sanitizeErrorMessage(e.getMessage()));
421
throw e;
422
}
423
424
// Performance optimization for bulk operations
425
private void bulkEncryptFields(List<Document> documents, ClientEncryption encryption) {
426
// Pre-create encrypt options to avoid repeated object creation
427
EncryptOptions deterministicOptions = new EncryptOptions("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic")
428
.keyId(dataKeyId);
429
430
EncryptOptions randomOptions = new EncryptOptions("AEAD_AES_256_CBC_HMAC_SHA_512-Random")
431
.keyId(dataKeyId);
432
433
for (Document doc : documents) {
434
// Encrypt deterministic fields (queryable)
435
if (doc.containsKey("ssn")) {
436
BsonString ssn = new BsonString(doc.getString("ssn"));
437
doc.put("ssn", encryption.encrypt(ssn, deterministicOptions));
438
}
439
440
// Encrypt random fields (higher security)
441
if (doc.containsKey("notes")) {
442
BsonString notes = new BsonString(doc.getString("notes"));
443
doc.put("notes", encryption.encrypt(notes, randomOptions));
444
}
445
}
446
}
447
```