or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

change-streams.mdcollection-crud.mdconnection-management.mddatabase-operations.mdencryption.mdgridfs.mdindex-management.mdindex.mdquery-aggregation.mdsessions-transactions.md

encryption.mddocs/

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

```