Skip to content

Instantly share code, notes, and snippets.

@salrashid123
Created June 26, 2022 15:46
Show Gist options
  • Save salrashid123/fa092d083bac5ec2a0e9802e4b0c3071 to your computer and use it in GitHub Desktop.
Save salrashid123/fa092d083bac5ec2a0e9802e4b0c3071 to your computer and use it in GitHub Desktop.
Create or import new KMS TINK key for BigQuery SQL column-level encryption https://blog.salrashid.dev/articles/2022/bq_kms/
package main
import (
"bytes"
"encoding/base64"
"flag"
"fmt"
"math/rand"
"github.com/google/tink/go/aead"
"github.com/google/tink/go/aead/subtle"
"github.com/google/tink/go/keyset"
"github.com/google/tink/go/core/registry"
"github.com/google/tink/go/integration/gcpkms"
"github.com/golang/protobuf/proto"
gcmpb "github.com/google/tink/go/proto/aes_gcm_go_proto"
tinkpb "github.com/google/tink/go/proto/tink_go_proto"
)
var (
keyURI = flag.String("keyURI", "", "KMS Key URI")
)
const ()
func main() {
flag.Parse()
if *keyURI == "" {
fmt.Printf("--keyURI must be set")
return
}
gcpClient, err := gcpkms.NewClient("gcp-kms://")
if err != nil {
panic(err)
}
registry.RegisterKMSClient(gcpClient)
backend, err := gcpClient.GetAEAD(*keyURI)
if err != nil {
fmt.Printf("Could not acquire KMS AEAD %v\n", err)
return
}
secret := "8y/B?E(H+MbQeThVmYq3t6w9z$C&F)J@"
rawKey := []byte(secret)
id := rand.Uint32()
tk, err := subtle.NewAESGCM(rawKey)
if err != nil {
fmt.Println(err)
return
}
k := &gcmpb.AesGcmKey{
Version: 0,
KeyValue: tk.Key,
}
fmt.Printf("Tink AESGCM Key: %v\n", base64.StdEncoding.EncodeToString(k.KeyValue))
keyserialized, err := proto.Marshal(k)
if err != nil {
fmt.Println(err)
return
}
keysetKey := &tinkpb.Keyset_Key{
KeyData: &tinkpb.KeyData{
TypeUrl: "type.googleapis.com/google.crypto.tink.AesGcmKey",
KeyMaterialType: tinkpb.KeyData_SYMMETRIC,
Value: keyserialized,
},
KeyId: id,
Status: tinkpb.KeyStatusType_ENABLED,
OutputPrefixType: tinkpb.OutputPrefixType_TINK,
}
ks := &tinkpb.Keyset{
PrimaryKeyId: id,
Key: []*tinkpb.Keyset_Key{keysetKey},
}
rawSerialized, err := proto.Marshal(ks)
if err != nil {
fmt.Println(err)
return
}
rd, err := backend.Encrypt(rawSerialized, []byte(""))
if err != nil {
fmt.Println(err)
return
}
ksi := &tinkpb.KeysetInfo{
PrimaryKeyId: keysetKey.KeyId,
KeyInfo: []*tinkpb.KeysetInfo_KeyInfo{
{
TypeUrl: keysetKey.KeyData.TypeUrl,
Status: keysetKey.Status,
KeyId: keysetKey.KeyId,
OutputPrefixType: tinkpb.OutputPrefixType_TINK,
},
},
}
aeks := &tinkpb.EncryptedKeyset{
EncryptedKeyset: rd,
KeysetInfo: ksi,
}
eksSerialized, err := proto.Marshal(aeks)
if err != nil {
fmt.Println(err)
return
}
r := keyset.NewBinaryReader(bytes.NewBuffer(eksSerialized))
if err != nil {
fmt.Printf("Could not create TINK NewBinaryReader %v\n", err)
return
}
rk, err := r.ReadEncrypted()
if err != nil {
fmt.Printf("Could not create TINK keyHandle %v\n", err)
return
}
tv := base64.StdEncoding.EncodeToString(rk.EncryptedKeyset)
fmt.Printf(" Key %s\n", tv)
r = keyset.NewBinaryReader(bytes.NewBuffer(eksSerialized))
if err != nil {
fmt.Printf(">>> Could not create TINK keyHandle %v\n", err)
return
}
kh, err := keyset.Read(r, backend)
if err != nil {
fmt.Printf("Could not create TINK keyHandle %v\n", err)
return
}
dkh, err := aead.New(kh)
if err != nil {
fmt.Printf("JSON parse error: %v \n", err)
return
}
ctaa, err := dkh.Encrypt([]byte("Juarez Gold DSS"), []byte("additional_data"))
if err != nil {
fmt.Printf("Error Encrypting %v\n", err)
return
}
fmt.Printf(" Cipher text: %s\n", base64.StdEncoding.EncodeToString(ctaa))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment