Docs 菜单

使用显式加密

This guide shows you how to encrypt a document with explicit encryption and a MongoDB driver.

After completing this guide, you should be able to configure a driver to encrypt fields in a document using explicit encryption. With this knowledge, you should be able to create a client application that uses explicit encryption. with automatic decryption.

重要

请勿在生产环境中使用此示例应用程序

本教程中的操作说明包括在不安全的环境中存储加密密钥,因此您不应在生产环境中使用此应用程序的未修改版本。在生产环境中使用此应用程序存在以下风险:未经授权访问加密密钥或丢失解密数据所需的密钥。本教程旨在演示如何使用 Queryable Encryption,而无需设置密钥管理系统。

您可以使用密钥管理系统将加密密钥安全地存储在生产环境中。 KMS是一种远程服务,可安全地存储和管理加密密钥。 要学习;了解如何设立使用KMS且启用了Queryable Encryption的应用程序,请参阅Queryable Encryption教程。

要完成并运行本指南中的代码,您需要设置开发环境,如“安装 Queryable Encryption 兼容驱动程序”页面中所示。

要查看示例应用程序的完整代码,请在语言选择器中选择您的编程语言。

1

您必须创建客户主密钥 (CMK) 才能执行 Queryable Encryption。

Create a 96-byte Customer Master Key and save it to the file master-key.txt:

using (var randomNumberGenerator = System.Security.Cryptography.RandomNumberGenerator.Create())
{
var bytes = new byte[96];
randomNumberGenerator.GetBytes(bytes);
var localMasterKeyBase64Write = Convert.ToBase64String(bytes);
File.WriteAllText("master-key.txt", localMasterKeyBase64Write);
}
func localMasterKey() []byte {
key := make([]byte, 96)
if _, err := rand.Read(key); err != nil {
log.Fatalf("Unable to create a random 96 byte data key: %v", err)
}
if err := ioutil.WriteFile("master-key.txt", key, 0644); err != nil {
log.Fatalf("Unable to write key to file: %v", err)
}
return key
}
byte[] localMasterKeyWrite = new byte[96];
new SecureRandom().nextBytes(localMasterKeyWrite);
try (FileOutputStream stream = new FileOutputStream("master-key.txt")) {
stream.write(localMasterKeyWrite);
}
const fs = require("fs");
const crypto = require("crypto");
try {
fs.writeFileSync("master-key.txt", crypto.randomBytes(96));
} catch (err) {
console.error(err);
}
path = "master-key.txt"
file_bytes = os.urandom(96)
with open(path, "wb") as f:
f.write(file_bytes)

警告

保护生产环境中的本地密钥文件

我们建议将您的客户主密钥存储在远程密钥管理系统KMS)中。要了解如何在 Queryable Encryption 实现中使用远程 KMS,请参阅教程指南。

如果选择在生产中使用本地密钥提供商,请格外小心,不要将其存储在文件系统中。 请考虑使用 sidecar进程将密钥注入到客户端应用程序中,或使用其他确保密钥安全的方法。

提示

从命令行生成 CMK

使用以下命令从 Unix Shell 或 PowerShell 生成 CMK

  • Unix/macOS Shell:

    echo $(head -c 96 /dev/urandom | base64 | tr -d '\n')
  • PowerShell:

    $r=[byte[]]::new(64);$g=[System.Security.Cryptography.RandomNumberGenerator]::Create();$g.GetBytes($r);[Convert]::ToBase64String($r)

将上述命令的输出保存到名为 customer-master-key.txt 的文件中。

提示

请参阅:完整代码

To view the complete code for making a Customer Master Key, see the Queryable Encryption sample application repository.

To view the complete code for making a Customer Master Key, see the Queryable Encryption sample application repository.

To view the complete code for making a Customer Master Key, see the Queryable Encryption sample application repository.

To view the complete code for making a Customer Master Key, see the Queryable Encryption sample application repository.

To view the complete code for making a Customer Master Key, see the Queryable Encryption sample application repository.

2

encryption.__keyVault 命名空间中的 keyAltNames 字段上创建唯一索引。

选择与所需的 MongoDB 驱动程序对应的标签页:

var connectionString = "<Your MongoDB URI>";
var keyVaultNamespace = CollectionNamespace.FromFullName("encryption.__keyVault");
var keyVaultClient = new MongoClient(connectionString);
var indexOptions = new CreateIndexOptions<BsonDocument>
{
Unique = true,
PartialFilterExpression = new BsonDocument
{{"keyAltNames", new BsonDocument {{"$exists", new BsonBoolean(true)}}}}
};
var builder = Builders<BsonDocument>.IndexKeys;
var indexKeysDocument = builder.Ascending("keyAltNames");
var indexModel = new CreateIndexModel<BsonDocument>(indexKeysDocument, indexOptions);
var keyVaultDatabase = keyVaultClient.GetDatabase(keyVaultNamespace.DatabaseNamespace.DatabaseName);
// Drop the Key Vault Collection in case you created this collection
// in a previous run of this application.
keyVaultDatabase.DropCollection(keyVaultNamespace.CollectionName);
var keyVaultCollection = keyVaultDatabase.GetCollection<BsonDocument>(keyVaultNamespace.CollectionName);
keyVaultCollection.Indexes.CreateOne(indexModel);

重要

When building or running the Golang code in this guide using go build or go run, always include the cse build constraint to enable Queryable Encryption. See the following shell command for an example of including the build constraint:

go run -tags cse make-data-key.go
uri := "<Your MongoDB URI>"
keyVaultClient, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri))
if err != nil {
return fmt.Errorf("Connect error for regular client: %v", err)
}
defer func() {
_ = keyVaultClient.Disconnect(context.TODO())
}()
keyVaultDb := "encryption"
keyVaultColl := "__keyVault"
keyVaultNamespace := keyVaultDb + "." + keyVaultColl
keyVaultIndex := mongo.IndexModel{
Keys: bson.D{{"keyAltNames", 1}},
Options: options.Index().
SetUnique(true).
SetPartialFilterExpression(bson.D{
{"keyAltNames", bson.D{
{"$exists", true},
}},
}),
}
// Drop the Key Vault Collection in case you created this collection
// in a previous run of this application.
if err = keyVaultClient.Database(keyVaultDb).Collection(keyVaultColl).Drop(context.TODO()); err != nil {
log.Fatalf("Collection.Drop error: %v", err)
}
_, err = keyVaultClient.Database(keyVaultDb).Collection(keyVaultColl).Indexes().CreateOne(context.TODO(), keyVaultIndex)
if err != nil {
panic(err)
}
String keyVaultDb = "encryption";
String keyVaultColl = "__keyVault";
MongoClient keyVaultClient = MongoClients.create(connectionString);
String encryptedDbName = "medicalRecords";
String encryptedCollName = "patients";
// Drop the Key Vault Collection in case you created this collection
// in a previous run of this application.
keyVaultClient.getDatabase(keyVaultDb).getCollection(keyVaultColl).drop();
MongoCollection keyVaultCollection = keyVaultClient.getDatabase(keyVaultDb).getCollection(keyVaultColl);
IndexOptions indexOpts = new IndexOptions().partialFilterExpression(new BsonDocument("keyAltNames", new BsonDocument("$exists", new BsonBoolean(true) ))).unique(true);
keyVaultCollection.createIndex(new BsonDocument("keyAltNames", new BsonInt32(1)), indexOpts);
keyVaultClient.close();
const uri = "<Your Connection String>";
const keyVaultClient = new MongoClient(uri);
await keyVaultClient.connect();
const keyVaultDB = keyVaultClient.db(keyVaultDatabase);
// Drop the Key Vault Collection in case you created this collection
// in a previous run of this application.
await keyVaultDB.dropDatabase();
const keyVaultColl = keyVaultDB.collection(keyVaultCollection);
await keyVaultColl.createIndex(
{ keyAltNames: 1 },
{
unique: true,
partialFilterExpression: { keyAltNames: { $exists: true } },
}
);
connection_string = "<your connection string here>"
key_vault_coll = "__keyVault"
key_vault_db = "encryption"
key_vault_namespace = f"{key_vault_db}.{key_vault_coll}"
key_vault_client = MongoClient(connection_string)
# Drop the Key Vault Collection in case you created this collection
# in a previous run of this application.
key_vault_client.drop_database(key_vault_db)
key_vault_client[key_vault_db][key_vault_coll].create_index(
[("keyAltNames", ASCENDING)],
unique=True,
partialFilterExpression={"keyAltNames": {"$exists": True}},
)
3
  1. 读取客户主密钥并指定 KMS 提供商设置

    检索您在本指南的创建客户主密钥步骤中生成的客户主密钥文件的内容。

    Use the CMK value in your KMS provider settings. The client uses these settings to discover the CMK. Set the provider name to local to indicate that you are using a Local Key Provider.

    选择与所需的 MongoDB 驱动程序对应的标签页:

    var kmsProviders = new Dictionary<string, IReadOnlyDictionary<string, object>>();
    const string provider = "local";
    var localMasterKeyBase64Read = File.ReadAllText("master-key.txt");
    var localMasterKeyBytes = Convert.FromBase64String(localMasterKeyBase64Read);
    var localOptions = new Dictionary<string, object>
    {
    {"key", localMasterKeyBytes}
    };
    kmsProviders.Add(provider, localOptions);
    key, err := ioutil.ReadFile("master-key.txt")
    if err != nil {
    log.Fatalf("Could not read the key from master-key.txt: %v", err)
    }
    provider := "local"
    kmsProviders := map[string]map[string]interface{}{"local": {"key": key}}
    String kmsProvider = "local";
    String path = "master-key.txt";
    byte[] localMasterKeyRead = new byte[96];
    try (FileInputStream fis = new FileInputStream(path)) {
    if (fis.read(localMasterKeyRead) < 96)
    throw new Exception("Expected to read 96 bytes from file");
    }
    Map<String, Object> keyMap = new HashMap<String, Object>();
    keyMap.put("key", localMasterKeyRead);
    Map<String, Map<String, Object>> kmsProviders = new HashMap<String, Map<String, Object>>();
    kmsProviders.put("local", keyMap);
    const provider = "local";
    const path = "./master-key.txt";
    // WARNING: Do not use a local key file in a production application
    const localMasterKey = fs.readFileSync(path);
    const kmsProviders = {
    local: {
    key: localMasterKey,
    },
    };
    provider = "local"
    path = "./master-key.txt"
    # WARNING: Do not use a local key file in a production application
    with open(path, "rb") as f:
    local_master_key = f.read()
    kms_providers = {
    "local": {
    "key": local_master_key # local_master_key variable from the previous step
    },
    }
  2. Create your Data Encryption Keys

    Construct a client with your MongoDB connection string and Key Vault collection namespace, and create the Data Encryption Keys:

    注意

    密钥保管库集合命名空间权限

    要完成本教程,您的应用程序用于连接到 MongoDB 的数据库用户必须具有对以下命名空间的dbAdmin权限:

    • encryption.__keyVault

    • medicalRecords database

    var clientEncryptionOptions = new ClientEncryptionOptions(
    keyVaultClient,
    keyVaultNamespace,
    kmsProviders: kmsProviders
    );
    var clientEncryption = new ClientEncryption(clientEncryptionOptions);
    var dataKeyOptions1 = new DataKeyOptions(alternateKeyNames: new List<string> { "dataKey1" });
    var dataKeyOptions2 = new DataKeyOptions(alternateKeyNames: new List<string> { "dataKey2" });
    BsonBinaryData CreateKeyGetID(DataKeyOptions options)
    {
    var dateKeyGuid = clientEncryption.CreateDataKey(provider, options, CancellationToken.None);
    return new BsonBinaryData(dateKeyGuid, GuidRepresentation.Standard);
    }
    var dataKeyId1 = CreateKeyGetID(dataKeyOptions1);
    var dataKeyId2 = CreateKeyGetID(dataKeyOptions2);
    var dataKeyId3 = CreateKeyGetID(dataKeyOptions3);
    var dataKeyId4 = CreateKeyGetID(dataKeyOptions4);
    clientEncryptionOpts := options.ClientEncryption().SetKeyVaultNamespace(keyVaultNamespace).
    SetKmsProviders(kmsProviders)
    clientEnc, err := mongo.NewClientEncryption(keyVaultClient, clientEncryptionOpts)
    if err != nil {
    return fmt.Errorf("NewClientEncryption error %v", err)
    }
    defer func() {
    _ = clientEnc.Close(context.TODO())
    }()
    dataKeyOpts1 := options.DataKey().
    SetKeyAltNames([]string{"demoDataKey1"})
    dataKeyID1, err := clientEnc.CreateDataKey(context.TODO(), provider, dataKeyOpts1)
    if err != nil {
    return fmt.Errorf("create data key error %v", err)
    }
    dataKeyOpts2 := options.DataKey().
    SetKeyAltNames([]string{"demoDataKey2"})
    dataKeyID2, err := clientEnc.CreateDataKey(context.TODO(), provider, dataKeyOpts2)
    if err != nil {
    return fmt.Errorf("create data key error %v", err)
    }
    String keyVaultNamespace = keyVaultDb + "." + keyVaultColl;
    ClientEncryptionSettings clientEncryptionSettings = ClientEncryptionSettings.builder()
    .keyVaultMongoClientSettings(MongoClientSettings.builder()
    .applyConnectionString(new ConnectionString(connectionString))
    .build())
    .keyVaultNamespace(keyVaultNamespace)
    .kmsProviders(kmsProviders)
    .build();
    ClientEncryption clientEncryption = ClientEncryptions.create(clientEncryptionSettings);
    List<String> keyAlts1 = new ArrayList<String>();
    keyAlts1.add("dataKey1");
    BsonBinary dataKeyId1 = clientEncryption.createDataKey(kmsProvider, new DataKeyOptions()
    .keyAltNames(keyAlts1));
    List<String> keyAlts2 = new ArrayList<String>();
    keyAlts2.add("dataKey2");
    BsonBinary dataKeyId2 = clientEncryption.createDataKey(kmsProvider, new DataKeyOptions()
    .keyAltNames(keyAlts2));
    const clientEnc = new ClientEncryption(keyVaultClient, {
    keyVaultNamespace: keyVaultNamespace,
    kmsProviders: kmsProviders,
    });
    const dek1 = await clientEnc.createDataKey(provider, {
    keyAltNames: ["dataKey1"],
    });
    const dek2 = await clientEnc.createDataKey(provider, {
    keyAltNames: ["dataKey2"],
    });
    client = MongoClient(connection_string)
    client_encryption = ClientEncryption(
    kms_providers, # pass in the kms_providers variable from the previous step
    key_vault_namespace,
    client,
    CodecOptions(uuid_representation=STANDARD),
    )
    data_key_id_1 = client_encryption.create_data_key(provider, key_alt_names=["dataKey1"])
    data_key_id_2 = client_encryption.create_data_key(provider, key_alt_names=["dataKey2"])
  3. Create Your Encrypted Collection

    Use a Queryable Encryption enabled MongoClient instance to specify what fields you must encrypt and create your encrypted collection:

    var encryptedCollectionNamespace = CollectionNamespace.FromFullName("medicalRecords.patients");
    var encryptedFieldsMap = new Dictionary<string, BsonDocument>
    {
    {
    encryptedCollectionNamespace.FullName, new BsonDocument
    {
    {
    "fields", new BsonArray
    {
    new BsonDocument
    {
    {"keyId", dataKeyId1},
    {"path", new BsonString("patientId")},
    {"bsonType", new BsonString("int")},
    {
    "queries", new BsonDocument
    {
    {"queryType", new BsonString("equality")}
    }
    }
    },
    new BsonDocument
    {
    {"keyId", dataKeyId2},
    {"path", new BsonString("medications")},
    {"bsonType", new BsonString("array")},
    },
    }
    }
    }
    }
    };
    var extraOptions = new Dictionary<string, object>()
    {
    { "cryptSharedLibPath", "<path to crypt_shared library>" },
    };
    var autoEncryptionOptions = new AutoEncryptionOptions(
    keyVaultNamespace,
    kmsProviders,
    encryptedFieldsMap: encryptedFieldsMap,
    extraOptions: extraOptions);
    var clientSettings = MongoClientSettings.FromConnectionString(connectionString);
    clientSettings.AutoEncryptionOptions = autoEncryptionOptions;
    var secureClient = new MongoClient(clientSettings);
    var encryptedDatabase = secureClient.GetDatabase(encryptedCollectionNamespace.DatabaseNamespace.DatabaseName);
    // Drop the encrypted collection in case you created this collection
    // in a previous run of this application.
    encryptedDatabase.DropCollection(encryptedCollectionNamespace.CollectionName);
    encryptedDatabase.CreateCollection(encryptedCollectionNamespace.CollectionName);
    Console.WriteLine("Created encrypted collection!");
    dbName := "medicalRecords"
    collName := "patients"
    encNamespace := (dbName + "." + collName)
    encryptedFieldsMap := bson.M{
    encNamespace: bson.M{
    "fields": []bson.M{
    {
    "path": "patientId",
    "bsonType": "int",
    "keyId": dataKeyID1,
    "queries": []bson.M{
    {
    "queryType": "equality",
    },
    },
    },
    {
    "path": "medications",
    "bsonType": "array",
    "keyId": dataKeyID2,
    },
    },
    },
    }
    extraOptions := map[string]interface{}{
    "cryptSharedLibPath": "<Your Crypt Shared lib Path>",
    }
    autoEncryptionOpts := options.AutoEncryption().
    SetKmsProviders(kmsProviders).
    SetKeyVaultNamespace(keyVaultNamespace).
    SetEncryptedFieldsMap(encryptedFieldsMap).
    SetExtraOptions(extraOptions)
    secureClient, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri).SetAutoEncryptionOptions(autoEncryptionOpts))
    if err != nil {
    return fmt.Errorf("Connect error for encrypted client: %v", err)
    }
    defer func() {
    _ = secureClient.Disconnect(context.TODO())
    }()
    // Drop the encrypted collection in case you created this collection
    // in a previous run of this application.
    if err = secureClient.Database(dbName).Collection(collName).Drop(context.TODO()); err != nil {
    log.Fatalf("Collection.Drop error: %v", err)
    }
    err = secureClient.Database(dbName).CreateCollection(context.TODO(), collName)
    if err != nil {
    return fmt.Errorf("Error creating collection: %v", err)
    }
    String encryptedNameSpace = encryptedDbName + "." + encryptedCollName;
    BsonDocument encFields = new BsonDocument().append("fields",
    new BsonArray(Arrays.asList(
    new BsonDocument().append("keyId", dataKeyId1)
    .append("path", new BsonString("patientId"))
    .append("bsonType", new BsonString("int"))
    .append("queries", new BsonDocument().append("queryType", new BsonString("equality"))),
    new BsonDocument().append("keyId", dataKeyId2)
    .append("path", new BsonString("medications"))
    .append("bsonType", new BsonString("array")),
    )));
    Map<String, BsonDocument> encryptedFieldsMap = new HashMap<String, BsonDocument>();
    encryptedFieldsMap.put(encryptedNameSpace, encFields);
    Map<String, Object> extraOptions = new HashMap<String, Object>();
    extraOptions.put("cryptSharedLibPath", "<path to crypt_shared>");
    MongoClientSettings clientSettings = MongoClientSettings.builder()
    .applyConnectionString(new ConnectionString(connectionString))
    .autoEncryptionSettings(AutoEncryptionSettings.builder()
    .keyVaultNamespace(keyVaultNamespace)
    .kmsProviders(kmsProviders)
    .encryptedFieldsMap(encryptedFieldsMap)
    .extraOptions(extraOptions)
    .build())
    .build();
    MongoClient mongoClientSecure = MongoClients.create(clientSettings);
    MongoDatabase encDb = mongoClientSecure.getDatabase(encryptedDbName);
    // Drop the encrypted collection in case you created this collection
    // in a previous run of this application.
    encDb.getCollection(encryptedCollName).drop();
    encDb.createCollection(encryptedCollName);
    const encryptedFieldsMap = {
    [`${secretDB}.${secretCollection}`]: {
    fields: [
    {
    keyId: dek1,
    path: "patientId",
    bsonType: "int",
    queries: { queryType: "equality" },
    },
    {
    keyId: dek2,
    path: "medications",
    bsonType: "array",
    },
    ],
    },
    };
    const extraOptions = {
    cryptSharedLibPath: "<path to FLE Shared Library>",
    };
    const encClient = new MongoClient(uri, {
    autoEncryption: {
    keyVaultNamespace,
    kmsProviders,
    extraOptions,
    encryptedFieldsMap,
    },
    });
    await encClient.connect();
    const newEncDB = encClient.db(secretDB);
    // Drop the encrypted collection in case you created this collection
    // in a previous run of this application.
    await newEncDB.dropDatabase();
    await newEncDB.createCollection(secretCollection);
    console.log("Created encrypted collection!");
    encrypted_db_name = "medicalRecords"
    encrypted_coll_name = "patients"
    encrypted_fields_map = {
    f"{encrypted_db_name}.{encrypted_coll_name}": {
    "fields": [
    {
    "keyId": data_key_id_1,
    "path": "patientId",
    "bsonType": "int",
    "queries": {"queryType": "equality"},
    },
    {
    "keyId": data_key_id_2,
    "path": "medications",
    "bsonType": "array",
    },
    ],
    },
    }
    key_vault_namespace = "encryption.__keyVault"
    auto_encryption = AutoEncryptionOpts(
    kms_providers,
    key_vault_namespace,
    encrypted_fields_map=encrypted_fields_map,
    crypt_shared_lib_path="<path to FLE Shared Library>",
    )
    secure_client = MongoClient(connection_string, auto_encryption_opts=auto_encryption)
    # Drop the encrypted collection in case you created this collection
    # in a previous run of this application.
    secure_client.drop_database(encrypted_db_name)
    encrypted_db = secure_client[encrypted_db_name]
    encrypted_db.create_collection(encrypted_coll_name)
    print("Created encrypted collection!")

The output from the code in this section should resemble the following:

Created encrypted collection!

提示

请参阅:完整代码

To view the complete code for making a Data Encryption Key, see the Queryable Encryption sample application repository.

To view the complete code for making a Data Encryption Key, see the Queryable Encryption sample application repository.

To view the complete code for making a Data Encryption Key, see the Queryable Encryption sample application repository.

To view the complete code for making a Data Encryption Key, see the Queryable Encryption sample application repository.

To view the complete code for making a Data Encryption Key, see the Queryable Encryption sample application repository.

4
  1. 指定密钥保管库集合命名空间

    指定 encryption.__keyVault 以作为密钥保管库集合命名空间。

    var connectionString = "<Your MongoDB URI>";
    var keyVaultNamespace = CollectionNamespace.FromFullName("encryption.__keyVault");
    var coll = "patients";
    var db = "medicalRecords";
    keyVaultColl := "__keyVault"
    keyVaultDb := "encryption"
    keyVaultNamespace := keyVaultDb + "." + keyVaultColl
    dbName := "medicalRecords"
    collName := "patients"
    String db = "medicalRecords";
    String coll = "patients";
    String keyVaultDb = "encryption";
    String keyVaultColl = "__keyVault";
    String keyVaultNamespace = String.format("%1$s.%2$s", keyVaultDb, keyVaultColl);
    String connectionString = "<Your MongoDB URI>";
    const eDB = "encryption";
    const eKV = "__keyVault";
    const keyVaultNamespace = `${eDB}.${eKV}`;
    const secretDB = "medicalRecords";
    const secretCollection = "patients";
    key_vault_namespace = "encryption.__keyVault"
    key_vault_db_name, key_vault_coll_name = key_vault_namespace.split(".", 1)
  2. Specify the Customer Master Key

    Specify the KMS provider and specify your Customer Master Key inline:

    var kmsProviders = new Dictionary<string, IReadOnlyDictionary<string, object>>();
    const string provider = "local";
    const string localMasterKeyPath = "master-key.txt";
    var localMasterKeyBase64Read = File.ReadAllText(localMasterKeyPath);
    var localMasterKeyBytes = Convert.FromBase64String(localMasterKeyBase64Read);
    var localOptions = new Dictionary<string, object>
    {
    {"key", localMasterKeyBytes}
    };
    kmsProviders.Add(provider, localOptions);
    key, err := ioutil.ReadFile("master-key.txt")
    if err != nil {
    log.Fatalf("Could not read the key from master-key.txt: %v", err)
    }
    kmsProviders := map[string]map[string]interface{}{"local": {"key": key}}
    String kmsProvider = "local";
    String path = "master-key.txt";
    byte[] localMasterKeyRead = new byte[96];
    try (FileInputStream fis = new FileInputStream(path)) {
    if (fis.read(localMasterKeyRead) < 96)
    throw new Exception("Expected to read 96 bytes from file");
    }
    Map<String, Object> keyMap = new HashMap<>();
    keyMap.put("key", localMasterKeyRead);
    Map<String, Map<String, Object>> kmsProviders = new HashMap<>();
    kmsProviders.put(kmsProvider, keyMap);
    const fs = require("fs");
    const path = "./master-key.txt";
    // WARNING: Do not use a local key file in a production application
    const localMasterKey = fs.readFileSync(path);
    const kmsProviders = {
    local: {
    key: localMasterKey,
    },
    };
    path = "./master-key.txt"
    with open(path, "rb") as f:
    local_master_key = f.read()
    kms_providers = {
    "local": {
    "key": local_master_key # local_master_key variable from the previous step
    },
    }
  3. Retrieve Data Encryption Keys

    Retrieve the Data Encryption Keys created in the 创建数据加密密钥 step of this guide:

    var regularClient = new MongoClient(connectionString);
    var keyVaultCollection = regularClient.GetDatabase(keyVaultNamespace.DatabaseNamespace.DatabaseName)
    .GetCollection<BsonDocument>(keyVaultNamespace.CollectionName);
    Guid GetKeyId(string altName)
    {
    var filter = Builders<BsonDocument>.Filter.Eq<BsonString>("keyAltNames", altName);
    return keyVaultCollection.Find(filter).First<BsonDocument>()["_id"].AsGuid;
    }
    var dataKeyId1 = GetKeyId("dataKey1");
    var dataKeyId2 = GetKeyId("dataKey2");
    uri := "<Your MongoDB URI>"
    regularClient, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri))
    if err != nil {
    panic(fmt.Errorf("Client connect error %v", err))
    }
    var foundDoc1 bson.M
    err = regularClient.Database(keyVaultDb).Collection(keyVaultColl).FindOne(context.TODO(), bson.D{{"keyAltNames", "demoDataKey1"}}).Decode(&foundDoc1)
    if err != nil {
    panic(err)
    }
    var dataKeyID1 = foundDoc1["_id"].(primitive.Binary)
    var foundDoc2 bson.M
    err = regularClient.Database(keyVaultDb).Collection(keyVaultColl).FindOne(context.TODO(), bson.D{{"keyAltNames", "demoDataKey2"}}).Decode(&foundDoc2)
    if err != nil {
    panic(err)
    }
    var dataKeyID2 = foundDoc2["_id"].(primitive.Binary)
    MongoClient client = MongoClients.create(connectionString);
    MongoCollection<Document> keyVaultClient = client.getDatabase(keyVaultDb).getCollection(keyVaultColl);
    BsonBinary dataKeyId1 = new BsonBinary(BsonBinarySubType.UUID_STANDARD, keyVaultClient.find(eq("keyAltNames", "dataKey1")).first().get("_id", Binary.class).getData());
    BsonBinary dataKeyId2 = new BsonBinary(BsonBinarySubType.UUID_STANDARD, keyVaultClient.find(eq("keyAltNames", "dataKey2")).first().get("_id", Binary.class).getData());
    const uri = "<Your MongoDB URI>";
    const unencryptedClient = new MongoClient(uri);
    await unencryptedClient.connect();
    const keyVaultClient = unencryptedClient.db(eDB).collection(eKV);
    const dek1 = await keyVaultClient.findOne({ keyAltNames: "dataKey1" });
    const dek2 = await keyVaultClient.findOne({ keyAltNames: "dataKey2" });
    connection_string = "<your connection string here>"
    client = MongoClient(connection_string)
    key_vault = client[key_vault_db_name][key_vault_coll_name]
    data_key_id_1 = key_vault.find_one({"keyAltNames": "dataKey1"})["_id"]
    data_key_id_2 = key_vault.find_one({"keyAltNames": "dataKey2"})["_id"]
  4. Specify the Path of the Automatic Encryption Shared Library

    var extraOptions = new Dictionary<string, object>()
    {
    {"cryptSharedLibPath", "<path to crypt_shared library>"},
    };
    extraOptions := map[string]interface{}{
    "cryptSharedLibPath": "<path to crypt_shared library>",
    }
    Map<String, Object> extraOptions = new HashMap<>();
    extraOptions.put("cryptSharedLibPath", "<path to crypt_shared library>");
    const extraOptions = {
    cryptSharedLibPath: "<path to crypt_shared library>",
    };
    opts = AutoEncryptionOpts(
    kms_providers,
    key_vault.full_name,
    bypass_query_analysis=True,
    key_vault_client=client,
    crypt_shared_lib_path="<path to FLE Shared Library>",
    )

    提示

    了解详情

    To learn more about the library referenced by this path, see the 自动加密共享库 page.

  5. Create a MongoClient Object

    Instantiate a MongoClient object with the following automatic encryption settings:

    var clientSettings = MongoClientSettings.FromConnectionString(connectionString);
    var autoEncryptionOptions = new AutoEncryptionOptions(
    keyVaultNamespace,
    kmsProviders,
    bypassQueryAnalysis: true,
    extraOptions: extraOptions);
    clientSettings.AutoEncryptionOptions = autoEncryptionOptions;
    var secureClient = new MongoClient(clientSettings);
    var collection = secureClient.GetDatabase(db).GetCollection<BsonDocument>(coll);
    autoEncryptionOpts := options.AutoEncryption().
    SetKmsProviders(kmsProviders).
    SetKeyVaultNamespace(keyVaultNamespace).
    SetExtraOptions(extraOptions).
    SetBypassQueryAnalysis(true)
    secureClient, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri).SetAutoEncryptionOptions(autoEncryptionOpts))
    if err != nil {
    return fmt.Errorf("Connect error for encrypted client: %v", err)
    }
    defer func() {
    _ = secureClient.Disconnect(context.TODO())
    }()
    var coll = secureClient.Database(dbName).Collection(collName)
    MongoClientSettings clientSettings = MongoClientSettings.builder()
    .applyConnectionString(new ConnectionString(connectionString))
    .autoEncryptionSettings(AutoEncryptionSettings.builder()
    .keyVaultNamespace(keyVaultNamespace)
    .kmsProviders(kmsProviders)
    .extraOptions(extraOptions)
    .bypassQueryAnalysis(true)
    .build())
    .build();
    MongoClient mongoClientSecure = MongoClients.create(clientSettings);
    const encryptedClient = new MongoClient(uri, {
    autoEncryption: {
    kmsProviders: kmsProviders,
    keyVaultNamespace: keyVaultNamespace,
    bypassQueryAnalysis: true,
    keyVaultClient: unencryptedClient,
    extraOptions: extraOptions,
    },
    });
    await encryptedClient.connect();
    encrypted_client = MongoClient(connection_string, auto_encryption_opts=opts)
    db = encrypted_client.medicalRecords
    coll = db.patients

    注意

    自动解密

    We use a MongoClient instance with automatic encryption enabled to perform automatic decryption.

    To learn more about explicit encryption with automatic decryption, see the Fundamentals section.

  6. Create a ClientEncryption Object

    Instantiate a ClientEncryption object as follows:

    var clientEncryptionOptions = new ClientEncryptionOptions(
    keyVaultClient: regularClient,
    keyVaultNamespace: keyVaultNamespace,
    kmsProviders: kmsProviders
    );
    var clientEncryption = new ClientEncryption(clientEncryptionOptions);
    clientEncryptionOpts := options.ClientEncryption().SetKeyVaultNamespace(keyVaultNamespace).SetKmsProviders(kmsProviders)
    clientEnc, err := mongo.NewClientEncryption(regularClient, clientEncryptionOpts)
    if err != nil {
    panic(fmt.Errorf("NewClientEncryption error %v", err))
    }
    defer func() {
    _ = clientEnc.Close(context.TODO())
    }()
    ClientEncryptionSettings clientEncryptionSettings = ClientEncryptionSettings.builder()
    .keyVaultMongoClientSettings(MongoClientSettings.builder()
    .applyConnectionString(new ConnectionString(connectionString))
    .build())
    .keyVaultNamespace(keyVaultNamespace)
    .kmsProviders(kmsProviders)
    .build();
    ClientEncryption clientEncryption = ClientEncryptions.create(clientEncryptionSettings);
    const encryption = new ClientEncryption(unencryptedClient, {
    keyVaultNamespace,
    kmsProviders,
    });
    client_encryption = ClientEncryption(
    kms_providers, key_vault_namespace, client, client.codec_options
    )

注意

Indexed and Unindexed Algorithms

To learn more about the indexed and unindexed algorithms in explicit encryption, see Algorithm Choice.

5

Use your Queryable Encryption enabled MongoClient instance to insert a document with encrypted fields into the medicalRecords.patients namespace using the following code snippet:

var patientId = 12345678;
var medications = new BsonArray
{
new BsonString("Atorvastatin"),
new BsonString("Levothyroxine")
};
var indexedEncrypted = clientEncryption.Encrypt(
patientId,
new EncryptOptions(algorithm: "Indexed", keyId: dataKeyId1, contentionFactor: 8),
CancellationToken.None);
var unindexedEncrypted = clientEncryption.Encrypt(
medications,
new EncryptOptions(algorithm: "Unindexed", keyId: dataKeyId2),
CancellationToken.None);
collection.InsertOne(new BsonDocument { { "firstName", "Jon" }, { "patientId", indexedEncrypted }, { "medications", unindexedEncrypted } });
patientIdRawValueType, patientIdRawValueData, err := bson.MarshalValue(12345678)
if err != nil {
panic(err)
}
patientIdRawValue := bson.RawValue{Type: patientIdRawValueType, Value: patientIdRawValueData}
patientIdEncryptionOpts := options.Encrypt().
SetAlgorithm("Indexed").
SetKeyID(dataKeyID1).
SetContentionFactor(8)
patientIdEncryptedField, err := clientEnc.Encrypt(
context.TODO(),
patientIdRawValue,
patientIdEncryptionOpts)
if err != nil {
panic(err)
}
medicationsRawValueType, medicationsRawValueData, err := bson.MarshalValue([]string{"Atorvastatin", "Levothyroxine"})
if err != nil {
panic(err)
}
medicationsRawValue := bson.RawValue{Type: medicationsRawValueType, Value: medicationsRawValueData}
medicationsEncryptionOpts := options.Encrypt().
SetAlgorithm("Unindexed").
SetKeyID(dataKeyID2)
medicationsEncryptedField, err := clientEnc.Encrypt(
context.TODO(),
medicationsRawValue,
medicationsEncryptionOpts)
if err != nil {
panic(err)
}
_, err = coll.InsertOne(
context.TODO(),
bson.D{{"firstName", "Jon"}, {"patientId", patientIdEncryptedField}, {"medications", medicationsEncryptedField}})
if err != nil {
panic(err)
}
BsonInt32 patientId = new BsonInt32(12345678);
ArrayList<BsonString> medications = new ArrayList<>();
medications.add(new BsonString("Atorvastatin"));
medications.add(new BsonString("Levothyroxine"));
BsonBinary indexedEncrypted = clientEncryption.encrypt(patientId, new EncryptOptions("Indexed").keyId(dataKeyId1).contentionFactor(8L));
BsonBinary unindexedEncrypted = clientEncryption.encrypt(new BsonArray(medications), new EncryptOptions("Unindexed").keyId(dataKeyId2));
MongoCollection<BsonDocument> collection = mongoClientSecure.getDatabase(db).getCollection(coll, BsonDocument.class);
collection.insertOne(new BsonDocument("firstName", new BsonString("Jon")).append("patientId", indexedEncrypted).append("medications", unindexedEncrypted));
const patientId = 12345678;
const medications = ["Atorvastatin", "Levothyroxine"];
const indexedInsertPayload = await encryption.encrypt(patientId, {
algorithm: "Indexed",
keyId: dek1._id,
contentionFactor: 8,
});
const unindexedInsertPayload = await encryption.encrypt(medications, {
algorithm: "Unindexed",
keyId: dek2._id,
});
const encryptedColl = encryptedClient
.db(secretDB)
.collection(secretCollection);
await encryptedColl.insertOne({
firstName: "Jon",
patientId: indexedInsertPayload,
medications: unindexedInsertPayload,
});
patientId = 12345678
medications = ["Atorvastatin", "Levothyroxine"]
indexed_insert_payload = client_encryption.encrypt(
patientId, Algorithm.INDEXED, data_key_id_1, contention_factor=8
)
unindexed_insert_payload = client_encryption.encrypt(
medications, Algorithm.UNINDEXED, data_key_id_2
)
coll.insert_one(
{
"firstName": "Jon",
"patientId": indexed_insert_payload,
"medications": unindexed_insert_payload,
}
)

When you insert a document, your Queryable Encryption enabled client encrypts the fields of your document such that it resembles the following:

{
"_id": {
"$oid": "6303e36053cc7ec2e6a630bd"
},
"firstName": "Jon",
"patientId": {
"$binary": {
"base64": "BxLJUBmg703civqMz8ASsD4QEYeSneOGiiYHfLE77ELEkp1EC/fXPrKCNRQl2mAFddszqDJ0P3znKrq0DVMEvJoU6wa0Ra+U+JjNVr8NtJE+TpTLCannY5Av6iGfLAaiHbM/E8Ftz1YCQsArQwuNp3wIV/GJPLa2662xsyk0wz7F6IRGC3FlnxpN4UIFaHE1M7Y6kEnx3tEy5uJBvU4Sex7I2H0kqHthClH77Q6xHIHc8H9d6upvgnEbkKBCnmc24A2pSG/xZ7LBsV3j5aOboPISuN/lvg==",
"subType": "06"
}
},
"medications": {
"$binary": {
"base64": "BvOsveapfUxiuQxCMSM2fYIEyRlQaSqR+0NxlMarwurBflvoMz1FrSjSGgCVCpK8X+YrilP6Bac99kkaUmRJfjo4savxcjpOfEnUj5bHciPyfQBYmYF4PMLDtTTzGZpPilb9d5KgpIMBXxHi+dIcog==",
"subType": "06"
}
},
"__safeContent__": [
{
"$binary": {
"base64": "ZLPIpgxzXpHUGrvdIHetwmMagR+mqvuUj5nzXNGf/WM=",
"subType": "00"
}
}
]
}

警告

不要修改 __safeContent__ 字段

__safeContent__ 字段对于 Queryable Encryption 至关重要。请勿修改此字段的内容。

提示

请参阅:完整代码

To view the complete code to insert a document encrypted with explicit encryption, see the Queryable Encryption sample application repository.

To view the complete code to insert a document encrypted with explicit encryption, see the Queryable Encryption sample application repository.

To view the complete code to insert a document encrypted with explicit encryption, see the Queryable Encryption sample application repository.

To view the complete code to insert a document encrypted with explicit encryption, see the Queryable Encryption sample application repository.

To view the complete code to insert a document encrypted with explicit encryption, see the Queryable Encryption sample application repository.

6

Retrieve the document with encrypted fields you inserted in the 插入具有加密字段的文档 step of this guide through a query on an encrypted field:

var findPayload = clientEncryption.Encrypt(
patientId,
new EncryptOptions(algorithm: "Indexed", keyId: dataKeyId1, queryType: "equality", contentionFactor: 8),
CancellationToken.None);
var doc = collection.Find(new BsonDocument { { "patientId", findPayload } }).Single();
Console.WriteLine($"Encrypted document: {doc}");
findPayloadRawValueType, findPayloadRawValueData, err := bson.MarshalValue(12345678)
if err != nil {
panic(err)
}
findPayloadRawValue := bson.RawValue{Type: findPayloadRawValueType, Value: findPayloadRawValueData}
findPayloadEncryptionOpts := options.Encrypt().
SetAlgorithm("Indexed").
SetKeyID(dataKeyID1).
SetQueryType("equality").
SetContentionFactor(8)
findPayloadEncryptedField, err := clientEnc.Encrypt(
context.TODO(),
findPayloadRawValue,
findPayloadEncryptionOpts)
if err != nil {
panic(err)
}
var resultSecure bson.M
coll.FindOne(context.TODO(), bson.D{{"firstName", findPayloadEncryptedField}}).Decode(&resultSecure)
if err != nil {
panic(err)
}
outputSecure, err := json.MarshalIndent(resultSecure, "", " ")
if err != nil {
panic(err)
}
fmt.Printf("\nFound document searching on explicitly encrypted field:\n%s\n", outputSecure)
BsonBinary findPayloadEncrypted = clientEncryption.encrypt(patientId, new EncryptOptions("Indexed").keyId(dataKeyId1).queryType("equality").contentionFactor(8L));
BsonDocument result = collection.find(eq("patientId", findPayloadEncrypted)).first();
System.out.println("Finding a document with manually encrypted field: " + result.toJson());
const findPayload = await encryption.encrypt(patientId, {
algorithm: "Indexed",
keyId: dek1._id,
queryType: "equality",
contentionFactor: 8,
});
console.log("Finding a document with manually encrypted field:");
console.log(await encryptedColl.findOne({ patientId: findPayload }));
find_payload = client_encryption.encrypt(
patientId,
Algorithm.INDEXED,
data_key_id_1,
query_type=QueryType.EQUALITY,
contention_factor=8,
)
doc = coll.find_one({"encryptedIndexed": find_payload})
print("\nReturned document:\n")
pprint.pprint(doc)

The output of the preceding code snippet should contain the following document:

{
"__safeContent__": [
{
"Subtype": 0,
"Data": "LfaIuWm9o30MIGrK7GGUoStJMSNOjRgbxy5q2TPiDes="
}
],
"_id": "6303a770857952ca5e363fd2",
"firstName": "Jon",
"medications": ["Atorvastatin", "Levothyroxine"],
"patientId": 12345678
}

提示

请参阅:完整代码

To view the code to retrieve your document with encrypted fields, see the Queryable Encryption sample application repository.

To view the code to retrieve your document with encrypted fields, see the Queryable Encryption sample application repository.

To view the code to retrieve your document with encrypted fields, see the Queryable Encryption sample application repository.

To view the code to retrieve your document with encrypted fields, see the Queryable Encryption sample application repository.

To view the code to retrieve your document with encrypted fields, see the Queryable Encryption sample application repository.

To view a tutorial on using Queryable Encryption with a remote KMS, see Tutorials.

To learn how Queryable Encryption works, see 显式加密.

如需详细了解本指南中提到的主题,请参阅以下链接: