客户端字段级加密 (Client-Side Field Level Encryption)
MongoDB 4.2中的新增功能、 客户端字段级加密(也称为 CSFLE)允许管理员和开发人员加密特定数据字段以及其他MongoDB加密功能。
使用 CSFLE,开发者可以加密客户端端字段,而无需任何服务器端配置或指令。 CSFLE 支持的工作负载中,应用程序必须保证未经授权的各方(包括服务器管理员)无法读取加密数据。
自动加密(即自动加密命令中的敏感字段)需要仅针对 Enterprise 的依赖项进行查询分析。 有关更多信息,请参阅正在使用的加密。
自动客户端字段级加密
通过调用 mongoc_client_enable_auto_encryption 启用自动加密 在 mongoc_client_t 。以下示例展示了如何使用 mongoc_client_encryption_t 设立自动加密 以创建新的加密数据密钥。
注意
自动加密需要 MongoDB 4.2企业版或 MongoDB 4.2 Atlas 集群。 服务器的社区版本支持自动解密和显式加密。
提供本地自动加密规则
以下示例演示如何使用模式映射设立 mongoc_auto_encryption_opts_set_schema_map 来指定自动加密规则 。自动加密规则使用JSON schema 语法的严格子集来表示。
与依赖从服务器获取的JSON schemas 相比,提供模式映射可提供更高的安全性。 它可以防止恶意服务器公布虚假JSON schema,这种情况可能会诱骗客户端发送应加密的未加密数据。
模式映射中提供的JSON 模式仅应用于配置自动加密。 JSON schema中的其他验证规则不会由驾驶员执行,并会导致错误:
/* Helper method to create a new data key in the key vault, a schema to use that * key, and writes the schema to a file for later use. */ static bool create_schema_file (bson_t *kms_providers, const char *keyvault_db, const char *keyvault_coll, mongoc_client_t *keyvault_client, bson_error_t *error) { mongoc_client_encryption_t *client_encryption = NULL; mongoc_client_encryption_opts_t *client_encryption_opts = NULL; mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL; bson_value_t datakey_id = {0}; char *keyaltnames[] = {"mongoc_encryption_example_1"}; bson_t *schema = NULL; char *schema_string = NULL; size_t schema_string_len; FILE *outfile = NULL; bool ret = false; client_encryption_opts = mongoc_client_encryption_opts_new (); mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts, kms_providers); mongoc_client_encryption_opts_set_keyvault_namespace (client_encryption_opts, keyvault_db, keyvault_coll); mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts, keyvault_client); client_encryption = mongoc_client_encryption_new (client_encryption_opts, error); if (!client_encryption) { goto fail; } /* Create a new data key and json schema for the encryptedField. * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules */ datakey_opts = mongoc_client_encryption_datakey_opts_new (); mongoc_client_encryption_datakey_opts_set_keyaltnames (datakey_opts, keyaltnames, 1); if (!mongoc_client_encryption_create_datakey (client_encryption, "local", datakey_opts, &datakey_id, error)) { goto fail; } /* Create a schema describing that "encryptedField" is a string encrypted * with the newly created data key using deterministic encryption. */ schema = BCON_NEW ( "properties", "{", "encryptedField", "{", "encrypt", "{", "keyId", "[", BCON_BIN (datakey_id.value.v_binary.subtype, datakey_id.value.v_binary.data, datakey_id.value.v_binary.data_len), "]", "bsonType", "string", "algorithm", MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, "}", "}", "}", "bsonType", "object"); /* Use canonical JSON so that other drivers and tools will be * able to parse the MongoDB extended JSON file. */ schema_string = bson_as_canonical_extended_json (schema, &schema_string_len); outfile = fopen ("jsonSchema.json", "w"); if (0 == fwrite (schema_string, sizeof (char), schema_string_len, outfile)) { fprintf (stderr, "failed to write to file\n"); goto fail; } ret = true; fail: mongoc_client_encryption_destroy (client_encryption); mongoc_client_encryption_datakey_opts_destroy (datakey_opts); mongoc_client_encryption_opts_destroy (client_encryption_opts); bson_free (schema_string); bson_destroy (schema); bson_value_destroy (&datakey_id); if (outfile) { fclose (outfile); } return ret; } /* This example demonstrates how to use automatic encryption with a client-side * schema map using the enterprise version of MongoDB */ int main (void) { /* The collection used to store the encryption data keys. */ /* The collection used to store the encrypted documents in this example. */ int exit_status = EXIT_FAILURE; bool ret; uint8_t *local_masterkey = NULL; uint32_t local_masterkey_len; bson_t *kms_providers = NULL; bson_error_t error = {0}; bson_t *index_keys = NULL; bson_t *index_opts = NULL; mongoc_index_model_t *index_model = NULL; bson_json_reader_t *reader = NULL; bson_t schema = BSON_INITIALIZER; bson_t *schema_map = NULL; /* The MongoClient used to access the key vault (keyvault_namespace). */ mongoc_client_t *keyvault_client = NULL; mongoc_collection_t *keyvault_coll = NULL; mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL; mongoc_client_t *client = NULL; mongoc_collection_t *coll = NULL; bson_t *to_insert = NULL; mongoc_client_t *unencrypted_client = NULL; mongoc_collection_t *unencrypted_coll = NULL; mongoc_init (); /* Configure the master key. This must be the same master key that was used * to create the encryption key. */ local_masterkey = hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len); if (!local_masterkey || local_masterkey_len != 96) { fprintf (stderr, "Specify LOCAL_MASTERKEY environment variable as a " "secure random 96 byte hex value.\n"); goto fail; } kms_providers = BCON_NEW ("local", "{", "key", BCON_BIN (0, local_masterkey, local_masterkey_len), "}"); /* Set up the key vault for this example. */ keyvault_client = mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption-keyvault"); BSON_ASSERT (keyvault_client); keyvault_coll = mongoc_client_get_collection (keyvault_client, KEYVAULT_DB, KEYVAULT_COLL); mongoc_collection_drop (keyvault_coll, NULL); /* Create a unique index to ensure that two data keys cannot share the same * keyAltName. This is recommended practice for the key vault. */ index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1)); index_opts = BCON_NEW ("unique", BCON_BOOL (true), "partialFilterExpression", "{", "keyAltNames", "{", "$exists", BCON_BOOL (true), "}", "}"); index_model = mongoc_index_model_new (index_keys, index_opts); ret = mongoc_collection_create_indexes_with_opts ( keyvault_coll, &index_model, 1, NULL /* opts */, NULL /* reply */, &error); if (!ret) { goto fail; } /* Create a new data key and a schema using it for encryption. Save the * schema to the file jsonSchema.json */ ret = create_schema_file (kms_providers, KEYVAULT_DB, KEYVAULT_COLL, keyvault_client, &error); if (!ret) { goto fail; } /* Load the JSON Schema and construct the local schema_map option. */ reader = bson_json_reader_new_from_file ("jsonSchema.json", &error); if (!reader) { goto fail; } bson_json_reader_read (reader, &schema, &error); /* Construct the schema map, mapping the namespace of the collection to the * schema describing encryption. */ schema_map = BCON_NEW (ENCRYPTED_DB "." ENCRYPTED_COLL, BCON_DOCUMENT (&schema)); auto_encryption_opts = mongoc_auto_encryption_opts_new (); mongoc_auto_encryption_opts_set_keyvault_client (auto_encryption_opts, keyvault_client); mongoc_auto_encryption_opts_set_keyvault_namespace (auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL); mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts, kms_providers); mongoc_auto_encryption_opts_set_schema_map (auto_encryption_opts, schema_map); client = mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption"); BSON_ASSERT (client); /* Enable automatic encryption. It will determine that encryption is * necessary from the schema map instead of relying on the server to provide * a schema. */ ret = mongoc_client_enable_auto_encryption (client, auto_encryption_opts, &error); if (!ret) { goto fail; } coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL); /* Clear old data */ mongoc_collection_drop (coll, NULL); to_insert = BCON_NEW ("encryptedField", "123456789"); ret = mongoc_collection_insert_one (coll, to_insert, NULL /* opts */, NULL /* reply */, &error); if (!ret) { goto fail; } printf ("decrypted document: "); if (!print_one_document (coll, &error)) { goto fail; } printf ("\n"); unencrypted_client = mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption-unencrypted"); BSON_ASSERT (unencrypted_client); unencrypted_coll = mongoc_client_get_collection (unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL); printf ("encrypted document: "); if (!print_one_document (unencrypted_coll, &error)) { goto fail; } printf ("\n"); exit_status = EXIT_SUCCESS; fail: if (error.code) { fprintf (stderr, "error: %s\n", error.message); } bson_free (local_masterkey); bson_destroy (kms_providers); mongoc_collection_destroy (keyvault_coll); mongoc_index_model_destroy (index_model); bson_destroy (index_opts); bson_destroy (index_keys); bson_json_reader_destroy (reader); mongoc_auto_encryption_opts_destroy (auto_encryption_opts); mongoc_collection_destroy (coll); mongoc_client_destroy (client); bson_destroy (to_insert); mongoc_collection_destroy (unencrypted_coll); mongoc_client_destroy (unencrypted_client); mongoc_client_destroy (keyvault_client); bson_destroy (&schema); bson_destroy (schema_map); mongoc_cleanup (); return exit_status; }
服务器端字段级加密实施
MongoDB 4.2服务器支持使用模式验证来实施对集合中的特定字段进行加密。 此模式验证将防止应用程序为任何标有“加密” JSON schema关键字的字段插入未加密的值。
以下示例展示了如何使用 mongoc_client_encryption_t 设立自动加密 创建新的加密数据密钥并使用必要的JSON schema 创建集合:
/* Helper method to create and return a JSON schema to use for encryption. The caller will use the returned schema for server-side encryption validation. */ static bson_t * create_schema (bson_t *kms_providers, const char *keyvault_db, const char *keyvault_coll, mongoc_client_t *keyvault_client, bson_error_t *error) { mongoc_client_encryption_t *client_encryption = NULL; mongoc_client_encryption_opts_t *client_encryption_opts = NULL; mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL; bson_value_t datakey_id = {0}; char *keyaltnames[] = {"mongoc_encryption_example_2"}; bson_t *schema = NULL; client_encryption_opts = mongoc_client_encryption_opts_new (); mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts, kms_providers); mongoc_client_encryption_opts_set_keyvault_namespace (client_encryption_opts, keyvault_db, keyvault_coll); mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts, keyvault_client); client_encryption = mongoc_client_encryption_new (client_encryption_opts, error); if (!client_encryption) { goto fail; } /* Create a new data key and json schema for the encryptedField. * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules */ datakey_opts = mongoc_client_encryption_datakey_opts_new (); mongoc_client_encryption_datakey_opts_set_keyaltnames (datakey_opts, keyaltnames, 1); if (!mongoc_client_encryption_create_datakey (client_encryption, "local", datakey_opts, &datakey_id, error)) { goto fail; } /* Create a schema describing that "encryptedField" is a string encrypted * with the newly created data key using deterministic encryption. */ schema = BCON_NEW ( "properties", "{", "encryptedField", "{", "encrypt", "{", "keyId", "[", BCON_BIN (datakey_id.value.v_binary.subtype, datakey_id.value.v_binary.data, datakey_id.value.v_binary.data_len), "]", "bsonType", "string", "algorithm", MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, "}", "}", "}", "bsonType", "object"); fail: mongoc_client_encryption_destroy (client_encryption); mongoc_client_encryption_datakey_opts_destroy (datakey_opts); mongoc_client_encryption_opts_destroy (client_encryption_opts); bson_value_destroy (&datakey_id); return schema; } /* This example demonstrates how to use automatic encryption with a server-side * schema using the enterprise version of MongoDB */ int main (void) { /* The collection used to store the encryption data keys. */ /* The collection used to store the encrypted documents in this example. */ int exit_status = EXIT_FAILURE; bool ret; uint8_t *local_masterkey = NULL; uint32_t local_masterkey_len; bson_t *kms_providers = NULL; bson_error_t error = {0}; bson_t *index_keys = NULL; bson_t *index_opts = NULL; mongoc_index_model_t *index_model = NULL; bson_json_reader_t *reader = NULL; bson_t *schema = NULL; /* The MongoClient used to access the key vault (keyvault_namespace). */ mongoc_client_t *keyvault_client = NULL; mongoc_collection_t *keyvault_coll = NULL; mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL; mongoc_client_t *client = NULL; mongoc_collection_t *coll = NULL; bson_t *to_insert = NULL; mongoc_client_t *unencrypted_client = NULL; mongoc_collection_t *unencrypted_coll = NULL; bson_t *create_cmd = NULL; bson_t *create_cmd_opts = NULL; mongoc_write_concern_t *wc = NULL; mongoc_init (); /* Configure the master key. This must be the same master key that was used * to create * the encryption key. */ local_masterkey = hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len); if (!local_masterkey || local_masterkey_len != 96) { fprintf (stderr, "Specify LOCAL_MASTERKEY environment variable as a " "secure random 96 byte hex value.\n"); goto fail; } kms_providers = BCON_NEW ("local", "{", "key", BCON_BIN (0, local_masterkey, local_masterkey_len), "}"); /* Set up the key vault for this example. */ keyvault_client = mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption-keyvault"); BSON_ASSERT (keyvault_client); keyvault_coll = mongoc_client_get_collection (keyvault_client, KEYVAULT_DB, KEYVAULT_COLL); mongoc_collection_drop (keyvault_coll, NULL); /* Create a unique index to ensure that two data keys cannot share the same * keyAltName. This is recommended practice for the key vault. */ index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1)); index_opts = BCON_NEW ("unique", BCON_BOOL (true), "partialFilterExpression", "{", "keyAltNames", "{", "$exists", BCON_BOOL (true), "}", "}"); index_model = mongoc_index_model_new (index_keys, index_opts); ret = mongoc_collection_create_indexes_with_opts ( keyvault_coll, &index_model, 1, NULL /* opts */, NULL /* reply */, &error); if (!ret) { goto fail; } auto_encryption_opts = mongoc_auto_encryption_opts_new (); mongoc_auto_encryption_opts_set_keyvault_client (auto_encryption_opts, keyvault_client); mongoc_auto_encryption_opts_set_keyvault_namespace (auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL); mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts, kms_providers); schema = create_schema (kms_providers, KEYVAULT_DB, KEYVAULT_COLL, keyvault_client, &error); if (!schema) { goto fail; } client = mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption"); BSON_ASSERT (client); ret = mongoc_client_enable_auto_encryption (client, auto_encryption_opts, &error); if (!ret) { goto fail; } coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL); /* Clear old data */ mongoc_collection_drop (coll, NULL); /* Create the collection with the encryption JSON Schema. */ create_cmd = BCON_NEW ("create", ENCRYPTED_COLL, "validator", "{", "$jsonSchema", BCON_DOCUMENT (schema), "}"); wc = mongoc_write_concern_new (); mongoc_write_concern_set_wmajority (wc, 0); create_cmd_opts = bson_new (); mongoc_write_concern_append (wc, create_cmd_opts); ret = mongoc_client_command_with_opts ( client, ENCRYPTED_DB, create_cmd, NULL /* read prefs */, create_cmd_opts, NULL /* reply */, &error); if (!ret) { goto fail; } to_insert = BCON_NEW ("encryptedField", "123456789"); ret = mongoc_collection_insert_one (coll, to_insert, NULL /* opts */, NULL /* reply */, &error); if (!ret) { goto fail; } printf ("decrypted document: "); if (!print_one_document (coll, &error)) { goto fail; } printf ("\n"); unencrypted_client = mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption-unencrypted"); BSON_ASSERT (unencrypted_client); unencrypted_coll = mongoc_client_get_collection (unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL); printf ("encrypted document: "); if (!print_one_document (unencrypted_coll, &error)) { goto fail; } printf ("\n"); /* Expect a server-side error if inserting with the unencrypted collection. */ ret = mongoc_collection_insert_one (unencrypted_coll, to_insert, NULL /* opts */, NULL /* reply */, &error); if (!ret) { printf ("insert with unencrypted collection failed: %s\n", error.message); memset (&error, 0, sizeof (error)); } exit_status = EXIT_SUCCESS; fail: if (error.code) { fprintf (stderr, "error: %s\n", error.message); } bson_free (local_masterkey); bson_destroy (kms_providers); mongoc_collection_destroy (keyvault_coll); mongoc_index_model_destroy (index_model); bson_destroy (index_opts); bson_destroy (index_keys); bson_json_reader_destroy (reader); mongoc_auto_encryption_opts_destroy (auto_encryption_opts); mongoc_collection_destroy (coll); mongoc_client_destroy (client); bson_destroy (to_insert); mongoc_collection_destroy (unencrypted_coll); mongoc_client_destroy (unencrypted_client); mongoc_client_destroy (keyvault_client); bson_destroy (schema); bson_destroy (create_cmd); bson_destroy (create_cmd_opts); mongoc_write_concern_destroy (wc); mongoc_cleanup (); return exit_status; }
显式加密
显式加密是MongoDB Community的一项功能,不使用查询分析(mongocryptd
或 crypt_shared
)。 显式加密由 mongoc_client_encryption_t 提供 类,示例:
/* This example demonstrates how to use explicit encryption and decryption using * the community version of MongoDB */ int main (void) { /* The collection used to store the encryption data keys. */ /* The collection used to store the encrypted documents in this example. */ int exit_status = EXIT_FAILURE; bool ret; uint8_t *local_masterkey = NULL; uint32_t local_masterkey_len; bson_t *kms_providers = NULL; bson_error_t error = {0}; bson_t *index_keys = NULL; bson_t *index_opts = NULL; mongoc_index_model_t *index_model = NULL; bson_t *schema = NULL; mongoc_client_t *client = NULL; mongoc_collection_t *coll = NULL; mongoc_collection_t *keyvault_coll = NULL; bson_t *to_insert = NULL; bson_t *create_cmd = NULL; bson_t *create_cmd_opts = NULL; mongoc_write_concern_t *wc = NULL; mongoc_client_encryption_t *client_encryption = NULL; mongoc_client_encryption_opts_t *client_encryption_opts = NULL; mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL; char *keyaltnames[] = {"mongoc_encryption_example_3"}; bson_value_t datakey_id = {0}; bson_value_t encrypted_field = {0}; bson_value_t to_encrypt = {0}; mongoc_client_encryption_encrypt_opts_t *encrypt_opts = NULL; bson_value_t decrypted = {0}; mongoc_init (); /* Configure the master key. This must be the same master key that was used * to create the encryption key. */ local_masterkey = hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len); if (!local_masterkey || local_masterkey_len != 96) { fprintf (stderr, "Specify LOCAL_MASTERKEY environment variable as a " "secure random 96 byte hex value.\n"); goto fail; } kms_providers = BCON_NEW ("local", "{", "key", BCON_BIN (0, local_masterkey, local_masterkey_len), "}"); /* The mongoc_client_t used to read/write application data. */ client = mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption"); coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL); /* Clear old data */ mongoc_collection_drop (coll, NULL); /* Set up the key vault for this example. */ keyvault_coll = mongoc_client_get_collection (client, KEYVAULT_DB, KEYVAULT_COLL); mongoc_collection_drop (keyvault_coll, NULL); /* Create a unique index to ensure that two data keys cannot share the same * keyAltName. This is recommended practice for the key vault. */ index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1)); index_opts = BCON_NEW ("unique", BCON_BOOL (true), "partialFilterExpression", "{", "keyAltNames", "{", "$exists", BCON_BOOL (true), "}", "}"); index_model = mongoc_index_model_new (index_keys, index_opts); ret = mongoc_collection_create_indexes_with_opts ( keyvault_coll, &index_model, 1, NULL /* opts */, NULL /* reply */, &error); if (!ret) { goto fail; } client_encryption_opts = mongoc_client_encryption_opts_new (); mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts, kms_providers); mongoc_client_encryption_opts_set_keyvault_namespace (client_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL); /* Set a mongoc_client_t to use for reading/writing to the key vault. This * can be the same mongoc_client_t used by the main application. */ mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts, client); client_encryption = mongoc_client_encryption_new (client_encryption_opts, &error); if (!client_encryption) { goto fail; } /* Create a new data key for the encryptedField. * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules */ datakey_opts = mongoc_client_encryption_datakey_opts_new (); mongoc_client_encryption_datakey_opts_set_keyaltnames (datakey_opts, keyaltnames, 1); if (!mongoc_client_encryption_create_datakey (client_encryption, "local", datakey_opts, &datakey_id, &error)) { goto fail; } /* Explicitly encrypt a field */ encrypt_opts = mongoc_client_encryption_encrypt_opts_new (); mongoc_client_encryption_encrypt_opts_set_algorithm (encrypt_opts, MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC); mongoc_client_encryption_encrypt_opts_set_keyid (encrypt_opts, &datakey_id); to_encrypt.value_type = BSON_TYPE_UTF8; to_encrypt.value.v_utf8.str = "123456789"; const size_t len = strlen (to_encrypt.value.v_utf8.str); BSON_ASSERT (bson_in_range_unsigned (uint32_t, len)); to_encrypt.value.v_utf8.len = (uint32_t) len; ret = mongoc_client_encryption_encrypt (client_encryption, &to_encrypt, encrypt_opts, &encrypted_field, &error); if (!ret) { goto fail; } to_insert = bson_new (); BSON_APPEND_VALUE (to_insert, "encryptedField", &encrypted_field); ret = mongoc_collection_insert_one (coll, to_insert, NULL /* opts */, NULL /* reply */, &error); if (!ret) { goto fail; } printf ("encrypted document: "); if (!print_one_document (coll, &error)) { goto fail; } printf ("\n"); /* Explicitly decrypt a field */ ret = mongoc_client_encryption_decrypt (client_encryption, &encrypted_field, &decrypted, &error); if (!ret) { goto fail; } printf ("decrypted value: %s\n", decrypted.value.v_utf8.str); exit_status = EXIT_SUCCESS; fail: if (error.code) { fprintf (stderr, "error: %s\n", error.message); } bson_free (local_masterkey); bson_destroy (kms_providers); mongoc_collection_destroy (keyvault_coll); mongoc_index_model_destroy (index_model); bson_destroy (index_opts); bson_destroy (index_keys); mongoc_collection_destroy (coll); mongoc_client_destroy (client); bson_destroy (to_insert); bson_destroy (schema); bson_destroy (create_cmd); bson_destroy (create_cmd_opts); mongoc_write_concern_destroy (wc); mongoc_client_encryption_destroy (client_encryption); mongoc_client_encryption_datakey_opts_destroy (datakey_opts); mongoc_client_encryption_opts_destroy (client_encryption_opts); bson_value_destroy (&encrypted_field); mongoc_client_encryption_encrypt_opts_destroy (encrypt_opts); bson_value_destroy (&decrypted); bson_value_destroy (&datakey_id); mongoc_cleanup (); return exit_status; }
带自动解密的显式加密
虽然自动加密需要MongoDB 4.2企业版或MongoDB 4.2 Atlas 集群,支持所有用户自动解密。 要配置自动解密而不自动加密,请在bypass_auto_encryption=True
mongoc_auto_encryption_opts_t 中设立 :
/* This example demonstrates how to set up automatic decryption without * automatic encryption using the community version of MongoDB */ int main (void) { /* The collection used to store the encryption data keys. */ /* The collection used to store the encrypted documents in this example. */ int exit_status = EXIT_FAILURE; bool ret; uint8_t *local_masterkey = NULL; uint32_t local_masterkey_len; bson_t *kms_providers = NULL; bson_error_t error = {0}; bson_t *index_keys = NULL; bson_t *index_opts = NULL; mongoc_index_model_t *index_model = NULL; bson_t *schema = NULL; mongoc_client_t *client = NULL; mongoc_collection_t *coll = NULL; mongoc_collection_t *keyvault_coll = NULL; bson_t *to_insert = NULL; bson_t *create_cmd = NULL; bson_t *create_cmd_opts = NULL; mongoc_write_concern_t *wc = NULL; mongoc_client_encryption_t *client_encryption = NULL; mongoc_client_encryption_opts_t *client_encryption_opts = NULL; mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL; char *keyaltnames[] = {"mongoc_encryption_example_4"}; bson_value_t datakey_id = {0}; bson_value_t encrypted_field = {0}; bson_value_t to_encrypt = {0}; mongoc_client_encryption_encrypt_opts_t *encrypt_opts = NULL; bson_value_t decrypted = {0}; mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL; mongoc_client_t *unencrypted_client = NULL; mongoc_collection_t *unencrypted_coll = NULL; mongoc_init (); /* Configure the master key. This must be the same master key that was used * to create the encryption key. */ local_masterkey = hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len); if (!local_masterkey || local_masterkey_len != 96) { fprintf (stderr, "Specify LOCAL_MASTERKEY environment variable as a " "secure random 96 byte hex value.\n"); goto fail; } kms_providers = BCON_NEW ("local", "{", "key", BCON_BIN (0, local_masterkey, local_masterkey_len), "}"); client = mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption"); auto_encryption_opts = mongoc_auto_encryption_opts_new (); mongoc_auto_encryption_opts_set_keyvault_namespace (auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL); mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts, kms_providers); /* Setting bypass_auto_encryption to true disables automatic encryption but * keeps the automatic decryption behavior. bypass_auto_encryption will also * disable spawning mongocryptd */ mongoc_auto_encryption_opts_set_bypass_auto_encryption (auto_encryption_opts, true); /* Once bypass_auto_encryption is set, community users can enable auto * encryption on the client. This will, in fact, only perform automatic * decryption. */ ret = mongoc_client_enable_auto_encryption (client, auto_encryption_opts, &error); if (!ret) { goto fail; } /* Now that automatic decryption is on, we can test it by inserting a * document with an explicitly encrypted value into the collection. When we * look up the document later, it should be automatically decrypted for us. */ coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL); /* Clear old data */ mongoc_collection_drop (coll, NULL); /* Set up the key vault for this example. */ keyvault_coll = mongoc_client_get_collection (client, KEYVAULT_DB, KEYVAULT_COLL); mongoc_collection_drop (keyvault_coll, NULL); /* Create a unique index to ensure that two data keys cannot share the same * keyAltName. This is recommended practice for the key vault. */ index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1)); index_opts = BCON_NEW ("unique", BCON_BOOL (true), "partialFilterExpression", "{", "keyAltNames", "{", "$exists", BCON_BOOL (true), "}", "}"); index_model = mongoc_index_model_new (index_keys, index_opts); ret = mongoc_collection_create_indexes_with_opts ( keyvault_coll, &index_model, 1, NULL /* opts */, NULL /* reply */, &error); if (!ret) { goto fail; } client_encryption_opts = mongoc_client_encryption_opts_new (); mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts, kms_providers); mongoc_client_encryption_opts_set_keyvault_namespace (client_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL); /* The key vault client is used for reading to/from the key vault. This can * be the same mongoc_client_t used by the application. */ mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts, client); client_encryption = mongoc_client_encryption_new (client_encryption_opts, &error); if (!client_encryption) { goto fail; } /* Create a new data key for the encryptedField. * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules */ datakey_opts = mongoc_client_encryption_datakey_opts_new (); mongoc_client_encryption_datakey_opts_set_keyaltnames (datakey_opts, keyaltnames, 1); ret = mongoc_client_encryption_create_datakey (client_encryption, "local", datakey_opts, &datakey_id, &error); if (!ret) { goto fail; } /* Explicitly encrypt a field. */ encrypt_opts = mongoc_client_encryption_encrypt_opts_new (); mongoc_client_encryption_encrypt_opts_set_algorithm (encrypt_opts, MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC); mongoc_client_encryption_encrypt_opts_set_keyaltname (encrypt_opts, "mongoc_encryption_example_4"); to_encrypt.value_type = BSON_TYPE_UTF8; to_encrypt.value.v_utf8.str = "123456789"; const size_t len = strlen (to_encrypt.value.v_utf8.str); BSON_ASSERT (bson_in_range_unsigned (uint32_t, len)); to_encrypt.value.v_utf8.len = (uint32_t) len; ret = mongoc_client_encryption_encrypt (client_encryption, &to_encrypt, encrypt_opts, &encrypted_field, &error); if (!ret) { goto fail; } to_insert = bson_new (); BSON_APPEND_VALUE (to_insert, "encryptedField", &encrypted_field); ret = mongoc_collection_insert_one (coll, to_insert, NULL /* opts */, NULL /* reply */, &error); if (!ret) { goto fail; } /* When we retrieve the document, any encrypted fields will get automatically * decrypted by the driver. */ printf ("decrypted document: "); if (!print_one_document (coll, &error)) { goto fail; } printf ("\n"); unencrypted_client = mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption"); unencrypted_coll = mongoc_client_get_collection (unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL); printf ("encrypted document: "); if (!print_one_document (unencrypted_coll, &error)) { goto fail; } printf ("\n"); exit_status = EXIT_SUCCESS; fail: if (error.code) { fprintf (stderr, "error: %s\n", error.message); } bson_free (local_masterkey); bson_destroy (kms_providers); mongoc_collection_destroy (keyvault_coll); mongoc_index_model_destroy (index_model); bson_destroy (index_opts); bson_destroy (index_keys); mongoc_collection_destroy (coll); mongoc_client_destroy (client); bson_destroy (to_insert); bson_destroy (schema); bson_destroy (create_cmd); bson_destroy (create_cmd_opts); mongoc_write_concern_destroy (wc); mongoc_client_encryption_destroy (client_encryption); mongoc_client_encryption_datakey_opts_destroy (datakey_opts); mongoc_client_encryption_opts_destroy (client_encryption_opts); bson_value_destroy (&encrypted_field); mongoc_client_encryption_encrypt_opts_destroy (encrypt_opts); bson_value_destroy (&decrypted); bson_value_destroy (&datakey_id); mongoc_collection_destroy (unencrypted_coll); mongoc_client_destroy (unencrypted_client); mongoc_auto_encryption_opts_destroy (auto_encryption_opts); mongoc_cleanup (); return exit_status; }