@@ -14,6 +14,7 @@ import (
14
14
"log"
15
15
16
16
"go.mongodb.org/mongo-driver/bson"
17
+ "go.mongodb.org/mongo-driver/bson/primitive"
17
18
"go.mongodb.org/mongo-driver/mongo/options"
18
19
)
19
20
@@ -131,10 +132,197 @@ func Example_clientSideEncryptionCreateKey() {
131
132
if err != nil {
132
133
log .Fatalf ("Connect error for encrypted client: %v" , err )
133
134
}
135
+ defer func () {
136
+ _ = client .Disconnect (context .TODO ())
137
+ }()
134
138
135
139
// 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 ())
136
266
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 )
139
326
}
327
+ fmt .Printf ("Decrypted document: %v\n " , foundDoc )
140
328
}
0 commit comments