Skip to content
This repository has been archived by the owner on Apr 17, 2024. It is now read-only.

KMS Envelope encryption formats #509

Closed
salrashid123 opened this issue May 22, 2021 · 3 comments
Closed

KMS Envelope encryption formats #509

salrashid123 opened this issue May 22, 2021 · 3 comments

Comments

@salrashid123
Copy link

This is really a question on the correct usage of KMS envelope encryption.

I'm trying to find out the correct way to wrap an a key w/ KMS....From what i can tell, both A and B below creates an EncrytedKeySet which is backed by a KMS KEK. B is what is whats documented here ...so i'm trying to understand where A fits in...what it is doing is writing a plain `AES256GCMKeyTemplate....

is A and B doing the pretty much the same here or did i miss a subtle and very important distinction on best use?

A

gcpClient, err := gcpkms.NewClient("gcp-kms://")
registry.RegisterKMSClient(gcpClient)
a, err := gcpClient.GetAEAD(keyURI)
memKeyset := &keyset.MemReaderWriter{}

kh1, err := keyset.NewHandle(aead.AES256GCMKeyTemplate())
err := kh1.Write(memKeyset, a)

buf := new(bytes.Buffer)
w := keyset.NewJSONWriter(buf)
err := w.WriteEncrypted(memKeyset.EncryptedKeyset)
{
 "encryptedKeyset": "CiUAmT+VVftIzno6MLCacsWfgYEkIvVIwSCyYW6VZ87RjVkuBXf8EpUBACsKZVI3Qv464/QOu1lWZLra/J28orUJRiPIpOz1IOCyMjWmMd+Ivkk4PXZkbR5GuEcdagS7sHt5A8pSy5dK92n4DHv6eYkM6JK+K5pGuUgTn2vKHHFPQT9MkWR66R+Q6boxgvFrubQbuDUftMyfDg8GhWxGSViJ29wCQ70D1Ii69ZnNsnJN3FWmYk514mP0YKjT8Ig=",
 "keysetInfo": {
   "primaryKeyId": 1765999365,
   "keyInfo": [
     {
       "typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey",
       "status": "ENABLED",
       "keyId": 1765999365,
       "outputPrefixType": "TINK"
     }
   ]
 }
}

B

gcpClient, err := gcpkms.NewClient("gcp-kms://")
registry.RegisterKMSClient(gcpClient)
kmsAead, err := gcpClient.GetAEAD(keyURI)
a := aead.NewKMSEnvelopeAEAD2(aead.AES256GCMKeyTemplate(), kmsAead)
memKeyset := &keyset.MemReaderWriter{}

kh1, err := keyset.NewHandle(aead.AES256GCMKeyTemplate())
err := kh1.Write(memKeyset, a)

buf := new(bytes.Buffer)
w := keyset.NewJSONWriter(buf)
err := w.WriteEncrypted(memKeyset.EncryptedKeyset)
{
 "encryptedKeyset": "AAAAdAolAJk/lVU/ZxWW4QWmQ+1OHnudp33KHk8fc63vR73PpS4GDMZJyRJLACsKZVIgu8+wv6+GjLFk8STHpDKvwLw7jNBQK6JyHknJdOCUIMFMx5vlbE5qNvj/jUgBPzWDfk0E/Jmgtz90YORd0TGzB+fSQcz7Y8q2f/IBejC+6GiH90g3dZ03K/H/9oxSLh2FRg8kDQqDcn+6A/dJDYIF0bppVvJ2lSLGU11+WwKRIfcIzJxt23QENtST0IG4C8WQxcbsTcSkEsGyA9I2W8pYO2nWUSPgBuzTpgDBcL8FYuyhJQr3kRvV0xMtlBH+b9PZWd6l+3InJuUzK9ga7Q==",
 "keysetInfo": {
   "primaryKeyId": 2535709174,
   "keyInfo": [
     {
       "typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey",
       "status": "ENABLED",
       "keyId": 2535709174,
       "outputPrefixType": "TINK"
     }
   ]
 }
}
@thaidn
Copy link
Contributor

thaidn commented May 24, 2021

Unfortunately, neither ways are envelope encryption. I have a pending PR to clarify the documentation.

1/ In envelop encryption, you generate a unique key for each message you encrypt. The unique key will be encrypted and appended to each ciphertext. If this is your intention, check out this snippet:

gcpclient, err := gcpkms.NewClientWithCredentials(keyURI, credentialsPath)
  if err != nil {
    log.Fatal(err)
  }
  registry.RegisterKMSClient(gcpclient)

  dek := aead.AES256GCMKeyTemplate()
  kh, err := keyset.NewHandle(aead.KMSEnvelopeAEADKeyTemplate(keyURI, dek))
  if err != nil {
    log.Fatal(err)
  }

  a, err := aead.New(kh)
  if err != nil {
    log.Fatal(err)
  }

  msg := []byte("this message needs to be encrypted")
  aad := []byte("this data needs to be authenticated, but not encrypted")
  ct, err := a.Encrypt(msg, aad)
  if err != nil {
    log.Fatal(err)
  }

  pt, err := a.Decrypt(ct, aad)
  if err != nil {
    log.Fatal(err)
  }

  fmt.Printf("Ciphertext: %s\n", base64.StdEncoding.EncodeToString(ct))
  fmt.Printf("Original  plaintext: %s\n", msg)
  fmt.Printf("Decrypted Plaintext: %s\n", pt)
}

2/ In both A & B, however, you're generating an encrypted keyset that you will use to encrypt multiple messages. This means the encrypted keyset needs to be saved separately. If this is your intention, A is the correct solution.

@salrashid123
Copy link
Author

thanks for the explanation. I didn't realize the ciphertext already had the key added into it in the example you just cited (which is nice but also incurs kms-operations per object (+some latency)

I guess i can use A and then manually saving the encrypted keyset alongside the data that it encrypted (eg, as GCS metadata or as pubsub attribute). then maybe also have N objects/messages encrypted w/ the same keyset

@thaidn
Copy link
Contributor

thaidn commented May 24, 2021

thanks for the explanation. I didn't realize the ciphertext already had the key added into it in the example you just cited (which is nice but also incurs kms-operations per object (+some latency)

We're going to cache the DEK and reuse it for multiple messages. it'd look a lot like solution A, except that it consumes more space, because an encrypted DEK is still included in every single message. Some users like it this way though because they don't have to worry about where to store the encrypted keyset.

I guess i can use A and then manually saving the encrypted keyset alongside the data that it encrypted (eg, as GCS metadata or as pubsub attribute). then maybe also have N objects/messages encrypted w/ the same keyset

Yeah this should work.

Please reopen if you have any further question.

@thaidn thaidn closed this as completed May 24, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants