github.com/TIBCOSoftware/flogo-lib@v0.5.9/core/data/secretresolver.go (about)

     1  package data
     2  
     3  import (
     4  	"crypto/aes"
     5  	"crypto/cipher"
     6  	"crypto/rand"
     7  	"crypto/sha256"
     8  	"encoding/base64"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  
    13  	"github.com/TIBCOSoftware/flogo-lib/config"
    14  )
    15  
    16  var secretValueHandler SecretValueHandler
    17  
    18  // SecretValueDecoder defines method for decoding value
    19  type SecretValueHandler interface {
    20  	EncodeValue(value interface{}) (string, error)
    21  	DecodeValue(value interface{}) (string, error)
    22  }
    23  
    24  // Set secret value decoder
    25  func SetSecretValueHandler(pwdResolver SecretValueHandler) {
    26  	secretValueHandler = pwdResolver
    27  }
    28  
    29  // Get secret value handler. If not already set by SetSecretValueHandler(), will return default KeyBasedSecretValueDecoder
    30  // where decoding key value is expected to be set through FLOGO_DATA_SECRET_KEY environment variable.
    31  // If key is not set, a default key value(github.com/TIBCOSoftware/flogo-lib/config.DATA_SECRET_KEY_DEFAULT) will be used.
    32  func GetSecretValueHandler() SecretValueHandler {
    33  	if secretValueHandler == nil {
    34  		secretValueHandler = &KeyBasedSecretValueHandler{Key: config.GetDataSecretKey()}
    35  	}
    36  	return secretValueHandler
    37  }
    38  
    39  // A key based secret value decoder. Secret value encryption/decryption is based on SHA256
    40  // and uses implementation from https://gist.github.com/willshiao/f4b03650e5a82561a460b4a15789cfa1
    41  type KeyBasedSecretValueHandler struct {
    42  	Key string
    43  }
    44  
    45  // Decode value based on a key
    46  func (defaultResolver *KeyBasedSecretValueHandler) DecodeValue(value interface{}) (string, error) {
    47  	if value != nil {
    48  		if defaultResolver.Key != "" {
    49  			kBytes := sha256.Sum256([]byte(defaultResolver.Key))
    50  			return decryptValue(kBytes[:], value.(string))
    51  		}
    52  		return value.(string), nil
    53  	}
    54  	return "", nil
    55  }
    56  
    57  func (defaultResolver *KeyBasedSecretValueHandler) EncodeValue(value interface{}) (string, error) {
    58  	if value != nil {
    59  		if defaultResolver.Key != "" {
    60  			kBytes := sha256.Sum256([]byte(defaultResolver.Key))
    61  			return encryptValue(kBytes[:], value.(string))
    62  		}
    63  		return value.(string), nil
    64  	}
    65  	return "", nil
    66  }
    67  
    68  // encrypt string to base64 crypto using AES
    69  func encryptValue(key []byte, text string) (string, error) {
    70  	plaintext := []byte(text)
    71  
    72  	block, err := aes.NewCipher(key)
    73  	if err != nil {
    74  		return "", err
    75  	}
    76  
    77  	// The IV needs to be unique, but not secure. Therefore it's common to
    78  	// include it at the beginning of the ciphertext.
    79  	ciphertext := make([]byte, aes.BlockSize+len(plaintext))
    80  	iv := ciphertext[:aes.BlockSize]
    81  	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
    82  		return "", err
    83  	}
    84  
    85  	stream := cipher.NewCFBEncrypter(block, iv)
    86  	stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
    87  
    88  	return base64.StdEncoding.EncodeToString(ciphertext), nil
    89  }
    90  
    91  // decrypt from base64 to decrypted string
    92  func decryptValue(key []byte, encryptedData string) (string, error) {
    93  	ciphertext, err := base64.StdEncoding.DecodeString(encryptedData)
    94  	if err != nil {
    95  		return "", err
    96  	}
    97  
    98  	block, err := aes.NewCipher(key)
    99  	if err != nil {
   100  		return "", err
   101  	}
   102  
   103  	if len(ciphertext) < aes.BlockSize {
   104  		return "", errors.New("ciphertext too short")
   105  	}
   106  
   107  	iv := ciphertext[:aes.BlockSize]
   108  	ciphertext = ciphertext[aes.BlockSize:]
   109  	stream := cipher.NewCFBDecrypter(block, iv)
   110  	stream.XORKeyStream(ciphertext, ciphertext)
   111  	return fmt.Sprintf("%s", ciphertext), nil
   112  }