Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 109 additions & 42 deletions wrappers/alicloudkms/alicloudkms.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ const (
EnvVaultAliCloudKmsSealKeyId = "VAULT_ALICLOUDKMS_SEAL_KEY_ID"
)

const (
// AliCloudKmsEnvelopeAesGcmEncrypt is when a data encryption key is generated and
// the data is encrypted with AES-GCM and the key is encrypted with KMS
AliCloudKmsEnvelopeAesGcmEncrypt = iota
// AliCloudKmsEncrypt is used to directly encrypt the data with KMS
AliCloudKmsEncrypt
)

// Wrapper is a Wrapper that uses AliCloud's KMS
type Wrapper struct {
client kmsClient
Expand Down Expand Up @@ -164,32 +172,63 @@ func (k *Wrapper) Encrypt(_ context.Context, plaintext []byte, opt ...wrapping.O
return nil, fmt.Errorf("given plaintext for encryption is nil")
}

env, err := wrapping.EnvelopeEncrypt(plaintext, opt...)
opts, err := getOpts(opt...)
if err != nil {
return nil, fmt.Errorf("error wrapping data: %w", err)
return nil, err
}

input := kms.CreateEncryptRequest()
input.KeyId = k.keyId
input.Plaintext = base64.StdEncoding.EncodeToString(env.Key)
input.Domain = k.domain
var ret *wrapping.BlobInfo
if opts.WithoutEnvelope {
input := kms.CreateEncryptRequest()
input.KeyId = k.keyId
input.Plaintext = base64.StdEncoding.EncodeToString(plaintext)
input.Domain = k.domain

output, err := k.client.Encrypt(input)
if err != nil {
return nil, fmt.Errorf("error encrypting data: %w", err)
}
output, err := k.client.Encrypt(input)
if err != nil {
return nil, fmt.Errorf("error encrypting data: %w", err)
}

// Store the current key id.
keyId := output.KeyId
k.currentKeyId.Store(keyId)

// Store the current key id.
keyId := output.KeyId
k.currentKeyId.Store(keyId)

ret := &wrapping.BlobInfo{
Ciphertext: env.Ciphertext,
Iv: env.Iv,
KeyInfo: &wrapping.KeyInfo{
KeyId: keyId,
WrappedKey: []byte(output.CiphertextBlob),
},
ret = &wrapping.BlobInfo{
Ciphertext: []byte(output.CiphertextBlob),
KeyInfo: &wrapping.KeyInfo{
Mechanism: AliCloudKmsEncrypt,
KeyId: keyId,
},
}
} else {
env, err := wrapping.EnvelopeEncrypt(plaintext, opt...)
if err != nil {
return nil, fmt.Errorf("error wrapping data: %w", err)
}

input := kms.CreateEncryptRequest()
input.KeyId = k.keyId
input.Plaintext = base64.StdEncoding.EncodeToString(env.Key)
input.Domain = k.domain

output, err := k.client.Encrypt(input)
if err != nil {
return nil, fmt.Errorf("error encrypting data: %w", err)
}

// Store the current key id.
keyId := output.KeyId
k.currentKeyId.Store(keyId)

ret = &wrapping.BlobInfo{
Ciphertext: env.Ciphertext,
Iv: env.Iv,
KeyInfo: &wrapping.KeyInfo{
Mechanism: AliCloudKmsEnvelopeAesGcmEncrypt,
KeyId: keyId,
WrappedKey: []byte(output.CiphertextBlob),
},
}
}

return ret, nil
Expand All @@ -201,30 +240,58 @@ func (k *Wrapper) Decrypt(_ context.Context, in *wrapping.BlobInfo, opt ...wrapp
return nil, fmt.Errorf("given input for decryption is nil")
}

// KeyId is not passed to this call because AliCloud handles this
// internally based on the metadata stored with the encrypted data
input := kms.CreateDecryptRequest()
input.CiphertextBlob = string(in.KeyInfo.WrappedKey)
input.Domain = k.domain

output, err := k.client.Decrypt(input)
if err != nil {
return nil, fmt.Errorf("error decrypting data encryption key: %w", err)
if in.KeyInfo == nil {
return nil, errors.New("key info is nil")
}

keyBytes, err := base64.StdEncoding.DecodeString(output.Plaintext)
if err != nil {
return nil, err
}
var plaintext []byte
switch in.KeyInfo.Mechanism {
case AliCloudKmsEncrypt:
// KeyId is not passed to this call because AliCloud handles this
// internally based on the metadata stored with the encrypted data
input := kms.CreateDecryptRequest()
input.CiphertextBlob = string(in.Ciphertext)
input.Domain = k.domain

envInfo := &wrapping.EnvelopeInfo{
Key: keyBytes,
Iv: in.Iv,
Ciphertext: in.Ciphertext,
}
plaintext, err := wrapping.EnvelopeDecrypt(envInfo, opt...)
if err != nil {
return nil, fmt.Errorf("error decrypting data: %w", err)
output, err := k.client.Decrypt(input)
if err != nil {
return nil, fmt.Errorf("error decrypting data: %w", err)
}

plaintext, err = base64.StdEncoding.DecodeString(output.Plaintext)
if err != nil {
return nil, fmt.Errorf("error base64 decoding plaintext: %w", err)
}

case AliCloudKmsEnvelopeAesGcmEncrypt:
// KeyId is not passed to this call because AliCloud handles this
// internally based on the metadata stored with the encrypted data
input := kms.CreateDecryptRequest()
input.CiphertextBlob = string(in.KeyInfo.WrappedKey)
input.Domain = k.domain

output, err := k.client.Decrypt(input)
if err != nil {
return nil, fmt.Errorf("error decrypting data encryption key: %w", err)
}

keyBytes, err := base64.StdEncoding.DecodeString(output.Plaintext)
if err != nil {
return nil, fmt.Errorf("error base64 decoding key: %w", err)
}

envInfo := &wrapping.EnvelopeInfo{
Key: keyBytes,
Iv: in.Iv,
Ciphertext: in.Ciphertext,
}
plaintext, err = wrapping.EnvelopeDecrypt(envInfo, opt...)
if err != nil {
return nil, fmt.Errorf("error decrypting data: %w", err)
}

default:
return nil, fmt.Errorf("invalid mechanism: %d", in.KeyInfo.Mechanism)
}

return plaintext, nil
Expand Down
15 changes: 15 additions & 0 deletions wrappers/alicloudkms/alicloudkms_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"testing"

"github.com/aliyun/alibaba-cloud-sdk-go/services/kms"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
)

const aliCloudTestKeyId = "foo"
Expand Down Expand Up @@ -73,6 +74,20 @@ func TestAliCloudKmsWrapper_Lifecycle(t *testing.T) {
if !reflect.DeepEqual(input, pt) {
t.Fatalf("expected %s, got %s", input, pt)
}

swi, err = s.Encrypt(context.Background(), input, wrapping.WithoutEnvelope(true))
if err != nil {
t.Fatalf("err: %s", err.Error())
}

pt, err = s.Decrypt(context.Background(), swi, wrapping.WithoutEnvelope(true))
if err != nil {
t.Fatalf("err: %s", err.Error())
}

if !reflect.DeepEqual(input, pt) {
t.Fatalf("expected %s, got %s", input, pt)
}
}

type mockAliCloudKmsWrapperClient struct {
Expand Down
4 changes: 2 additions & 2 deletions wrappers/alicloudkms/go.mod
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
module github.com/hashicorp/go-kms-wrapping/wrappers/alicloudkms/v2

go 1.20
go 1.24.0

require (
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1499
github.com/hashicorp/go-kms-wrapping/v2 v2.0.17
github.com/hashicorp/go-kms-wrapping/v2 v2.0.21
)

require (
Expand Down
8 changes: 6 additions & 2 deletions wrappers/alicloudkms/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.17 h1:UjjwDABbv2Usc+ESZTC4DXimCRIyWUDBJe/LOUFxe/M=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.17/go.mod h1:M79wTAvbhiVLo1WmglCPBgI5CEETtZWh18B3eXipmFc=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.21 h1:7mL3k701Go+prNM7xf7JAz6HAFM2iaAUEiPnjAEu0dA=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.21/go.mod h1:NeK2Ul15t1zutp/dZzt28XQrGZHosbxE/QLNNfaWObM=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.9 h1:FW0YttEnUNDJ2WL9XcrrfteS1xW8u+sh4ggM8pN5isQ=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.9/go.mod h1:Ll013mhdmsVDuoIXVfBtvgGJsXDYkTw1kooNcoCXuE0=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts=
Expand Down Expand Up @@ -42,7 +43,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand All @@ -53,3 +56,4 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
106 changes: 69 additions & 37 deletions wrappers/awskms/awskms.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,46 +190,81 @@ func (k *Wrapper) Encrypt(ctx context.Context, plaintext []byte, opt ...wrapping
return nil, fmt.Errorf("given plaintext for encryption is nil")
}

env, err := wrapping.EnvelopeEncrypt(plaintext, opt...)
opts, err := getOpts(opt...)
if err != nil {
return nil, fmt.Errorf("error wrapping data: %w", err)
return nil, err
}

var ret *wrapping.BlobInfo
if k.client == nil {
return nil, fmt.Errorf("nil client")
}
if opts.WithoutEnvelope {
input := &kms.EncryptInput{
KeyId: &k.keyId,
Plaintext: plaintext,
}
output, err := k.client.Encrypt(ctx, input)
if err != nil {
return nil, fmt.Errorf("error encrypting data: %w", err)
}

input := &kms.EncryptInput{
KeyId: &k.keyId,
Plaintext: env.Key,
}
output, err := k.client.Encrypt(ctx, input)
if err != nil {
return nil, fmt.Errorf("error encrypting data: %w", err)
}
// Store the current key id
//
// When using a key alias, this will return the actual underlying key id
// used for encryption. This is helpful if you are looking to reencyrpt
// your data when it is not using the latest key id. See these docs relating
// to key rotation https://docs.aws.amazon.com/kms/latest/developerguide/rotate-keys.html
keyId := output.KeyId
k.currentKeyId.Store(*keyId)

ret = &wrapping.BlobInfo{
Ciphertext: output.CiphertextBlob,
KeyInfo: &wrapping.KeyInfo{
Mechanism: AwsKmsEncrypt,
// Even though we do not use the key id during decryption, store it
// to know exactly the specific key used in encryption in case we
// want to rewrap older entries
KeyId: *keyId,
},
}
} else {
env, err := wrapping.EnvelopeEncrypt(plaintext, opt...)
if err != nil {
return nil, fmt.Errorf("error wrapping data: %w", err)
}

// Store the current key id
//
// When using a key alias, this will return the actual underlying key id
// used for encryption. This is helpful if you are looking to reencyrpt
// your data when it is not using the latest key id. See these docs relating
// to key rotation https://docs.aws.amazon.com/kms/latest/developerguide/rotate-keys.html
keyId := output.KeyId
k.currentKeyId.Store(*keyId)

ret := &wrapping.BlobInfo{
Ciphertext: env.Ciphertext,
Iv: env.Iv,
KeyInfo: &wrapping.KeyInfo{
Mechanism: AwsKmsEnvelopeAesGcmEncrypt,
// Even though we do not use the key id during decryption, store it
// to know exactly the specific key used in encryption in case we
// want to rewrap older entries
KeyId: *keyId,
WrappedKey: output.CiphertextBlob,
},
}
input := &kms.EncryptInput{
KeyId: &k.keyId,
Plaintext: env.Key,
}
output, err := k.client.Encrypt(ctx, input)
if err != nil {
return nil, fmt.Errorf("error encrypting data: %w", err)
}

// Store the current key id
//
// When using a key alias, this will return the actual underlying key id
// used for encryption. This is helpful if you are looking to reencyrpt
// your data when it is not using the latest key id. See these docs relating
// to key rotation https://docs.aws.amazon.com/kms/latest/developerguide/rotate-keys.html
keyId := output.KeyId
k.currentKeyId.Store(*keyId)

ret = &wrapping.BlobInfo{
Ciphertext: env.Ciphertext,
Iv: env.Iv,
KeyInfo: &wrapping.KeyInfo{
Mechanism: AwsKmsEnvelopeAesGcmEncrypt,
// Even though we do not use the key id during decryption, store it
// to know exactly the specific key used in encryption in case we
// want to rewrap older entries
KeyId: *keyId,
WrappedKey: output.CiphertextBlob,
},
}
}
return ret, nil
}

Expand All @@ -239,11 +274,8 @@ func (k *Wrapper) Decrypt(ctx context.Context, in *wrapping.BlobInfo, opt ...wra
return nil, fmt.Errorf("given input for decryption is nil")
}

// Default to mechanism used before key info was stored
if in.KeyInfo == nil {
in.KeyInfo = &wrapping.KeyInfo{
Mechanism: AwsKmsEncrypt,
}
return nil, errors.New("key info is nil")
}

var plaintext []byte
Expand All @@ -265,13 +297,13 @@ func (k *Wrapper) Decrypt(ctx context.Context, in *wrapping.BlobInfo, opt ...wra
input := &kms.DecryptInput{
CiphertextBlob: in.KeyInfo.WrappedKey,
}
output, err := k.client.Decrypt(ctx, input)
resp, err := k.client.Decrypt(ctx, input)
if err != nil {
return nil, fmt.Errorf("error decrypting data encryption key: %w", err)
}

envInfo := &wrapping.EnvelopeInfo{
Key: output.Plaintext,
Key: resp.Plaintext,
Iv: in.Iv,
Ciphertext: in.Ciphertext,
}
Expand Down
Loading
Loading