BigQuery AEAD encryption functions uses TINK Keysets.
Works fine but all samples included there describe how to generate an encoded key using a BQ function itself: KEYS.NEW_KEYSET(‘AEAD_AES_GCM_256’)
However, what if you
a)
already have a raw AEAD_AES_GCM_256
that you want to use with BQ
or
b)
you’ve already generated a Key within BQ and want to extract the base AEAD_AES_GCM_256
from a keyset and want to decrypt it on a sunday like as i’m writing this today.
you’re probably wondering how to do that?
well
for a)
you need to create a Tink Keyset from a raw AES key
for b)
you need to extract an AES key from an existing TINK keyset
thats what you can use this repo for..
This is not supported by Google. caveat emptor
You can find the source here
If the AES_GCM key is:
// 1. AES GCM Key
secret := "change this password to a secret"
then import that into a tink keyset. You can use the encoded key with Bigquery
$ go run import_aes_gcm/main.go
Tink Keyset Encoded: CMKIrNYJEmQKWAowdHlwZS5nb29nbGVhcGlzLmNvbS9nb29nbGUuY3J5cHRvLnRpbmsuQWVzR2NtS2V5EiIaIGNoYW5nZSB0aGlzIHBhc3N3b3JkIHRvIGEgc2VjcmV0GAEQARjCiKzWCSAB
Tink Keyset:
{
"primaryKeyId": 2596996162,
"key": [
{
"keyData": {
"typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey",
"value": "GiBjaGFuZ2UgdGhpcyBwYXNzd29yZCB0byBhIHNlY3JldA==",
"keyMaterialType": "SYMMETRIC"
},
"status": "ENABLED",
"keyId": 2596996162,
"outputPrefixType": "TINK"
}
]
}
Attempt to decrypt with BQ output
Plain text Decrypted from BQ: Greed
Plain text Decrypted from BQ: Greed
Plain text Decrypted from BQ: Greed
ReCreated Raw Key: change this password to a secret
use the encoded key with the key of your choosing with AEAD.ENCRYPT function
$ bq query --nouse_legacy_sql --parameter=keyset1::CMKIrNYJEmQKWAowdHlwZS5nb29nbGVhcGlzLmNvbS9nb29nbGUuY3J5cHRvLnRpbmsuQWVzR2NtS2V5EiIaIGNoYW5nZSB0aGlzIHBhc3N3b3JkIHRvIGEgc2VjcmV0GAEQARjCiKzWCSAB \ '
SELECT
title,AEAD.ENCRYPT(FROM_BASE64(@keyset1),title,"")
FROM
bigquery-public-data.san_francisco_film_locations.film_locations
WHERE
title = "Greed"
'
+-------+------------------------------------------------------+
| title | f0_ |
+-------+------------------------------------------------------+
| Greed | AZrLBEKaUq6kFMfPY7XzKcFxvSCJQ31WYqnJEPAzsHPhk6WQ0S4= |
| Greed | AZrLBEL2mv3fZ05icMISrDXdN35gtAX54Z4zqDN0rDevfsfSFoY= |
| Greed | AZrLBEKjpZf+H+JIFijHakbiHtrtY09GNPTrpeHL95CYZj+jk/8= |
+-------+------------------------------------------------------+
then decrypt the BQ output using AEAD.DECRYPT and the key you generated
bq query --nouse_legacy_sql --parameter=keyset1::CMKIrNYJEmQKWAowdHlwZS5nb29nbGVhcGlzLmNvbS9nb29nbGUuY3J5cHRvLnRpbmsuQWVzR2NtS2V5EiIaIGNoYW5nZSB0aGlzIHBhc3N3b3JkIHRvIGEgc2VjcmV0GAEQARjCiKzWCSAB \ '
SELECT
AEAD.DECRYPT_STRING(FROM_BASE64(@keyset1),FROM_BASE64("AZrLBEKaUq6kFMfPY7XzKcFxvSCJQ31WYqnJEPAzsHPhk6WQ0S4="),""),
AEAD.DECRYPT_STRING(FROM_BASE64(@keyset1),FROM_BASE64("AZrLBEL2mv3fZ05icMISrDXdN35gtAX54Z4zqDN0rDevfsfSFoY="),""),
AEAD.DECRYPT_STRING(FROM_BASE64(@keyset1),FROM_BASE64("AZrLBEKjpZf+H+JIFijHakbiHtrtY09GNPTrpeHL95CYZj+jk/8="),""),
'
+-------+-------+-------+
| f0_ | f1_ | f2_ |
+-------+-------+-------+
| Greed | Greed | Greed |
+-------+-------+-------+
Just as verification you can even use golang to verify too using the keyset you just imported the raw key into
log.Printf("Attempt to decrypt with BQ output\n")
bqCiphers := []string{"AZrLBEKaUq6kFMfPY7XzKcFxvSCJQ31WYqnJEPAzsHPhk6WQ0S4=", "AZrLBEL2mv3fZ05icMISrDXdN35gtAX54Z4zqDN0rDevfsfSFoY=", "AZrLBEKjpZf+H+JIFijHakbiHtrtY09GNPTrpeHL95CYZj+jk/8="}
for _, bc := range bqCiphers {
bb, err := base64.StdEncoding.DecodeString(bc)
if err != nil {
log.Fatal(err)
}
dl, err := a.Decrypt(bb, []byte(""))
if err != nil {
log.Fatal(err)
}
log.Printf("Plain text Decrypted from BQ: %s\n", string(dl))
}
To do the reverse (extract a key from tink, see the sample in this repo here which will unmarshall the encoded key. Your key here for BQ is
const (
keySetString = "CMKIrNYJEmQKWAowdHlwZS5nb29nbGVhcGlzLmNvbS9nb29nbGUuY3J5cHRvLnRpbmsuQWVzR2NtS2V5EiIaIGNoYW5nZSB0aGlzIHBhc3N3b3JkIHRvIGEgc2VjcmV0GAEQARjCiKzWCSAB"
)
which is actually the same raw key from above: change this password to a secret
$ go run export_aes_gcm/main.go
Tink Keyset:
{
"primaryKeyId": 2596996162,
"key": [
{
"keyData": {
"typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey",
"value": "GiBjaGFuZ2UgdGhpcyBwYXNzd29yZCB0byBhIHNlY3JldA==",
"keyMaterialType": "SYMMETRIC"
},
"status": "ENABLED",
"keyId": 2596996162,
"outputPrefixType": "TINK"
}
]
}
Encrypted Data: AZrLBELglGoDvAXMqIT+N7J8Pu6VPBHwM2Hp5Z6tS0Z1Py9szPk=
Plain text: Greed
Extracted Raw Key: change this password to a secret
references
for more refernces, see https://github.com/salrashid123/tink_samples
You can also use tinkkey to manage a keyset
$ ./tinkey list-keyset --in-format=json --in keyset.json
primary_key_id: 2596996162
key_info {
type_url: "type.googleapis.com/google.crypto.tink.AesGcmKey"
status: ENABLED
key_id: 2596996162
output_prefix_type: TINK
}
$ ./tinkey rotate-keyset --in-format=json --in keyset.json --key-template AES256_GCM --out-format=json --out keyset2.json
$ ./tinkey list-keyset --in-format=json --in keyset2.json
primary_key_id: 2130552249
key_info {
type_url: "type.googleapis.com/google.crypto.tink.AesGcmKey"
status: ENABLED
key_id: 2596996162
output_prefix_type: TINK
}
key_info {
type_url: "type.googleapis.com/google.crypto.tink.AesGcmKey"
status: ENABLED
key_id: 2130552249
output_prefix_type: TINK
}
This site supports webmentions. Send me a mention via this form.