Skip to content

Commit 4ae363d

Browse files
author
Divjot Arora
committed
GODRIVER-1431 Add explicit encryption examples (#350)
1 parent 6bb0f15 commit 4ae363d

File tree

1 file changed

+190
-2
lines changed

1 file changed

+190
-2
lines changed

mongo/client_side_encryption_examples_test.go

Lines changed: 190 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"log"
1515

1616
"go.mongodb.org/mongo-driver/bson"
17+
"go.mongodb.org/mongo-driver/bson/primitive"
1718
"go.mongodb.org/mongo-driver/mongo/options"
1819
)
1920

@@ -131,10 +132,197 @@ func Example_clientSideEncryptionCreateKey() {
131132
if err != nil {
132133
log.Fatalf("Connect error for encrypted client: %v", err)
133134
}
135+
defer func() {
136+
_ = client.Disconnect(context.TODO())
137+
}()
134138

135139
// Use client for operations.
140+
}
141+
142+
func Example_explictEncryption() {
143+
var localMasterKey []byte // This must be the same master key that was used to create the encryption key.
144+
kmsProviders := map[string]map[string]interface{}{
145+
"local": {
146+
"key": localMasterKey,
147+
},
148+
}
149+
150+
// The MongoDB namespace (db.collection) used to store the encryption data keys.
151+
keyVaultDBName, keyVaultCollName := "encryption", "testKeyVault"
152+
keyVaultNamespace := keyVaultDBName + "." + keyVaultCollName
153+
154+
// The Client used to read/write application data.
155+
client, err := Connect(context.TODO(), options.Client().ApplyURI("mongodb://localhost:27017"))
156+
if err != nil {
157+
panic(err)
158+
}
159+
defer func() { _ = client.Disconnect(context.TODO()) }()
160+
161+
// Get a handle to the application collection and clear existing data.
162+
coll := client.Database("test").Collection("coll")
163+
_ = coll.Drop(context.TODO())
164+
165+
// Set up the key vault for this example.
166+
keyVaultColl := client.Database(keyVaultDBName).Collection(keyVaultCollName)
167+
_ = keyVaultColl.Drop(context.TODO())
168+
// Ensure that two data keys cannot share the same keyAltName.
169+
keyVaultIndex := IndexModel{
170+
Keys: bson.D{{"keyAltNames", 1}},
171+
Options: options.Index().
172+
SetUnique(true).
173+
SetPartialFilterExpression(bson.D{
174+
{"keyAltNames", bson.D{
175+
{"$exists", true},
176+
}},
177+
}),
178+
}
179+
if _, err = keyVaultColl.Indexes().CreateOne(context.TODO(), keyVaultIndex); err != nil {
180+
panic(err)
181+
}
182+
183+
// Create the ClientEncryption object to use for explicit encryption/decryption. The Client passed to
184+
// NewClientEncryption is used to read/write to the key vault. This can be the same Client used by the main
185+
// application.
186+
clientEncryptionOpts := options.ClientEncryption().
187+
SetKmsProviders(kmsProviders).
188+
SetKeyVaultNamespace(keyVaultNamespace)
189+
clientEncryption, err := NewClientEncryption(client, clientEncryptionOpts)
190+
if err != nil {
191+
panic(err)
192+
}
193+
defer func() { _ = clientEncryption.Close(context.TODO()) }()
194+
195+
// Create a new data key for the encrypted field.
196+
dataKeyOpts := options.DataKey().SetKeyAltNames([]string{"go_encryption_example"})
197+
dataKeyID, err := clientEncryption.CreateDataKey(context.TODO(), "local", dataKeyOpts)
198+
if err != nil {
199+
panic(err)
200+
}
201+
202+
// Create a bson.RawValue to encrypt and encrypt it using the key that was just created.
203+
rawValueType, rawValueData, err := bson.MarshalValue("123456789")
204+
if err != nil {
205+
panic(err)
206+
}
207+
rawValue := bson.RawValue{Type: rawValueType, Value: rawValueData}
208+
encryptionOpts := options.Encrypt().
209+
SetAlgorithm("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic").
210+
SetKeyID(dataKeyID)
211+
encryptedField, err := clientEncryption.Encrypt(context.TODO(), rawValue, encryptionOpts)
212+
if err != nil {
213+
panic(err)
214+
}
215+
216+
// Insert a document with the encrypted field and then find it.
217+
if _, err = coll.InsertOne(context.TODO(), bson.D{{"encryptedField", encryptedField}}); err != nil {
218+
panic(err)
219+
}
220+
var foundDoc bson.M
221+
if err = coll.FindOne(context.TODO(), bson.D{}).Decode(&foundDoc); err != nil {
222+
panic(err)
223+
}
224+
225+
// Decrypt the encrypted field in the found document.
226+
decrypted, err := clientEncryption.Decrypt(context.TODO(), foundDoc["encryptedField"].(primitive.Binary))
227+
if err != nil {
228+
panic(err)
229+
}
230+
fmt.Printf("Decrypted value: %s\n", decrypted)
231+
}
232+
233+
func Example_explictEncryptionWithAutomaticDecryption() {
234+
// Automatic encryption requires MongoDB 4.2 enterprise, but automatic decryption is supported for all users.
235+
236+
var localMasterKey []byte // This must be the same master key that was used to create the encryption key.
237+
kmsProviders := map[string]map[string]interface{}{
238+
"local": {
239+
"key": localMasterKey,
240+
},
241+
}
242+
243+
// The MongoDB namespace (db.collection) used to store the encryption data keys.
244+
keyVaultDBName, keyVaultCollName := "encryption", "testKeyVault"
245+
keyVaultNamespace := keyVaultDBName + "." + keyVaultCollName
246+
247+
// Create the Client for reading/writing application data. Configure it with BypassAutoEncryption=true to disable
248+
// automatic encryption but keep automatic decryption. Setting BypassAutoEncryption will also bypass spawning
249+
// mongocryptd in the driver.
250+
autoEncryptionOpts := options.AutoEncryption().
251+
SetKmsProviders(kmsProviders).
252+
SetKeyVaultNamespace(keyVaultNamespace).
253+
SetBypassAutoEncryption(true)
254+
clientOpts := options.Client().
255+
ApplyURI("mongodb://localhost:27017").
256+
SetAutoEncryptionOptions(autoEncryptionOpts)
257+
client, err := Connect(context.TODO(), clientOpts)
258+
if err != nil {
259+
panic(err)
260+
}
261+
defer func() { _ = client.Disconnect(context.TODO()) }()
262+
263+
// Get a handle to the application collection and clear existing data.
264+
coll := client.Database("test").Collection("coll")
265+
_ = coll.Drop(context.TODO())
136266

137-
if err = client.Disconnect(context.TODO()); err != nil {
138-
log.Fatalf("Disconnect error: %v", err)
267+
// Set up the key vault for this example.
268+
keyVaultColl := client.Database(keyVaultDBName).Collection(keyVaultCollName)
269+
_ = keyVaultColl.Drop(context.TODO())
270+
// Ensure that two data keys cannot share the same keyAltName.
271+
keyVaultIndex := IndexModel{
272+
Keys: bson.D{{"keyAltNames", 1}},
273+
Options: options.Index().
274+
SetUnique(true).
275+
SetPartialFilterExpression(bson.D{
276+
{"keyAltNames", bson.D{
277+
{"$exists", true},
278+
}},
279+
}),
280+
}
281+
if _, err = keyVaultColl.Indexes().CreateOne(context.TODO(), keyVaultIndex); err != nil {
282+
panic(err)
283+
}
284+
285+
// Create the ClientEncryption object to use for explicit encryption/decryption. The Client passed to
286+
// NewClientEncryption is used to read/write to the key vault. This can be the same Client used by the main
287+
// application.
288+
clientEncryptionOpts := options.ClientEncryption().
289+
SetKmsProviders(kmsProviders).
290+
SetKeyVaultNamespace(keyVaultNamespace)
291+
clientEncryption, err := NewClientEncryption(client, clientEncryptionOpts)
292+
if err != nil {
293+
panic(err)
294+
}
295+
defer func() { _ = clientEncryption.Close(context.TODO()) }()
296+
297+
// Create a new data key for the encrypted field.
298+
dataKeyOpts := options.DataKey().SetKeyAltNames([]string{"go_encryption_example"})
299+
dataKeyID, err := clientEncryption.CreateDataKey(context.TODO(), "local", dataKeyOpts)
300+
if err != nil {
301+
panic(err)
302+
}
303+
304+
// Create a bson.RawValue to encrypt and encrypt it using the key that was just created.
305+
rawValueType, rawValueData, err := bson.MarshalValue("123456789")
306+
if err != nil {
307+
panic(err)
308+
}
309+
rawValue := bson.RawValue{Type: rawValueType, Value: rawValueData}
310+
encryptionOpts := options.Encrypt().
311+
SetAlgorithm("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic").
312+
SetKeyID(dataKeyID)
313+
encryptedField, err := clientEncryption.Encrypt(context.TODO(), rawValue, encryptionOpts)
314+
if err != nil {
315+
panic(err)
316+
}
317+
318+
// Insert a document with the encrypted field and then find it. The FindOne call will automatically decrypt the
319+
// field in the document.
320+
if _, err = coll.InsertOne(context.TODO(), bson.D{{"encryptedField", encryptedField}}); err != nil {
321+
panic(err)
322+
}
323+
var foundDoc bson.M
324+
if err = coll.FindOne(context.TODO(), bson.D{}).Decode(&foundDoc); err != nil {
325+
panic(err)
139326
}
327+
fmt.Printf("Decrypted document: %v\n", foundDoc)
140328
}

0 commit comments

Comments
 (0)