tink icon indicating copy to clipboard operation
tink copied to clipboard

AWS KMS private key decryption fails

Open apoorvmote opened this issue 4 years ago • 1 comments
trafficstars

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.

apoorvmote avatar Jan 30 '21 05:01 apoorvmote

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?

apoorvmote avatar Jan 30 '21 05:01 apoorvmote

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.

juergw avatar Mar 21 '23 14:03 juergw