@@ -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