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 }