2023-03-15 16:00:52 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2020-05-19 22:15:30 +00:00
|
|
|
package configutil
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"context"
|
|
|
|
"encoding/base64"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"regexp"
|
|
|
|
|
2022-08-23 19:37:16 +00:00
|
|
|
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
|
2020-05-19 22:15:30 +00:00
|
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
encryptRegex = regexp.MustCompile(`{{encrypt\(.*\)}}`)
|
|
|
|
decryptRegex = regexp.MustCompile(`{{decrypt\(.*\)}}`)
|
|
|
|
)
|
|
|
|
|
|
|
|
func EncryptDecrypt(rawStr string, decrypt, strip bool, wrapper wrapping.Wrapper) (string, error) {
|
|
|
|
var locs [][]int
|
|
|
|
raw := []byte(rawStr)
|
|
|
|
searchVal := "{{encrypt("
|
|
|
|
replaceVal := "{{decrypt("
|
|
|
|
suffixVal := ")}}"
|
|
|
|
if decrypt {
|
|
|
|
searchVal = "{{decrypt("
|
|
|
|
replaceVal = "{{encrypt("
|
|
|
|
locs = decryptRegex.FindAllIndex(raw, -1)
|
|
|
|
} else {
|
|
|
|
locs = encryptRegex.FindAllIndex(raw, -1)
|
|
|
|
}
|
|
|
|
if strip {
|
|
|
|
replaceVal = ""
|
|
|
|
suffixVal = ""
|
|
|
|
}
|
|
|
|
|
|
|
|
out := make([]byte, 0, len(rawStr)*2)
|
|
|
|
var prevMaxLoc int
|
|
|
|
for _, match := range locs {
|
|
|
|
if len(match) != 2 {
|
|
|
|
return "", fmt.Errorf("expected two values for match, got %d", len(match))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Append everything from the end of the last match to the beginning of this one
|
|
|
|
out = append(out, raw[prevMaxLoc:match[0]]...)
|
|
|
|
|
|
|
|
// Transform. First pull off the suffix/prefix
|
|
|
|
matchBytes := raw[match[0]:match[1]]
|
|
|
|
matchBytes = bytes.TrimSuffix(bytes.TrimPrefix(matchBytes, []byte(searchVal)), []byte(")}}"))
|
|
|
|
var finalVal string
|
|
|
|
|
|
|
|
// Now encrypt or decrypt
|
|
|
|
switch decrypt {
|
|
|
|
case false:
|
|
|
|
outBlob, err := wrapper.Encrypt(context.Background(), matchBytes, nil)
|
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("error encrypting parameter: %w", err)
|
|
|
|
}
|
|
|
|
if outBlob == nil {
|
|
|
|
return "", errors.New("nil value returned from encrypting parameter")
|
|
|
|
}
|
|
|
|
outMsg, err := proto.Marshal(outBlob)
|
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("error marshaling encrypted parameter: %w", err)
|
|
|
|
}
|
|
|
|
finalVal = base64.RawURLEncoding.EncodeToString(outMsg)
|
|
|
|
|
|
|
|
default:
|
|
|
|
inMsg, err := base64.RawURLEncoding.DecodeString(string(matchBytes))
|
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("error decoding encrypted parameter: %w", err)
|
|
|
|
}
|
2022-08-23 19:37:16 +00:00
|
|
|
inBlob := new(wrapping.BlobInfo)
|
2020-05-19 22:15:30 +00:00
|
|
|
if err := proto.Unmarshal(inMsg, inBlob); err != nil {
|
|
|
|
return "", fmt.Errorf("error unmarshaling encrypted parameter: %w", err)
|
|
|
|
}
|
|
|
|
dec, err := wrapper.Decrypt(context.Background(), inBlob, nil)
|
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("error decrypting encrypted parameter: %w", err)
|
|
|
|
}
|
|
|
|
finalVal = string(dec)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Append new value
|
|
|
|
out = append(out, []byte(fmt.Sprintf("%s%s%s", replaceVal, finalVal, suffixVal))...)
|
|
|
|
prevMaxLoc = match[1]
|
|
|
|
}
|
|
|
|
// At the end, append the rest
|
2021-04-08 16:43:39 +00:00
|
|
|
out = append(out, raw[prevMaxLoc:]...)
|
2020-05-19 22:15:30 +00:00
|
|
|
return string(out), nil
|
|
|
|
}
|