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
69 changes: 37 additions & 32 deletions azure/azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import (
"context"
"encoding/base64"
"encoding/json"
"log"

"github.com/VirtusLab/crypt/version"

"github.com/Azure/azure-sdk-for-go/services/keyvault/2016-10-01/keyvault"
"github.com/Azure/azure-sdk-for-go/services/keyvault/2016-10-01/keyvault/keyvaultapi"
"github.com/Azure/azure-sdk-for-go/services/keyvault/auth"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys"

"github.com/pkg/errors"

"github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -44,33 +46,38 @@ type KeyVault struct {
vaultURL string
key string
keyVersion string
client keyvaultapi.BaseClientAPI
client KeyVaultClient
}

// KeyVaultClient interface represents Azure Key Vault client for encrypting and decrypting data
type KeyVaultClient interface {
Encrypt(ctx context.Context, name string, version string, parameters azkeys.KeyOperationsParameters, options *azkeys.EncryptOptions) (azkeys.EncryptResponse, error)
Decrypt(ctx context.Context, name string, version string, parameters azkeys.KeyOperationsParameters, options *azkeys.DecryptOptions) (azkeys.DecryptResponse, error)
}

// New creates Azure Key Vault KeyVault
// New creates Azure Key Vault KeyVault using chained token credential
func New(vaultURL, key, keyVersion string) (*KeyVault, error) {
client, err := newKeyVaultClient()
azCreds, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
log.Fatalf("failed to obtain a credential: %v", err)
}

if err != nil {
return nil, err // err already wrapped in newKeyVaultClient function
}
keyVaultClient, err := azkeys.NewClient(vaultURL, azCreds, nil)
if err != nil {
log.Fatal(err)
}

return &KeyVault{
client: client,
client: keyVaultClient,
vaultURL: vaultURL,
key: key,
keyVersion: keyVersion,
}, nil
}

func newKeyVaultClient() (keyvaultapi.BaseClientAPI, error) {
var err error
vaultClient := keyvault.New()
vaultClient.Authorizer, err = auth.NewAuthorizerFromCLI()
if err != nil {
return vaultClient, errors.Wrap(err, "failed to create Azure Authorizer")
}
return vaultClient, nil
}

// Encrypt encrypts plaintext using Azure Key Vault and returns ciphertext
// See Crypt.Encrypt
func (k *KeyVault) Encrypt(plaintext []byte) ([]byte, error) {
Expand All @@ -83,14 +90,12 @@ func (k *KeyVault) encrypt(plaintext []byte, includeHeader bool) ([]byte, error)
return nil, err // err already wrapped in validate function
}

data := base64.RawURLEncoding.EncodeToString(plaintext)
p := keyvault.KeyOperationsParameters{Value: &data, Algorithm: keyvault.RSAOAEP256}

res, err := k.client.Encrypt(context.Background(), k.vaultURL, k.key, k.keyVersion, p)
alg := azkeys.JSONWebKeyEncryptionAlgorithmRSAOAEP256
p := azkeys.KeyOperationsParameters{Value: plaintext, Algorithm: &alg}
res, err := k.client.Encrypt(context.Background(), k.key, k.keyVersion, p, nil)
if err != nil {
return nil, errors.WithStack(err)
return nil, errors.Wrap(err, "error with decoding data")
}

if includeHeader {
metadata := MetadataHeader{
Provider: providerName,
Expand All @@ -113,10 +118,12 @@ func (k *KeyVault) encrypt(plaintext []byte, includeHeader bool) ([]byte, error)
"keyVersion": k.keyVersion,
}).Info("Encryption succeeded")
result := append(metadataURLEncoded, encryptedFileMetadataSeparator)
result = append(result, []byte(*res.Result)...)
result = append(result, res.Result...)

return result, nil
}
result, err := base64.RawURLEncoding.DecodeString(*res.Result)

result, err := base64.RawURLEncoding.DecodeString(string(res.Result[:]))
if err != nil {
return nil, errors.Wrap(err, "error with decoding data")
}
Expand Down Expand Up @@ -157,17 +164,15 @@ func (k *KeyVault) Decrypt(ciphertext []byte) ([]byte, error) {
k.keyVersion = metadata.AzureKeyVaultKeyVersion
}

p := keyvault.KeyOperationsParameters{Value: &dataToDecrypt, Algorithm: keyvault.RSAOAEP256}

res, err := k.client.Decrypt(context.Background(), k.vaultURL, k.key, k.keyVersion, p)
if err != nil {
return nil, errors.WithStack(err)
}
var plaintext []byte

plaintext, err := base64.RawURLEncoding.DecodeString(*res.Result)
alg := azkeys.JSONWebKeyEncryptionAlgorithmRSAOAEP256
p := azkeys.KeyOperationsParameters{Value: []byte(dataToDecrypt), Algorithm: &alg}
res, err := k.client.Decrypt(context.Background(), k.key, k.keyVersion, p, nil)
if err != nil {
return nil, errors.Wrap(err, "error with decoding data")
}
plaintext = res.Result

logrus.WithFields(logrus.Fields{
"keyVaultURL": k.vaultURL,
Expand Down
5 changes: 2 additions & 3 deletions azure/azure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func TestEncryptedDataStructure(t *testing.T) {
vaultURL: "https://key-vault-url.com",
key: "key-vault-key",
keyVersion: "das87d8asgd",
client: fake.KeyVaultAPIClient{},
client: fake.FakeKeyVaultAPIClient{},
}
secret := "top secret token"

Expand All @@ -41,8 +41,7 @@ func TestEncryptedDataStructure(t *testing.T) {
assert.Equal(t, crypto.vaultURL, metadata.AzureKeyVaultURL)
assert.Equal(t, version.VERSION, metadata.CryptVersion)

dataToDecrypt := string(encrypted[indexOfSeparator+1:])
decrypted, err := base64.RawURLEncoding.DecodeString(string(dataToDecrypt))
decrypted := string(encrypted[indexOfSeparator+1:])
require.NoError(t, err, "encrypted data should be encoded with base64")
assert.Equal(t, secret, string(decrypted))
}
1 change: 0 additions & 1 deletion crypto/render/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ TemplateFunctions provides template functions for render or the standard (text/t
- decryptGCP - decrypts the data from inside of the template using GCP KMS, for best results use with ungzip and b64dec
- encryptAzure - encrypts the data from inside of the template using Azure Key Vault, for best results use with gzip and b64enc
- decryptAzure - decrypts the data from inside of the template using Azure Key Vault, for best results use with ungzip and b64dec

*/
func TemplateFunctions() template.FuncMap {
return template.FuncMap{
Expand Down
36 changes: 16 additions & 20 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,45 @@ module github.com/VirtusLab/crypt
go 1.17

require (
github.com/Azure/azure-sdk-for-go v65.0.0+incompatible
github.com/Azure/go-autorest/autorest v0.11.27
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0
github.com/VirtusLab/go-extended v0.0.11
github.com/aws/aws-sdk-go v1.44.21
github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.1
github.com/stretchr/testify v1.8.4
github.com/urfave/cli v1.22.9
golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898
golang.org/x/net v0.0.0-20220524220425-1d687d428aca
golang.org/x/crypto v0.17.0
golang.org/x/net v0.19.0
google.golang.org/api v0.81.0
)

require (
cloud.google.com/go/compute v1.6.1 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
github.com/Azure/go-autorest/autorest/azure/auth v0.5.11 // indirect
github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
github.com/golang-jwt/jwt/v5 v5.2.0 // indirect
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/uuid v1.5.0 // indirect
github.com/googleapis/gax-go/v2 v2.4.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/russross/blackfriday/v2 v2.0.1 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
go.opencensus.io v0.23.0 // indirect
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
golang.org/x/text v0.3.8 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd // indirect
google.golang.org/grpc v1.46.2 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading