porting crypto functions
This commit is contained in:
parent
1a5299efcb
commit
9aa9b18658
|
@ -1,9 +1,16 @@
|
|||
package funcs
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
||||
uuid "github.com/hashicorp/go-uuid"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
"github.com/zclconf/go-cty/cty/function"
|
||||
"github.com/zclconf/go-cty/cty/gocty"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
var UUIDFunc = function.New(&function.Spec{
|
||||
|
@ -18,6 +25,82 @@ var UUIDFunc = function.New(&function.Spec{
|
|||
},
|
||||
})
|
||||
|
||||
// Base64Sha256Func constructs a function that computes the SHA256 hash of a given string and encodes it with
|
||||
// Base64.
|
||||
var Base64Sha256Func = function.New(&function.Spec{
|
||||
Params: []function.Parameter{
|
||||
{
|
||||
Name: "str",
|
||||
Type: cty.String,
|
||||
},
|
||||
},
|
||||
Type: function.StaticReturnType(cty.String),
|
||||
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
|
||||
s := args[0].AsString()
|
||||
h := sha256.New()
|
||||
h.Write([]byte(s))
|
||||
shaSum := h.Sum(nil)
|
||||
return cty.StringVal(base64.StdEncoding.EncodeToString(shaSum[:])), nil
|
||||
},
|
||||
})
|
||||
|
||||
// Base64Sha512Func constructs a function that computes the SHA256 hash of a given string and encodes it with
|
||||
// Base64.
|
||||
var Base64Sha512Func = function.New(&function.Spec{
|
||||
Params: []function.Parameter{
|
||||
{
|
||||
Name: "str",
|
||||
Type: cty.String,
|
||||
},
|
||||
},
|
||||
Type: function.StaticReturnType(cty.String),
|
||||
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
|
||||
s := args[0].AsString()
|
||||
h := sha512.New()
|
||||
h.Write([]byte(s))
|
||||
shaSum := h.Sum(nil)
|
||||
return cty.StringVal(base64.StdEncoding.EncodeToString(shaSum[:])), nil
|
||||
},
|
||||
})
|
||||
|
||||
// BcryptFunc constructs a function that computes a hash of the given string using the Blowfish cipher.
|
||||
var BcryptFunc = function.New(&function.Spec{
|
||||
Params: []function.Parameter{
|
||||
{
|
||||
Name: "str",
|
||||
Type: cty.String,
|
||||
},
|
||||
},
|
||||
VarParam: &function.Parameter{
|
||||
Name: "cost",
|
||||
Type: cty.Number,
|
||||
},
|
||||
Type: function.StaticReturnType(cty.String),
|
||||
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
|
||||
defaultCost := 10
|
||||
|
||||
if len(args) > 1 {
|
||||
var val int
|
||||
if err := gocty.FromCtyValue(args[1], &val); err != nil {
|
||||
return cty.UnknownVal(cty.String), err
|
||||
}
|
||||
defaultCost = val
|
||||
}
|
||||
|
||||
if len(args) > 2 {
|
||||
return cty.UnknownVal(cty.String), fmt.Errorf("bcrypt() takes no more than two arguments")
|
||||
}
|
||||
|
||||
input := args[0].AsString()
|
||||
out, err := bcrypt.GenerateFromPassword([]byte(input), defaultCost)
|
||||
if err != nil {
|
||||
return cty.UnknownVal(cty.String), fmt.Errorf("error occured generating password %s", err.Error())
|
||||
}
|
||||
|
||||
return cty.StringVal(string(out)), nil
|
||||
},
|
||||
})
|
||||
|
||||
// UUID generates and returns a Type-4 UUID in the standard hexadecimal string
|
||||
// format.
|
||||
//
|
||||
|
@ -27,3 +110,35 @@ var UUIDFunc = function.New(&function.Spec{
|
|||
func UUID() (cty.Value, error) {
|
||||
return UUIDFunc.Call(nil)
|
||||
}
|
||||
|
||||
// Base64sha256 computes the SHA256 hash of a given string and encodes it with
|
||||
// Base64.
|
||||
//
|
||||
// The given string is first encoded as UTF-8 and then the SHA256 algorithm is applied
|
||||
// as defined in [RFC 4634](https://tools.ietf.org/html/rfc4634). The raw hash is
|
||||
// then encoded with Base64 before returning. Terraform uses the "standard" Base64
|
||||
// alphabet as defined in [RFC 4648 section 4](https://tools.ietf.org/html/rfc4648#section-4).
|
||||
func Base64Sha256(str cty.Value) (cty.Value, error) {
|
||||
return Base64Sha256Func.Call([]cty.Value{str})
|
||||
}
|
||||
|
||||
// Base64sha512 computes the SHA512 hash of a given string and encodes it with
|
||||
// Base64.
|
||||
//
|
||||
// The given string is first encoded as UTF-8 and then the SHA256 algorithm is applied
|
||||
// as defined in [RFC 4634](https://tools.ietf.org/html/rfc4634). The raw hash is
|
||||
// then encoded with Base64 before returning. Terraform uses the "standard" Base64
|
||||
// alphabet as defined in [RFC 4648 section 4](https://tools.ietf.org/html/rfc4648#section-4).
|
||||
func Base64Sha512(str cty.Value) (cty.Value, error) {
|
||||
return Base64Sha512Func.Call([]cty.Value{str})
|
||||
}
|
||||
|
||||
// Bcrypt computes a hash of the given string using the Blowfish cipher,
|
||||
// returning a string in the Modular Crypt Format(https://passlib.readthedocs.io/en/stable/modular_crypt_format.html)
|
||||
// usually expected in the shadow password file on many Unix systems.
|
||||
func Bcrypt(str cty.Value, cost ...cty.Value) (cty.Value, error) {
|
||||
args := make([]cty.Value, len(cost)+1)
|
||||
args[0] = str
|
||||
copy(args[1:], cost)
|
||||
return BcryptFunc.Call(args)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
package funcs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func TestUUID(t *testing.T) {
|
||||
|
@ -15,3 +19,109 @@ func TestUUID(t *testing.T) {
|
|||
t.Errorf("wrong result length %d; want %d", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBase64Sha256(t *testing.T) {
|
||||
tests := []struct {
|
||||
String cty.Value
|
||||
Want cty.Value
|
||||
Err bool
|
||||
}{
|
||||
{
|
||||
cty.StringVal("test"),
|
||||
cty.StringVal("n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg="),
|
||||
false,
|
||||
},
|
||||
// This would differ because we're base64-encoding hex represantiation, not raw bytes.
|
||||
// base64encode(sha256("test")) =
|
||||
// "OWY4NmQwODE4ODRjN2Q2NTlhMmZlYWEwYzU1YWQwMTVhM2JmNGYxYjJiMGI4MjJjZDE1ZDZjMTViMGYwMGEwOA=="
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(fmt.Sprintf("base64sha256(%#v)", test.String), func(t *testing.T) {
|
||||
got, err := Base64Sha256(test.String)
|
||||
|
||||
if test.Err {
|
||||
if err == nil {
|
||||
t.Fatal("succeeded; want error")
|
||||
}
|
||||
return
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if !got.RawEquals(test.Want) {
|
||||
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBase64Sha512(t *testing.T) {
|
||||
tests := []struct {
|
||||
String cty.Value
|
||||
Want cty.Value
|
||||
Err bool
|
||||
}{
|
||||
{
|
||||
cty.StringVal("test"),
|
||||
cty.StringVal("7iaw3Ur350mqGo7jwQrpkj9hiYB3Lkc/iBml1JQODbJ6wYX4oOHV+E+IvIh/1nsUNzLDBMxfqa2Ob1f1ACio/w=="),
|
||||
false,
|
||||
},
|
||||
// This would differ because we're base64-encoding hex represantiation, not raw bytes
|
||||
// base64encode(sha512("test")) =
|
||||
// "OZWUyNmIwZGQ0YWY3ZTc0OWFhMWE4ZWUzYzEwYWU5OTIzZjYxODk4MDc3MmU0NzNmODgxOWE1ZDQ5NDBlMGRiMjdhYzE4NWY4YTBlMWQ1Zjg0Zjg4YmM4ODdmZDY3YjE0MzczMmMzMDRjYzVmYTlhZDhlNmY1N2Y1MDAyOGE4ZmY="
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(fmt.Sprintf("base64sha512(%#v)", test.String), func(t *testing.T) {
|
||||
got, err := Base64Sha512(test.String)
|
||||
|
||||
if test.Err {
|
||||
if err == nil {
|
||||
t.Fatal("succeeded; want error")
|
||||
}
|
||||
return
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if !got.RawEquals(test.Want) {
|
||||
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBcrypt(t *testing.T) {
|
||||
// single variable test
|
||||
p, err := Bcrypt(cty.StringVal("test"))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
err = bcrypt.CompareHashAndPassword([]byte(p.AsString()), []byte("test"))
|
||||
if err != nil {
|
||||
t.Fatalf("Error comparing hash and password: %s", err)
|
||||
}
|
||||
|
||||
// testing with two parameters
|
||||
p, err = Bcrypt(cty.StringVal("test"), cty.NumberIntVal(5))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
err = bcrypt.CompareHashAndPassword([]byte(p.AsString()), []byte("test"))
|
||||
if err != nil {
|
||||
t.Fatalf("Error comparing hash and password: %s", err)
|
||||
}
|
||||
|
||||
// Negative test for more than two parameters
|
||||
_, err = Bcrypt(cty.StringVal("test"), cty.NumberIntVal(10), cty.NumberIntVal(11))
|
||||
if err == nil {
|
||||
t.Fatal("succeeded; want error")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,9 +33,9 @@ func (s *Scope) Functions() map[string]function.Function {
|
|||
"base64decode": funcs.Base64DecodeFunc,
|
||||
"base64encode": funcs.Base64EncodeFunc,
|
||||
"base64gzip": funcs.Base64GzipFunc,
|
||||
"base64sha256": unimplFunc, // TODO
|
||||
"base64sha512": unimplFunc, // TODO
|
||||
"bcrypt": unimplFunc, // TODO
|
||||
"base64sha256": funcs.Base64Sha256Func,
|
||||
"base64sha512": funcs.Base64Sha512Func,
|
||||
"bcrypt": funcs.BcryptFunc,
|
||||
"ceil": unimplFunc, // TODO
|
||||
"chomp": unimplFunc, // TODO
|
||||
"cidrhost": unimplFunc, // TODO
|
||||
|
@ -63,6 +63,7 @@ func (s *Scope) Functions() map[string]function.Function {
|
|||
"join": funcs.JoinFunc,
|
||||
"jsondecode": stdlib.JSONDecodeFunc,
|
||||
"jsonencode": stdlib.JSONEncodeFunc,
|
||||
"keys": unimplFunc, // TODO
|
||||
"length": funcs.LengthFunc,
|
||||
"list": unimplFunc, // TODO
|
||||
"log": unimplFunc, // TODO
|
||||
|
@ -93,6 +94,7 @@ func (s *Scope) Functions() map[string]function.Function {
|
|||
"upper": stdlib.UpperFunc,
|
||||
"urlencode": funcs.UrlEncodeFunc,
|
||||
"uuid": funcs.UUIDFunc,
|
||||
"values": unimplFunc, // TODO
|
||||
"zipmap": unimplFunc, // TODO
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,8 @@ description: |-
|
|||
# `base64sha256` Function
|
||||
|
||||
`base64sha256` computes the SHA256 hash of a given string and encodes it with
|
||||
Base64.
|
||||
Base64. This is not equivalent to base64encode(sha256512("test")) since sha512()
|
||||
returns hexadecimal representation.
|
||||
|
||||
The given string is first encoded as UTF-8 and then the SHA256 algorithm is applied
|
||||
as defined in [RFC 4634](https://tools.ietf.org/html/rfc4634). The raw hash is
|
||||
|
|
|
@ -10,7 +10,8 @@ description: |-
|
|||
# `base64sha512` Function
|
||||
|
||||
`base64sha512` computes the SHA512 hash of a given string and encodes it with
|
||||
Base64.
|
||||
Base64. This is not equivalent to base64encode(sha512("test")) since sha512()
|
||||
returns hexadecimal representation.
|
||||
|
||||
The given string is first encoded as UTF-8 and then the SHA512 algorithm is applied
|
||||
as defined in [RFC 4634](https://tools.ietf.org/html/rfc4634). The raw hash is
|
||||
|
|
Loading…
Reference in New Issue