Docs Menu
Docs Home
/ /

In-Use Encryption

In-Use Encryption provides two features that encrypt sensitive data in your MongoDB collections:

  • Client-Side Field Level Encryption - Encrypts specific data fields client-side

  • Queryable Encryption - Encrypts data while maintaining the ability to query encrypted fields

Both features guarantee that unauthorized parties, including server administrators, cannot read encrypted data.

You must install libmongocrypt as a dependency to use In-Use Encryption. See the libmongocrypt installation instructions in the MongoDB Server manual for a complete installation guide.

After you install libmongocrypt, configure the C driver with -DENABLE_CLIENT_SIDE_ENCRYPTION=ON to enable In-Use Encryption, as shown in the following example:

$ cd mongo-c-driver
$ mkdir cmake-build && cd cmake-build
$ cmake -DENABLE_CLIENT_SIDE_ENCRYPTION=ON ..
$ cmake --build . --target install

To support automatic encryption, you need one of the following dependencies:

  • The mongocryptd executable. See the mongocryptd guide in the MongoDB Server manual for installation instructions.

  • The crypt_shared library. See the Automatic Encryption Shared Library guide in the MongoDB Server manual for more information.

A mongoc_client_t or mongoc_client_pool_t configured with auto encryption automatically tries to load the crypt_shared library. If loading the crypt_shared library fails, the mongoc_client_t or mongoc_client_pool_t tries to spawn the mongocryptd process from the application's PATH. To configure use of crypt_shared and mongocryptd, see mongoc_auto_encryption_opts_set_extra.

Use mongoc_client_encryption_t for explicit encryption and key management. Use mongoc_client_enable_auto_encryption and mongoc_client_pool_enable_auto_encryption to enable automatic encryption.

The Queryable Encryption (QE) and Client-Side Field Level Encryption (CSFLE) features share much of the same API, with some exceptions:

CSFLE enables administrators and developers to encrypt specific data fields in addition to other MongoDB encryption features.

By using CSFLE, you can encrypt fields client side without any server-side configuration or directives. CSFLE supports workloads where applications must guarantee that unauthorized parties, including server administrators, cannot read encrypted data.

Automatic encryption, where sensitive fields in commands encrypt automatically, requires an Enterprise-only dependency for Query Analysis. See Query Analysis for more information.

Tip

The Client-Side Field Level Encryption guide in the MongoDB Server manual

Enable automatic encryption by calling mongoc_client_enable_auto_encryption on a mongoc_client_t object. The following examples show how to set up automatic encryption by using mongoc_client_encryption_t to create a new encryption data key.

Note

Automatic encryption requires MongoDB Enterprise Advanced 4.2 or later, or a MongoDB 4.2 or later Atlas cluster. The community version of MongoDB Server supports automatic decryption and Explicit Encryption.

You can specify automatic encryption rules by using a schema map. To create a schema map, call the mongoc_auto_encryption_opts_set_schema_map function. The automatic encryption rules use a strict subset of the JSON Schema syntax.

Supplying a schema map provides more security than relying on JSON Schemas obtained from the server. It protects against a malicious server advertising a false JSON Schema, which could trick the client into sending unencrypted data that should be encrypted.

JSON Schemas supplied in the schema map only apply to configuring automatic encryption. Other validation rules in the JSON schema are not enforced by the driver and result in an error.

The following example uses the mongoc_auto_encryption_opts_set_schema_map() function to create a schema map that specifies automatic encryption rules:

client-side-encryption-schema-map.c
#include <mongoc/mongoc.h>
#include <stdio.h>
#include <stdlib.h>
#define FAIL(...) \
fprintf(stderr, "Error [%s:%d]:\n", __FILE__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
abort();
// `init_bson` creates BSON from JSON. Aborts on error. Use the `BSON_STR()` macro to avoid quotes.
#define init_bson(bson, json) \
if (!bson_init_from_json(&bson, json, -1, &error)) { \
FAIL("Failed to create BSON: %s", error.message); \
}
int
main(void)
{
bson_error_t error;
// The key vault collection stores encrypted data keys:
const char *keyvault_db_name = "keyvault";
const char *keyvault_coll_name = "datakeys";
// The encrypted collection stores application data:
const char *encrypted_db_name = "db";
const char *encrypted_coll_name = "coll";
// Set `local_key` to a 96 byte base64-encoded string:
const char *local_key =
"qx/3ydlPRXgUrBvSBWLsllUTaYDcS/pyaVo27qBHkS2AFePjInwhzCmDWHdmCYPmzhO4lRBzeZKFjSafduLL5z5DMvR/"
"QFfV4zc7btcVmV3QWbDwqZyn6G+Y18ToLHyK";
const char *uri = "mongodb://localhost/?appname=client-side-encryption";
mongoc_init();
// Configure KMS providers used to encrypt data keys:
bson_t kms_providers;
{
char *as_json = bson_strdup_printf(BSON_STR({"local" : {"key" : "%s"}}), local_key);
init_bson(kms_providers, as_json);
bson_free(as_json);
}
// Set up key vault collection:
mongoc_client_t *keyvault_client;
{
keyvault_client = mongoc_client_new(uri);
if (!keyvault_client) {
FAIL("Failed to create keyvault client");
}
mongoc_collection_t *coll = mongoc_client_get_collection(keyvault_client, keyvault_db_name, keyvault_coll_name);
mongoc_collection_drop(coll, NULL); // Clear pre-existing data.
// Create index to ensure keys have unique keyAltNames:
bson_t index_keys, index_opts;
init_bson(index_keys, BSON_STR({"keyAltNames" : 1}));
init_bson(index_opts,
BSON_STR({"unique" : true, "partialFilterExpression" : {"keyAltNames" : {"$exists" : true}}}));
mongoc_index_model_t *index_model = mongoc_index_model_new(&index_keys, &index_opts);
if (!mongoc_collection_create_indexes_with_opts(
coll, &index_model, 1, NULL /* opts */, NULL /* reply */, &error)) {
FAIL("Failed to create index: %s", error.message);
}
mongoc_index_model_destroy(index_model);
bson_destroy(&index_opts);
bson_destroy(&index_keys);
mongoc_collection_destroy(coll);
}
// Create ClientEncryption object:
mongoc_client_encryption_t *client_encryption;
{
mongoc_client_encryption_opts_t *ce_opts = mongoc_client_encryption_opts_new();
mongoc_client_encryption_opts_set_kms_providers(ce_opts, &kms_providers);
mongoc_client_encryption_opts_set_keyvault_namespace(ce_opts, keyvault_db_name, keyvault_coll_name);
mongoc_client_encryption_opts_set_keyvault_client(ce_opts, keyvault_client);
client_encryption = mongoc_client_encryption_new(ce_opts, &error);
if (!client_encryption) {
FAIL("Failed to create ClientEncryption: %s", error.message);
}
mongoc_client_encryption_opts_destroy(ce_opts);
}
// Create data key (see:
// https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules):
bson_value_t datakey_id;
{
mongoc_client_encryption_datakey_opts_t *dk_opts = mongoc_client_encryption_datakey_opts_new();
if (!mongoc_client_encryption_create_datakey(client_encryption, "local", dk_opts, &datakey_id, &error)) {
FAIL("Failed to create data key: %s", error.message);
}
mongoc_client_encryption_datakey_opts_destroy(dk_opts);
}
// Create a schema map:
bson_t schema_map = BSON_INITIALIZER;
{
/*
{
"db.coll": {
"properties" : {
"encryptedField" : {
"encrypt" : {
"keyId" : [ "<key ID>" ],
"bsonType" : "string",
"algorithm" : "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
}
}
},
"bsonType" : "object"
}
}
*/
bson_t key_ids = BSON_INITIALIZER;
BSON_APPEND_VALUE(&key_ids, "0", &datakey_id);
bson_t encrypt = BSON_INITIALIZER;
BSON_APPEND_ARRAY(&encrypt, "keyId", &key_ids);
BSON_APPEND_UTF8(&encrypt, "bsonType", "string");
BSON_APPEND_UTF8(&encrypt, "algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic");
bson_t encryptedField = BSON_INITIALIZER;
BSON_APPEND_DOCUMENT(&encryptedField, "encrypt", &encrypt);
bson_t properties = BSON_INITIALIZER;
BSON_APPEND_DOCUMENT(&properties, "encryptedField", &encryptedField);
bson_t db_coll = BSON_INITIALIZER;
BSON_APPEND_DOCUMENT(&db_coll, "properties", &properties);
BSON_APPEND_UTF8(&db_coll, "bsonType", "object");
BSON_APPEND_DOCUMENT(&schema_map, "db.coll", &db_coll);
bson_destroy(&key_ids);
bson_destroy(&db_coll);
bson_destroy(&encrypt);
bson_destroy(&encryptedField);
bson_destroy(&properties);
}
// Create client configured to automatically encrypt:
mongoc_client_t *encrypted_client;
{
encrypted_client = mongoc_client_new(uri);
if (!encrypted_client) {
FAIL("Failed to create client");
}
mongoc_auto_encryption_opts_t *ae_opts = mongoc_auto_encryption_opts_new();
mongoc_auto_encryption_opts_set_schema_map(ae_opts, &schema_map);
mongoc_auto_encryption_opts_set_keyvault_namespace(ae_opts, keyvault_db_name, keyvault_coll_name);
mongoc_auto_encryption_opts_set_kms_providers(ae_opts, &kms_providers);
if (!mongoc_client_enable_auto_encryption(encrypted_client, ae_opts, &error)) {
FAIL("Failed to enable auto encryption: %s", error.message);
}
mongoc_auto_encryption_opts_destroy(ae_opts);
}
// Insert a document:
mongoc_collection_t *encrypted_coll =
mongoc_client_get_collection(encrypted_client, encrypted_db_name, encrypted_coll_name);
{
mongoc_collection_drop(encrypted_coll, NULL); // Clear pre-existing data.
bson_t to_insert = BSON_INITIALIZER;
BSON_APPEND_UTF8(&to_insert, "encryptedField", "foobar");
if (!mongoc_collection_insert_one(encrypted_coll, &to_insert, NULL /* opts */, NULL /* reply */, &error)) {
FAIL("Failed to insert: %s", error.message);
}
char *as_str = bson_as_relaxed_extended_json(&to_insert, NULL);
printf("Inserted document with automatic encryption: %s\n", as_str);
bson_free(as_str);
bson_destroy(&to_insert);
}
// Retrieve document with automatic decryption:
{
bson_t filter = BSON_INITIALIZER;
mongoc_cursor_t *cursor = mongoc_collection_find_with_opts(encrypted_coll, &filter, NULL, NULL);
const bson_t *result;
if (!mongoc_cursor_next(cursor, &result)) {
FAIL("Failed to find inserted document: %s", error.message);
}
char *as_str = bson_as_relaxed_extended_json(result, NULL);
printf("Retrieved document with automatic decryption: %s\n", as_str);
bson_free(as_str);
mongoc_cursor_destroy(cursor);
bson_destroy(&filter);
}
// Retrieve document without decryption:
{
mongoc_collection_t *unencrypted_coll =
mongoc_client_get_collection(keyvault_client, encrypted_db_name, encrypted_coll_name);
bson_t filter = BSON_INITIALIZER;
mongoc_cursor_t *cursor = mongoc_collection_find_with_opts(unencrypted_coll, &filter, NULL, NULL);
const bson_t *result;
if (!mongoc_cursor_next(cursor, &result)) {
FAIL("Failed to find inserted document: %s", error.message);
}
char *as_str = bson_as_relaxed_extended_json(result, NULL);
printf("Retrieved document without automatic decryption: %s\n", as_str);
bson_free(as_str);
mongoc_cursor_destroy(cursor);
bson_destroy(&filter);
mongoc_collection_destroy(unencrypted_coll);
}
mongoc_collection_destroy(encrypted_coll);
mongoc_client_destroy(encrypted_client);
bson_destroy(&schema_map);
bson_value_destroy(&datakey_id);
mongoc_client_encryption_destroy(client_encryption);
bson_destroy(&kms_providers);
mongoc_client_destroy(keyvault_client);
mongoc_cleanup();
return 0;
}

MongoDB Server supports using schema validation to enforce encryption of specific fields in a collection. This schema validation prevents an application from inserting unencrypted values for any fields marked with the encrypt JSON Schema keyword.

To implement server-side enforcement, you must create both an encryption data key and a collection configured with the appropriate JSON Schema validation rules, as shown in the following example:

client-side-encryption-server-schema.c
#include <mongoc/mongoc.h>
#include <stdio.h>
#include <stdlib.h>
#define FAIL(...) \
fprintf(stderr, "Error [%s:%d]:\n", __FILE__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
abort();
// `init_bson` creates BSON from JSON. Aborts on error. Use the `BSON_STR()` macro to avoid quotes.
#define init_bson(bson, json) \
if (!bson_init_from_json(&bson, json, -1, &error)) { \
FAIL("Failed to create BSON: %s", error.message); \
}
int
main(void)
{
bson_error_t error;
// The key vault collection stores encrypted data keys:
const char *keyvault_db_name = "keyvault";
const char *keyvault_coll_name = "datakeys";
// The encrypted collection stores application data:
const char *encrypted_db_name = "db";
const char *encrypted_coll_name = "coll";
// Set `local_key` to a 96 byte base64-encoded string:
const char *local_key =
"qx/3ydlPRXgUrBvSBWLsllUTaYDcS/pyaVo27qBHkS2AFePjInwhzCmDWHdmCYPmzhO4lRBzeZKFjSafduLL5z5DMvR/"
"QFfV4zc7btcVmV3QWbDwqZyn6G+Y18ToLHyK";
const char *uri = "mongodb://localhost/?appname=client-side-encryption";
mongoc_init();
// Configure KMS providers used to encrypt data keys:
bson_t kms_providers;
{
char *as_json = bson_strdup_printf(BSON_STR({"local" : {"key" : "%s"}}), local_key);
init_bson(kms_providers, as_json);
bson_free(as_json);
}
// Set up key vault collection:
mongoc_client_t *keyvault_client;
{
keyvault_client = mongoc_client_new(uri);
if (!keyvault_client) {
FAIL("Failed to create keyvault client");
}
mongoc_collection_t *coll = mongoc_client_get_collection(keyvault_client, keyvault_db_name, keyvault_coll_name);
mongoc_collection_drop(coll, NULL); // Clear pre-existing data.
// Create index to ensure keys have unique keyAltNames:
bson_t index_keys, index_opts;
init_bson(index_keys, BSON_STR({"keyAltNames" : 1}));
init_bson(index_opts,
BSON_STR({"unique" : true, "partialFilterExpression" : {"keyAltNames" : {"$exists" : true}}}));
mongoc_index_model_t *index_model = mongoc_index_model_new(&index_keys, &index_opts);
if (!mongoc_collection_create_indexes_with_opts(
coll, &index_model, 1, NULL /* opts */, NULL /* reply */, &error)) {
FAIL("Failed to create index: %s", error.message);
}
mongoc_index_model_destroy(index_model);
bson_destroy(&index_opts);
bson_destroy(&index_keys);
mongoc_collection_destroy(coll);
}
// Create ClientEncryption object:
mongoc_client_encryption_t *client_encryption;
{
mongoc_client_encryption_opts_t *ce_opts = mongoc_client_encryption_opts_new();
mongoc_client_encryption_opts_set_kms_providers(ce_opts, &kms_providers);
mongoc_client_encryption_opts_set_keyvault_namespace(ce_opts, keyvault_db_name, keyvault_coll_name);
mongoc_client_encryption_opts_set_keyvault_client(ce_opts, keyvault_client);
client_encryption = mongoc_client_encryption_new(ce_opts, &error);
if (!client_encryption) {
FAIL("Failed to create ClientEncryption: %s", error.message);
}
mongoc_client_encryption_opts_destroy(ce_opts);
}
// Create data key (see:
// https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules):
bson_value_t datakey_id;
{
mongoc_client_encryption_datakey_opts_t *dk_opts = mongoc_client_encryption_datakey_opts_new();
if (!mongoc_client_encryption_create_datakey(client_encryption, "local", dk_opts, &datakey_id, &error)) {
FAIL("Failed to create data key: %s", error.message);
}
mongoc_client_encryption_datakey_opts_destroy(dk_opts);
}
// Create collection with remote schema:
bson_t schema = BSON_INITIALIZER;
{
/*
{
"properties" : {
"encryptedField" : {
"encrypt" : {
"keyId" : [ "<key ID>" ],
"bsonType" : "string",
"algorithm" : "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
}
}
},
"bsonType" : "object"
}
*/
bson_t key_ids = BSON_INITIALIZER;
BSON_APPEND_VALUE(&key_ids, "0", &datakey_id);
bson_t encrypt = BSON_INITIALIZER;
BSON_APPEND_ARRAY(&encrypt, "keyId", &key_ids);
BSON_APPEND_UTF8(&encrypt, "bsonType", "string");
BSON_APPEND_UTF8(&encrypt, "algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic");
bson_t encryptedField = BSON_INITIALIZER;
BSON_APPEND_DOCUMENT(&encryptedField, "encrypt", &encrypt);
bson_t properties = BSON_INITIALIZER;
BSON_APPEND_DOCUMENT(&properties, "encryptedField", &encryptedField);
BSON_APPEND_DOCUMENT(&schema, "properties", &properties);
BSON_APPEND_UTF8(&schema, "bsonType", "object");
bson_destroy(&key_ids);
bson_destroy(&encrypt);
bson_destroy(&encryptedField);
bson_destroy(&properties);
}
// Create client configured to automatically encrypt:
mongoc_client_t *encrypted_client;
{
encrypted_client = mongoc_client_new(uri);
if (!encrypted_client) {
FAIL("Failed to create client");
}
mongoc_auto_encryption_opts_t *ae_opts = mongoc_auto_encryption_opts_new();
mongoc_auto_encryption_opts_set_keyvault_namespace(ae_opts, keyvault_db_name, keyvault_coll_name);
mongoc_auto_encryption_opts_set_kms_providers(ae_opts, &kms_providers);
if (!mongoc_client_enable_auto_encryption(encrypted_client, ae_opts, &error)) {
FAIL("Failed to enable auto encryption: %s", error.message);
}
mongoc_auto_encryption_opts_destroy(ae_opts);
}
// Clear pre-existing data:
{
mongoc_collection_t *coll =
mongoc_client_get_collection(encrypted_client, encrypted_db_name, encrypted_coll_name);
mongoc_collection_drop(coll, NULL);
mongoc_collection_destroy(coll);
}
// Create collection with server-side schema:
mongoc_collection_t *encrypted_coll;
{
mongoc_database_t *db = mongoc_client_get_database(encrypted_client, encrypted_db_name);
bson_t create_opts = BSON_INITIALIZER; // { validator: { $jsonSchema: <schema> } }
bson_t json_schema = BSON_INITIALIZER;
BSON_APPEND_DOCUMENT(&json_schema, "$jsonSchema", &schema);
BSON_APPEND_DOCUMENT(&create_opts, "validator", &json_schema);
encrypted_coll = mongoc_database_create_collection(db, encrypted_coll_name, &create_opts, &error);
if (!encrypted_coll) {
FAIL("Failed to create collection: %s", error.message);
}
bson_destroy(&json_schema);
bson_destroy(&create_opts);
mongoc_database_destroy(db);
}
// Insert a document:
{
bson_t to_insert = BSON_INITIALIZER;
BSON_APPEND_UTF8(&to_insert, "encryptedField", "foobar");
if (!mongoc_collection_insert_one(encrypted_coll, &to_insert, NULL /* opts */, NULL /* reply */, &error)) {
FAIL("Failed to insert: %s", error.message);
}
char *as_str = bson_as_relaxed_extended_json(&to_insert, NULL);
printf("Inserted document with automatic encryption: %s\n", as_str);
bson_free(as_str);
bson_destroy(&to_insert);
}
// Retrieve document with automatic decryption:
{
bson_t filter = BSON_INITIALIZER;
mongoc_cursor_t *cursor = mongoc_collection_find_with_opts(encrypted_coll, &filter, NULL, NULL);
const bson_t *result;
if (!mongoc_cursor_next(cursor, &result)) {
FAIL("Failed to find inserted document: %s", error.message);
}
char *as_str = bson_as_relaxed_extended_json(result, NULL);
printf("Retrieved document with automatic decryption: %s\n", as_str);
bson_free(as_str);
mongoc_cursor_destroy(cursor);
bson_destroy(&filter);
}
// Retrieve document without automatic decryption:
{
mongoc_collection_t *unencrypted_coll =
mongoc_client_get_collection(keyvault_client, encrypted_db_name, encrypted_coll_name);
bson_t filter = BSON_INITIALIZER;
mongoc_cursor_t *cursor = mongoc_collection_find_with_opts(unencrypted_coll, &filter, NULL, NULL);
const bson_t *result;
if (!mongoc_cursor_next(cursor, &result)) {
FAIL("Failed to find inserted document: %s", error.message);
}
char *as_str = bson_as_relaxed_extended_json(result, NULL);
printf("Retrieved document without automatic decryption: %s\n", as_str);
bson_free(as_str);
mongoc_cursor_destroy(cursor);
bson_destroy(&filter);
mongoc_collection_destroy(unencrypted_coll);
}
mongoc_collection_destroy(encrypted_coll);
bson_value_destroy(&datakey_id);
mongoc_client_destroy(encrypted_client);
bson_destroy(&schema);
mongoc_client_encryption_destroy(client_encryption);
bson_destroy(&kms_providers);
mongoc_client_destroy(keyvault_client);
mongoc_cleanup();
return 0;
}

You can use explicit encryption to specify how to encrypt fields in your document for each operation you perform on the database. You must define your own encryption data keys and encryption options when using explicit encryption.

Explicit encryption is a MongoDB Community Edition feature and does not use Query Analysis (mongocryptd or crypt_shared). Explicit encryption uses the mongoc_client_encryption_t class. The following example demonstrates how to use explicit encryption and decryption:

client-side-encryption-explicit.c
#include <mongoc/mongoc.h>
#include <stdio.h>
#include <stdlib.h>
#define FAIL(...) \
fprintf(stderr, "Error [%s:%d]:\n", __FILE__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
abort();
// `init_bson` creates BSON from JSON. Aborts on error. Use the `BSON_STR()` macro to avoid quotes.
#define init_bson(bson, json) \
if (!bson_init_from_json(&bson, json, -1, &error)) { \
FAIL("Failed to create BSON: %s", error.message); \
}
int
main(void)
{
bson_error_t error;
// The key vault collection stores encrypted data keys:
const char *keyvault_db_name = "keyvault";
const char *keyvault_coll_name = "datakeys";
// Set `local_key` to a 96 byte base64-encoded string:
const char *local_key =
"qx/3ydlPRXgUrBvSBWLsllUTaYDcS/pyaVo27qBHkS2AFePjInwhzCmDWHdmCYPmzhO4lRBzeZKFjSafduLL5z5DMvR/"
"QFfV4zc7btcVmV3QWbDwqZyn6G+Y18ToLHyK";
const char *uri = "mongodb://localhost/?appname=client-side-encryption";
mongoc_init();
// Create client:
mongoc_client_t *client = mongoc_client_new(uri);
if (!client) {
FAIL("Failed to create client");
}
// Configure KMS providers used to encrypt data keys:
bson_t kms_providers;
{
char *as_json = bson_strdup_printf(BSON_STR({"local" : {"key" : "%s"}}), local_key);
init_bson(kms_providers, as_json);
bson_free(as_json);
}
// Set up key vault collection:
{
mongoc_collection_t *coll = mongoc_client_get_collection(client, keyvault_db_name, keyvault_coll_name);
mongoc_collection_drop(coll, NULL); // Clear pre-existing data.
// Create index to ensure keys have unique keyAltNames:
bson_t index_keys, index_opts;
init_bson(index_keys, BSON_STR({"keyAltNames" : 1}));
init_bson(index_opts,
BSON_STR({"unique" : true, "partialFilterExpression" : {"keyAltNames" : {"$exists" : true}}}));
mongoc_index_model_t *index_model = mongoc_index_model_new(&index_keys, &index_opts);
if (!mongoc_collection_create_indexes_with_opts(
coll, &index_model, 1, NULL /* opts */, NULL /* reply */, &error)) {
FAIL("Failed to create index: %s", error.message);
}
mongoc_index_model_destroy(index_model);
bson_destroy(&index_opts);
bson_destroy(&index_keys);
mongoc_collection_destroy(coll);
}
// Create ClientEncryption object:
mongoc_client_encryption_t *client_encryption;
{
mongoc_client_encryption_opts_t *ce_opts = mongoc_client_encryption_opts_new();
mongoc_client_encryption_opts_set_kms_providers(ce_opts, &kms_providers);
mongoc_client_encryption_opts_set_keyvault_namespace(ce_opts, keyvault_db_name, keyvault_coll_name);
mongoc_client_encryption_opts_set_keyvault_client(ce_opts, client);
client_encryption = mongoc_client_encryption_new(ce_opts, &error);
if (!client_encryption) {
FAIL("Failed to create ClientEncryption: %s", error.message);
}
mongoc_client_encryption_opts_destroy(ce_opts);
}
// Create data key (see:
// https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules):
bson_value_t datakey_id;
{
mongoc_client_encryption_datakey_opts_t *dk_opts = mongoc_client_encryption_datakey_opts_new();
if (!mongoc_client_encryption_create_datakey(client_encryption, "local", dk_opts, &datakey_id, &error)) {
FAIL("Failed to create data key: %s", error.message);
}
mongoc_client_encryption_datakey_opts_destroy(dk_opts);
}
// Explicitly encrypt a value:
bson_value_t encrypted_value;
{
mongoc_client_encryption_encrypt_opts_t *e_opts = mongoc_client_encryption_encrypt_opts_new();
mongoc_client_encryption_encrypt_opts_set_algorithm(e_opts, MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC);
mongoc_client_encryption_encrypt_opts_set_keyid(e_opts, &datakey_id);
bson_value_t to_encrypt = {.value_type = BSON_TYPE_INT32, .value = {.v_int32 = 123}};
if (!mongoc_client_encryption_encrypt(client_encryption, &to_encrypt, e_opts, &encrypted_value, &error)) {
FAIL("Failed to encrypt field: %s", error.message);
}
mongoc_client_encryption_encrypt_opts_destroy(e_opts);
}
// Explicitly decrypt a value:
{
bson_value_t decrypted_value;
if (!mongoc_client_encryption_decrypt(client_encryption, &encrypted_value, &decrypted_value, &error)) {
FAIL("Failed to decrypt field: %s", error.message);
}
printf("Decrypted value: %" PRId32 "\n", decrypted_value.value.v_int32);
bson_value_destroy(&decrypted_value);
}
bson_value_destroy(&encrypted_value);
bson_value_destroy(&datakey_id);
mongoc_client_encryption_destroy(client_encryption);
bson_destroy(&kms_providers);
mongoc_client_destroy(client);
mongoc_cleanup();
return 0;
}

Although automatic encryption requires MongoDB Enterprise Advanced or a MongoDB Atlas cluster, all MongoDB Server products support automatic decryption. To configure explicit encrytpion with automatic decryption, set bypass_auto_encryption=True in mongoc_auto_encryption_opts_t, as shown in the following example:

client-side-encryption-auto-decryption.c
#include <mongoc/mongoc.h>
#include <stdio.h>
#include <stdlib.h>
#define FAIL(...) \
fprintf(stderr, "Error [%s:%d]:\n", __FILE__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
abort();
// `init_bson` creates BSON from JSON. Aborts on error. Use the `BSON_STR()` macro to avoid quotes.
#define init_bson(bson, json) \
if (!bson_init_from_json(&bson, json, -1, &error)) { \
FAIL("Failed to create BSON: %s", error.message); \
}
int
main(void)
{
bson_error_t error;
// The key vault collection stores encrypted data keys:
const char *keyvault_db_name = "keyvault";
const char *keyvault_coll_name = "datakeys";
// The encrypted collection stores application data:
const char *encrypted_db_name = "db";
const char *encrypted_coll_name = "coll";
// Set `local_key` to a 96 byte base64-encoded string:
const char *local_key =
"qx/3ydlPRXgUrBvSBWLsllUTaYDcS/pyaVo27qBHkS2AFePjInwhzCmDWHdmCYPmzhO4lRBzeZKFjSafduLL5z5DMvR/"
"QFfV4zc7btcVmV3QWbDwqZyn6G+Y18ToLHyK";
const char *uri = "mongodb://localhost/?appname=client-side-encryption";
mongoc_init();
// Configure KMS providers used to encrypt data keys:
bson_t kms_providers;
{
char *as_json = bson_strdup_printf(BSON_STR({"local" : {"key" : "%s"}}), local_key);
init_bson(kms_providers, as_json);
bson_free(as_json);
}
// Create client configured to automatically decrypt:
mongoc_client_t *client;
{
client = mongoc_client_new(uri);
if (!client) {
FAIL("Failed to create client");
}
mongoc_auto_encryption_opts_t *ae_opts = mongoc_auto_encryption_opts_new();
// Bypass automatic encryption (requires mongocryptd/crypt_shared) but keep automatic decryption:
mongoc_auto_encryption_opts_set_bypass_auto_encryption(ae_opts, true);
mongoc_auto_encryption_opts_set_keyvault_namespace(ae_opts, keyvault_db_name, keyvault_coll_name);
mongoc_auto_encryption_opts_set_kms_providers(ae_opts, &kms_providers);
if (!mongoc_client_enable_auto_encryption(client, ae_opts, &error)) {
FAIL("Failed to enable auto encryption: %s", error.message);
}
mongoc_auto_encryption_opts_destroy(ae_opts);
}
// Set up key vault collection:
{
mongoc_collection_t *coll = mongoc_client_get_collection(client, keyvault_db_name, keyvault_coll_name);
mongoc_collection_drop(coll, NULL); // Clear pre-existing data.
// Create index to ensure keys have unique keyAltNames:
bson_t index_keys, index_opts;
init_bson(index_keys, BSON_STR({"keyAltNames" : 1}));
init_bson(index_opts,
BSON_STR({"unique" : true, "partialFilterExpression" : {"keyAltNames" : {"$exists" : true}}}));
mongoc_index_model_t *index_model = mongoc_index_model_new(&index_keys, &index_opts);
if (!mongoc_collection_create_indexes_with_opts(
coll, &index_model, 1, NULL /* opts */, NULL /* reply */, &error)) {
FAIL("Failed to create index: %s", error.message);
}
mongoc_index_model_destroy(index_model);
bson_destroy(&index_opts);
bson_destroy(&index_keys);
mongoc_collection_destroy(coll);
}
// Create ClientEncryption object:
mongoc_client_encryption_t *client_encryption;
{
mongoc_client_encryption_opts_t *ce_opts = mongoc_client_encryption_opts_new();
mongoc_client_encryption_opts_set_kms_providers(ce_opts, &kms_providers);
mongoc_client_encryption_opts_set_keyvault_namespace(ce_opts, keyvault_db_name, keyvault_coll_name);
mongoc_client_encryption_opts_set_keyvault_client(ce_opts, client);
client_encryption = mongoc_client_encryption_new(ce_opts, &error);
if (!client_encryption) {
FAIL("Failed to create ClientEncryption: %s", error.message);
}
mongoc_client_encryption_opts_destroy(ce_opts);
}
// Create data key (see:
// https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules):
bson_value_t datakey_id;
{
mongoc_client_encryption_datakey_opts_t *dk_opts = mongoc_client_encryption_datakey_opts_new();
if (!mongoc_client_encryption_create_datakey(client_encryption, "local", dk_opts, &datakey_id, &error)) {
FAIL("Failed to create data key: %s", error.message);
}
mongoc_client_encryption_datakey_opts_destroy(dk_opts);
}
// Explicitly encrypt a value:
bson_value_t encrypted_value;
{
mongoc_client_encryption_encrypt_opts_t *e_opts = mongoc_client_encryption_encrypt_opts_new();
mongoc_client_encryption_encrypt_opts_set_algorithm(e_opts, MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC);
mongoc_client_encryption_encrypt_opts_set_keyid(e_opts, &datakey_id);
bson_value_t to_encrypt = {.value_type = BSON_TYPE_INT32, .value = {.v_int32 = 123}};
if (!mongoc_client_encryption_encrypt(client_encryption, &to_encrypt, e_opts, &encrypted_value, &error)) {
FAIL("Failed to encrypt field: %s", error.message);
}
mongoc_client_encryption_encrypt_opts_destroy(e_opts);
}
// Insert document with encrypted payload:
mongoc_collection_t *encrypted_coll = mongoc_client_get_collection(client, encrypted_db_name, encrypted_coll_name);
{
mongoc_collection_drop(encrypted_coll, NULL); // Clear pre-existing data.
bson_t to_insert = BSON_INITIALIZER;
BSON_APPEND_VALUE(&to_insert, "encryptedField", &encrypted_value);
if (!mongoc_collection_insert_one(encrypted_coll, &to_insert, NULL /* opts */, NULL /* reply */, &error)) {
FAIL("Failed to insert: %s", error.message);
}
char *as_str = bson_as_relaxed_extended_json(&to_insert, NULL);
printf("Inserted document with encrypted payload: %s\n", as_str);
bson_free(as_str);
bson_destroy(&to_insert);
}
// Retrieve document (automatically decrypts):
{
bson_t filter = BSON_INITIALIZER;
mongoc_cursor_t *cursor = mongoc_collection_find_with_opts(encrypted_coll, &filter, NULL, NULL);
const bson_t *result;
if (!mongoc_cursor_next(cursor, &result)) {
FAIL("Failed to find inserted document: %s", error.message);
}
char *as_str = bson_as_relaxed_extended_json(result, NULL);
printf("Retrieved document with automatic decryption: %s\n", as_str);
bson_free(as_str);
mongoc_cursor_destroy(cursor);
bson_destroy(&filter);
}
mongoc_collection_destroy(encrypted_coll);
bson_value_destroy(&encrypted_value);
bson_value_destroy(&datakey_id);
mongoc_client_encryption_destroy(client_encryption);
bson_destroy(&kms_providers);
mongoc_client_destroy(client);
mongoc_cleanup();
return 0;
}

Queryable Encryption is the next-generation in-use encryption feature, first introduced as a preview feature in MongoDB Server version 6.0 and as a generally available (GA) feature in MongoDB 7.0. Queryable Encryption supports searching encrypted fields for equality and encrypts each value uniquely.

Note

QE Requires MongoDB Server 7.0 or later

For information about upgrading your MongoDB Server deployment from 6.0 to 7.0, see Upgrade 6.0 to 7.0 in the MongoDB Server manual.

See the Queryable Encryption guide in the MongoDB Server manual for more information about the feature.

MongoDB Server 6.0 introduced Queryable Encryption as a Public Technical Preview. MongoDB Server 7.0 includes backwards breaking changes to the Queryable Encryption protocol that affect compatibility between different versions of the driver libraries and server.

The following table shows which versions are compatible for Queryable Encryption:

libmongocrypt
libmongoc
Compatible MongoDB Server Versions

1.7.x and earlier

1.23.x and earlier

6.0 only

1.8.0 and later

1.24.0 and later

7.0 and later

Important

Version Mismatch Errors

Using incompatible versions of the packages listed in the preceding table results in server errors.

Back

Authentication

On this page