mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
porting crypto functions
This commit is contained in:
parent
1a5299efcb
commit
9aa9b18658
@ -1,9 +1,16 @@
|
|||||||
package funcs
|
package funcs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/sha512"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
uuid "github.com/hashicorp/go-uuid"
|
uuid "github.com/hashicorp/go-uuid"
|
||||||
"github.com/zclconf/go-cty/cty"
|
"github.com/zclconf/go-cty/cty"
|
||||||
"github.com/zclconf/go-cty/cty/function"
|
"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{
|
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
|
// UUID generates and returns a Type-4 UUID in the standard hexadecimal string
|
||||||
// format.
|
// format.
|
||||||
//
|
//
|
||||||
@ -27,3 +110,35 @@ var UUIDFunc = function.New(&function.Spec{
|
|||||||
func UUID() (cty.Value, error) {
|
func UUID() (cty.Value, error) {
|
||||||
return UUIDFunc.Call(nil)
|
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
|
package funcs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/zclconf/go-cty/cty"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestUUID(t *testing.T) {
|
func TestUUID(t *testing.T) {
|
||||||
@ -15,3 +19,109 @@ func TestUUID(t *testing.T) {
|
|||||||
t.Errorf("wrong result length %d; want %d", got, want)
|
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,
|
"base64decode": funcs.Base64DecodeFunc,
|
||||||
"base64encode": funcs.Base64EncodeFunc,
|
"base64encode": funcs.Base64EncodeFunc,
|
||||||
"base64gzip": funcs.Base64GzipFunc,
|
"base64gzip": funcs.Base64GzipFunc,
|
||||||
"base64sha256": unimplFunc, // TODO
|
"base64sha256": funcs.Base64Sha256Func,
|
||||||
"base64sha512": unimplFunc, // TODO
|
"base64sha512": funcs.Base64Sha512Func,
|
||||||
"bcrypt": unimplFunc, // TODO
|
"bcrypt": funcs.BcryptFunc,
|
||||||
"ceil": unimplFunc, // TODO
|
"ceil": unimplFunc, // TODO
|
||||||
"chomp": unimplFunc, // TODO
|
"chomp": unimplFunc, // TODO
|
||||||
"cidrhost": unimplFunc, // TODO
|
"cidrhost": unimplFunc, // TODO
|
||||||
@ -63,6 +63,7 @@ func (s *Scope) Functions() map[string]function.Function {
|
|||||||
"join": funcs.JoinFunc,
|
"join": funcs.JoinFunc,
|
||||||
"jsondecode": stdlib.JSONDecodeFunc,
|
"jsondecode": stdlib.JSONDecodeFunc,
|
||||||
"jsonencode": stdlib.JSONEncodeFunc,
|
"jsonencode": stdlib.JSONEncodeFunc,
|
||||||
|
"keys": unimplFunc, // TODO
|
||||||
"length": funcs.LengthFunc,
|
"length": funcs.LengthFunc,
|
||||||
"list": unimplFunc, // TODO
|
"list": unimplFunc, // TODO
|
||||||
"log": unimplFunc, // TODO
|
"log": unimplFunc, // TODO
|
||||||
@ -93,6 +94,7 @@ func (s *Scope) Functions() map[string]function.Function {
|
|||||||
"upper": stdlib.UpperFunc,
|
"upper": stdlib.UpperFunc,
|
||||||
"urlencode": funcs.UrlEncodeFunc,
|
"urlencode": funcs.UrlEncodeFunc,
|
||||||
"uuid": funcs.UUIDFunc,
|
"uuid": funcs.UUIDFunc,
|
||||||
|
"values": unimplFunc, // TODO
|
||||||
"zipmap": unimplFunc, // TODO
|
"zipmap": unimplFunc, // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,8 @@ description: |-
|
|||||||
# `base64sha256` Function
|
# `base64sha256` Function
|
||||||
|
|
||||||
`base64sha256` computes the SHA256 hash of a given string and encodes it with
|
`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
|
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
|
as defined in [RFC 4634](https://tools.ietf.org/html/rfc4634). The raw hash is
|
||||||
|
@ -10,7 +10,8 @@ description: |-
|
|||||||
# `base64sha512` Function
|
# `base64sha512` Function
|
||||||
|
|
||||||
`base64sha512` computes the SHA512 hash of a given string and encodes it with
|
`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
|
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
|
as defined in [RFC 4634](https://tools.ietf.org/html/rfc4634). The raw hash is
|
||||||
|
Loading…
Reference in New Issue
Block a user