16 uuid "github.com/hashicorp/go-uuid"
17 "github.com/zclconf/go-cty/cty"
18 "github.com/zclconf/go-cty/cty/function"
19 "github.com/zclconf/go-cty/cty/gocty"
20 "golang.org/x/crypto/bcrypt"
23 var UUIDFunc = function.New(&function.Spec{
24 Params: []function.Parameter{},
25 Type: function.StaticReturnType(cty.String),
26 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
27 result, err := uuid.GenerateUUID()
29 return cty.UnknownVal(cty.String), err
31 return cty.StringVal(result), nil
35 // Base64Sha256Func constructs a function that computes the SHA256 hash of a given string
36 // and encodes it with Base64.
37 var Base64Sha256Func = makeStringHashFunction(sha256.New, base64.StdEncoding.EncodeToString)
39 // MakeFileBase64Sha256Func constructs a function that is like Base64Sha256Func but reads the
40 // contents of a file rather than hashing a given literal string.
41 func MakeFileBase64Sha256Func(baseDir string) function.Function {
42 return makeFileHashFunction(baseDir, sha256.New, base64.StdEncoding.EncodeToString)
45 // Base64Sha512Func constructs a function that computes the SHA256 hash of a given string
46 // and encodes it with Base64.
47 var Base64Sha512Func = makeStringHashFunction(sha512.New, base64.StdEncoding.EncodeToString)
49 // MakeFileBase64Sha512Func constructs a function that is like Base64Sha512Func but reads the
50 // contents of a file rather than hashing a given literal string.
51 func MakeFileBase64Sha512Func(baseDir string) function.Function {
52 return makeFileHashFunction(baseDir, sha512.New, base64.StdEncoding.EncodeToString)
55 // BcryptFunc constructs a function that computes a hash of the given string using the Blowfish cipher.
56 var BcryptFunc = function.New(&function.Spec{
57 Params: []function.Parameter{
63 VarParam: &function.Parameter{
67 Type: function.StaticReturnType(cty.String),
68 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
73 if err := gocty.FromCtyValue(args[1], &val); err != nil {
74 return cty.UnknownVal(cty.String), err
80 return cty.UnknownVal(cty.String), fmt.Errorf("bcrypt() takes no more than two arguments")
83 input := args[0].AsString()
84 out, err := bcrypt.GenerateFromPassword([]byte(input), defaultCost)
86 return cty.UnknownVal(cty.String), fmt.Errorf("error occured generating password %s", err.Error())
89 return cty.StringVal(string(out)), nil
93 // Md5Func constructs a function that computes the MD5 hash of a given string and encodes it with hexadecimal digits.
94 var Md5Func = makeStringHashFunction(md5.New, hex.EncodeToString)
96 // MakeFileMd5Func constructs a function that is like Md5Func but reads the
97 // contents of a file rather than hashing a given literal string.
98 func MakeFileMd5Func(baseDir string) function.Function {
99 return makeFileHashFunction(baseDir, md5.New, hex.EncodeToString)
102 // RsaDecryptFunc constructs a function that decrypts an RSA-encrypted ciphertext.
103 var RsaDecryptFunc = function.New(&function.Spec{
104 Params: []function.Parameter{
114 Type: function.StaticReturnType(cty.String),
115 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
116 s := args[0].AsString()
117 key := args[1].AsString()
119 b, err := base64.StdEncoding.DecodeString(s)
121 return cty.UnknownVal(cty.String), fmt.Errorf("failed to decode input %q: cipher text must be base64-encoded", s)
124 block, _ := pem.Decode([]byte(key))
126 return cty.UnknownVal(cty.String), fmt.Errorf("failed to parse key: no key found")
128 if block.Headers["Proc-Type"] == "4,ENCRYPTED" {
129 return cty.UnknownVal(cty.String), fmt.Errorf(
130 "failed to parse key: password protected keys are not supported. Please decrypt the key prior to use",
134 x509Key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
136 return cty.UnknownVal(cty.String), err
139 out, err := rsa.DecryptPKCS1v15(nil, x509Key, b)
141 return cty.UnknownVal(cty.String), err
144 return cty.StringVal(string(out)), nil
148 // Sha1Func contructs a function that computes the SHA1 hash of a given string
149 // and encodes it with hexadecimal digits.
150 var Sha1Func = makeStringHashFunction(sha1.New, hex.EncodeToString)
152 // MakeFileSha1Func constructs a function that is like Sha1Func but reads the
153 // contents of a file rather than hashing a given literal string.
154 func MakeFileSha1Func(baseDir string) function.Function {
155 return makeFileHashFunction(baseDir, sha1.New, hex.EncodeToString)
158 // Sha256Func contructs a function that computes the SHA256 hash of a given string
159 // and encodes it with hexadecimal digits.
160 var Sha256Func = makeStringHashFunction(sha256.New, hex.EncodeToString)
162 // MakeFileSha256Func constructs a function that is like Sha256Func but reads the
163 // contents of a file rather than hashing a given literal string.
164 func MakeFileSha256Func(baseDir string) function.Function {
165 return makeFileHashFunction(baseDir, sha256.New, hex.EncodeToString)
168 // Sha512Func contructs a function that computes the SHA512 hash of a given string
169 // and encodes it with hexadecimal digits.
170 var Sha512Func = makeStringHashFunction(sha512.New, hex.EncodeToString)
172 // MakeFileSha512Func constructs a function that is like Sha512Func but reads the
173 // contents of a file rather than hashing a given literal string.
174 func MakeFileSha512Func(baseDir string) function.Function {
175 return makeFileHashFunction(baseDir, sha512.New, hex.EncodeToString)
178 func makeStringHashFunction(hf func() hash.Hash, enc func([]byte) string) function.Function {
179 return function.New(&function.Spec{
180 Params: []function.Parameter{
186 Type: function.StaticReturnType(cty.String),
187 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
188 s := args[0].AsString()
191 rv := enc(h.Sum(nil))
192 return cty.StringVal(rv), nil
197 func makeFileHashFunction(baseDir string, hf func() hash.Hash, enc func([]byte) string) function.Function {
198 return function.New(&function.Spec{
199 Params: []function.Parameter{
205 Type: function.StaticReturnType(cty.String),
206 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
207 path := args[0].AsString()
208 src, err := readFileBytes(baseDir, path)
210 return cty.UnknownVal(cty.String), err
215 rv := enc(h.Sum(nil))
216 return cty.StringVal(rv), nil
221 // UUID generates and returns a Type-4 UUID in the standard hexadecimal string
224 // This is not a pure function: it will generate a different result for each
225 // call. It must therefore be registered as an impure function in the function
226 // table in the "lang" package.
227 func UUID() (cty.Value, error) {
228 return UUIDFunc.Call(nil)
231 // Base64Sha256 computes the SHA256 hash of a given string and encodes it with
234 // The given string is first encoded as UTF-8 and then the SHA256 algorithm is applied
235 // as defined in RFC 4634. The raw hash is then encoded with Base64 before returning.
236 // Terraform uses the "standard" Base64 alphabet as defined in RFC 4648 section 4.
237 func Base64Sha256(str cty.Value) (cty.Value, error) {
238 return Base64Sha256Func.Call([]cty.Value{str})
241 // Base64Sha512 computes the SHA512 hash of a given string and encodes it with
244 // The given string is first encoded as UTF-8 and then the SHA256 algorithm is applied
245 // as defined in RFC 4634. The raw hash is then encoded with Base64 before returning.
246 // Terraform uses the "standard" Base64 alphabet as defined in RFC 4648 section 4
247 func Base64Sha512(str cty.Value) (cty.Value, error) {
248 return Base64Sha512Func.Call([]cty.Value{str})
251 // Bcrypt computes a hash of the given string using the Blowfish cipher,
252 // returning a string in the Modular Crypt Format
253 // usually expected in the shadow password file on many Unix systems.
254 func Bcrypt(str cty.Value, cost ...cty.Value) (cty.Value, error) {
255 args := make([]cty.Value, len(cost)+1)
258 return BcryptFunc.Call(args)
261 // Md5 computes the MD5 hash of a given string and encodes it with hexadecimal digits.
262 func Md5(str cty.Value) (cty.Value, error) {
263 return Md5Func.Call([]cty.Value{str})
266 // RsaDecrypt decrypts an RSA-encrypted ciphertext, returning the corresponding
268 func RsaDecrypt(ciphertext, privatekey cty.Value) (cty.Value, error) {
269 return RsaDecryptFunc.Call([]cty.Value{ciphertext, privatekey})
272 // Sha1 computes the SHA1 hash of a given string and encodes it with hexadecimal digits.
273 func Sha1(str cty.Value) (cty.Value, error) {
274 return Sha1Func.Call([]cty.Value{str})
277 // Sha256 computes the SHA256 hash of a given string and encodes it with hexadecimal digits.
278 func Sha256(str cty.Value) (cty.Value, error) {
279 return Sha256Func.Call([]cty.Value{str})
282 // Sha512 computes the SHA512 hash of a given string and encodes it with hexadecimal digits.
283 func Sha512(str cty.Value) (cty.Value, error) {
284 return Sha512Func.Call([]cty.Value{str})