Skip to content

Instantly share code, notes, and snippets.

@kennwhite
Last active September 5, 2022 21:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kennwhite/50918e4bcb1b1923ceb1e17071959feb to your computer and use it in GitHub Desktop.
Save kennwhite/50918e4bcb1b1923ceb1e17071959feb to your computer and use it in GitHub Desktop.
CSFLE explicit encryption golang Hello World example
/*
CSFLE explicit encryption golang Hello World example
brew install mongodb/brew/libmongocrypt
go get go.mongodb.org/mongo-driver/mongo
go get go.mongodb.org/mongo-driver/bson
go get go.mongodb.org/mongo-driver/mongo/options
go get go.mongodb.org/mongo-driver/mongo/readpref
go get go.mongodb.org/mongo-driver/bson/primitive
go clean --cache
go build -tags cse csfle_golang_explicit.go
OR
go run -tags cse csfle_golang_explicit.go
*/
package main
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
var uri = "mongodb://localhost:27017"
// localMasterKey must be the same master key that was used to create the
// encryption key. Obviously, don't use this example key in production.
var localMasterKey = "E7h/7bm+gvHPosEhZLB96Nms4Lrn2zV90vKpVJIo7UMn9112iex7dPeHHKVt088kNr3Zv+ZpBGZTYFI7yVm49eIysA7PwXdZ/QpNcwuw9Ut5rYiXXf4UA8G9fNNkYonQ"
kmsProviders := map[string]map[string]interface{}{
"local": {
"key": localMasterKey,
},
}
// The MongoDB namespace (db.collection) used to store the encryption data
// keys.
keyVaultDBName, keyVaultCollName := "encryption", "__keyVault"
keyVaultNamespace := keyVaultDBName + "." + keyVaultCollName
// The Client used to read/write application data.
client, err := mongo.Connect(
context.TODO(),
options.Client().ApplyURI(uri))
if err != nil {
panic(err)
}
defer func() { _ = client.Disconnect(context.TODO()) }()
// Get a handle to the application collection and clear existing data.
coll := client.Database("test").Collection("coll")
_ = coll.Drop(context.TODO())
// Set up the key vault for this example.
keyVaultColl := client.Database(keyVaultDBName).Collection(keyVaultCollName)
_ = keyVaultColl.Drop(context.TODO())
// Ensure that two data keys cannot share the same keyAltName.
keyVaultIndex := mongo.IndexModel{
Keys: bson.D{{Key: "keyAltNames", Value: 1}},
Options: options.Index().
SetUnique(true).
SetPartialFilterExpression(bson.D{
{Key: "keyAltNames", Value: bson.D{
{Key: "$exists", Value: true},
}},
}),
}
_, err = keyVaultColl.Indexes().CreateOne(context.TODO(), keyVaultIndex)
if err != nil {
panic(err)
}
// Create the ClientEncryption object to use for explicit
// encryption/decryption. The Client passed to NewClientEncryption is used
// to read/write to the key vault. This can be the same Client used by the
// main application.
clientEncryptionOpts := options.ClientEncryption().
SetKmsProviders(kmsProviders).
SetKeyVaultNamespace(keyVaultNamespace)
clientEncryption, err := mongo.NewClientEncryption(client, clientEncryptionOpts)
if err != nil {
panic(err)
}
defer func() { _ = clientEncryption.Close(context.TODO()) }()
// Create a new data key for the encrypted field.
dataKeyOpts := options.DataKey().
SetKeyAltNames([]string{"go_encryption_example"})
dataKeyID, err := clientEncryption.CreateDataKey(
context.TODO(),
"local",
dataKeyOpts)
if err != nil {
panic(err)
}
// Create a bson.RawValue to encrypt and encrypt it using the key that was
// just created.
rawValueType, rawValueData, err := bson.MarshalValue("Hello, 世界!")
if err != nil {
panic(err)
}
rawValue := bson.RawValue{Type: rawValueType, Value: rawValueData}
encryptionOpts := options.Encrypt().
SetAlgorithm("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic").
SetKeyID(dataKeyID)
encryptedField, err := clientEncryption.Encrypt(
context.TODO(),
rawValue,
encryptionOpts)
if err != nil {
panic(err)
}
// Insert a document with the encrypted field and then find it.
_, err = coll.InsertOne(
context.TODO(),
bson.D{{Key: "encryptedField", Value: encryptedField}})
if err != nil {
panic(err)
}
var foundDoc bson.M
err = coll.FindOne(context.TODO(), bson.D{}).Decode(&foundDoc)
if err != nil {
panic(err)
}
// Decrypt the encrypted field in the found document.
decrypted, err := clientEncryption.Decrypt(
context.TODO(),
foundDoc["encryptedField"].(primitive.Binary))
if err != nil {
panic(err)
}
fmt.Printf("Decrypted value: %s\n", decrypted)
}
$ ./csfle_golang_explicit
Decrypted value: "Hello, 世界!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment