tink
tink copied to clipboard
AWS KMS private key decryption fails
Describe the bug
I have created private key and public key. And encrypted private key. When I do the opposite and try to decode the private key then decryption fails.
To Reproduce
Generating key and Encryption
package main
import (
"bytes"
"encoding/base64"
"fmt"
"log"
"os"
"github.com/google/tink/go/aead"
"github.com/google/tink/go/core/registry"
"github.com/google/tink/go/hybrid"
"github.com/google/tink/go/insecurecleartextkeyset"
"github.com/google/tink/go/integration/awskms"
"github.com/google/tink/go/keyset"
)
func main() {
keyURI := "aws-kms://arn:aws:kms:{my-region}:{my-account-no}:key/{my-key-id}"
outFilePrivate := "./private"
outFilePublic := "./public.json"
awsClient, err := awskms.NewClient(keyURI)
if err != nil {
log.Fatal(err)
}
registry.RegisterKMSClient(awsClient)
dek := aead.AES128CTRHMACSHA256KeyTemplate()
khgcs, err := keyset.NewHandle(aead.KMSEnvelopeAEADKeyTemplate(keyURI, dek))
if err != nil {
log.Fatal(err)
}
a, err := aead.New(khgcs)
if err != nil {
log.Fatal(err)
}
// Create a Tink Hybrid key handle to encrypt document keys.
kh, err := keyset.NewHandle(hybrid.ECIESHKDFAES128GCMKeyTemplate())
if err != nil {
log.Fatal(err)
}
exported := &keyset.MemReaderWriter{}
if err := insecurecleartextkeyset.Write(kh, exported); err != nil {
log.Fatal("unexpected error writing keyset: ", err)
}
// Encrypt the Tink key with the GCP AEAD
ct, err := a.Encrypt([]byte(exported.Keyset.String()), nil)
if err != nil {
log.Fatal(err)
}
// Write the encrypted Tink private key to the output file.
f, err := os.Create(outFilePrivate)
if err != nil {
log.Fatal(err)
}
f.WriteString(base64.StdEncoding.EncodeToString(ct))
log.Println("Private keyset writen to file: ", outFilePrivate)
// Get the public Tink Hybrid key handle.
khPub, err := kh.Public()
if err != nil {
log.Fatal(err)
}
buf := new(bytes.Buffer)
exportedPub := keyset.NewJSONWriter(buf)
if err = khPub.WriteWithNoSecrets(exportedPub); err != nil {
log.Fatal(err)
}
// Write the public key to the output file.
pf, err := os.Create(outFilePublic)
if err != nil {
log.Fatal(err)
}
pf.Write(buf.Bytes())
log.Println("Public keyset writen to file: ", outFilePublic)
}
Everything works upto this point. I get private and public key.
Decode private key
package main
import (
"encoding/base64"
"fmt"
"github.com/google/tink/go/core/registry"
"github.com/google/tink/go/integration/awskms"
"github.com/google/tink/go/keyset"
"github.com/google/tink/go/aead"
)
func main() {
keyURI := "aws-kms://arn:aws:kms:{my-region}:{my-account-no}:key/{my-key-id}"
awsClient, err := awskms.NewClient(keyURI)
if err != nil {
fmt.Printf("creating aws kms client failed, %v\n", err)
return
}
registry.RegisterKMSClient(awsClient)
dek := aead.AES128CTRHMACSHA256KeyTemplate()
khgcs, err := keyset.NewHandle(aead.KMSEnvelopeAEADKeyTemplate(keyURI, dek))
if err != nil {
fmt.Printf("new handle failed, %v", err)
return
}
a, err := aead.New(khgcs)
if err != nil {
fmt.Printf("failed to create new aead, %v", err)
return
}
privateKey := "private key outputed from previous snippet"
pk, pkErr := base64.StdEncoding.DecodeString(privateKey)
if pkErr != nil {
fmt.Printf("decoding private key failed, %v\n", pkErr)
return
}
plainBytesPk, err := a.Decrypt(pk, nil)
if err != nil {
fmt.Printf("decrypting private key failed, %v\n", err)
return
}
fmt.Printf("plain text private key, %v", string(plainBytesPk))
}
Expected behavior
I should see my plain text private key
Error messages, stack traces, etc.
I get following error message
decrypting private key failed, aead_factory: decryption failed
Version information
- Language: Golang
- Version: 1.5.0
- Environment: Testing in local playground but it will be deployed to aws lambda golang.
I have additional question on the same topic. There is huge warning on not hard coding your private key in source code or commit history. But if my private key is already encrypted then is it safe to hardcode inside my private git repo?
The problem of your code was that you serialized the keyset in the wrong way. You shouldn't use MemReaderWriter and then call exported.Keyset.String() on that. This will generate a string representation of the keyset that you can't parse. (I think MemReaderWriter should in fact not be used at all, I have now deprecated it.)
Here is an example on how to encrypt a keyset: https://github.com/google/tink/blob/master/go/keyset/keyset_test.go
It encrypts a keyset with a symmetric key, but in the same way you can also encrypt a private key.
And yes, when the private key is encrypted, it is fine to hard-code it.