pkg/crypto/hmac: add crypto/hmac support
Adds interface for the standard library crypto/hmac package, along with a
way to select from a list of supported hash functions.
Fixes #788
Change-Id: Ifdbe031a6da4a8690448ae66d562079068539449
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/8861
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/pkg/crypto/hmac/hmac.go b/pkg/crypto/hmac/hmac.go
new file mode 100644
index 0000000..851d356
--- /dev/null
+++ b/pkg/crypto/hmac/hmac.go
@@ -0,0 +1,71 @@
+// Copyright 2020 CUE Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package hmac
+
+import (
+ "crypto/hmac"
+ "crypto/md5"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/sha512"
+ "fmt"
+ "hash"
+)
+
+const (
+ MD5 = "MD5"
+ SHA1 = "SHA1"
+ SHA224 = "SHA224"
+ SHA256 = "SHA256"
+ SHA384 = "SHA384"
+ SHA512 = "SHA512"
+ SHA512_224 = "SHA512_224"
+ SHA512_256 = "SHA512_256"
+)
+
+// Sign returns the HMAC signature of the data, using the provided key and hash function.
+//
+// Supported hash functions: "MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512", "SHA512_224",
+// and "SHA512_256".
+func Sign(hashName string, key []byte, data []byte) ([]byte, error) {
+ hash, err := hashFromName(hashName)
+ if err != nil {
+ return nil, err
+ }
+ mac := hmac.New(hash, key)
+ mac.Write(data)
+ return mac.Sum(nil), nil
+}
+
+func hashFromName(hash string) (func() hash.Hash, error) {
+ switch hash {
+ case MD5:
+ return md5.New, nil
+ case SHA1:
+ return sha1.New, nil
+ case SHA224:
+ return sha256.New224, nil
+ case SHA256:
+ return sha256.New, nil
+ case SHA384:
+ return sha512.New384, nil
+ case SHA512:
+ return sha512.New, nil
+ case SHA512_224:
+ return sha512.New512_224, nil
+ case SHA512_256:
+ return sha512.New512_256, nil
+ }
+ return nil, fmt.Errorf("unsupported hash function")
+}
diff --git a/pkg/crypto/hmac/hmac_test.go b/pkg/crypto/hmac/hmac_test.go
new file mode 100644
index 0000000..27326e1
--- /dev/null
+++ b/pkg/crypto/hmac/hmac_test.go
@@ -0,0 +1,24 @@
+// Copyright 2020 CUE Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package hmac_test
+
+import (
+ "testing"
+
+ "cuelang.org/go/pkg/internal/builtintest"
+)
+
+func TestBuiltin(t *testing.T) {
+ builtintest.Run("hmac", t)
+}
diff --git a/pkg/crypto/hmac/pkg.go b/pkg/crypto/hmac/pkg.go
new file mode 100644
index 0000000..98d72c9
--- /dev/null
+++ b/pkg/crypto/hmac/pkg.go
@@ -0,0 +1,59 @@
+// Code generated by go generate. DO NOT EDIT.
+
+//go:generate rm pkg.go
+//go:generate go run ../../gen/gen.go
+
+package hmac
+
+import (
+ "cuelang.org/go/internal/core/adt"
+ "cuelang.org/go/pkg/internal"
+)
+
+func init() {
+ internal.Register("crypto/hmac", pkg)
+}
+
+var _ = adt.TopKind // in case the adt package isn't used
+
+var pkg = &internal.Package{
+ Native: []*internal.Builtin{{
+ Name: "MD5",
+ Const: "\"MD5\"",
+ }, {
+ Name: "SHA1",
+ Const: "\"SHA1\"",
+ }, {
+ Name: "SHA224",
+ Const: "\"SHA224\"",
+ }, {
+ Name: "SHA256",
+ Const: "\"SHA256\"",
+ }, {
+ Name: "SHA384",
+ Const: "\"SHA384\"",
+ }, {
+ Name: "SHA512",
+ Const: "\"SHA512\"",
+ }, {
+ Name: "SHA512_224",
+ Const: "\"SHA512_224\"",
+ }, {
+ Name: "SHA512_256",
+ Const: "\"SHA512_256\"",
+ }, {
+ Name: "Sign",
+ Params: []internal.Param{
+ {Kind: adt.StringKind},
+ {Kind: adt.BytesKind | adt.StringKind},
+ {Kind: adt.BytesKind | adt.StringKind},
+ },
+ Result: adt.BytesKind | adt.StringKind,
+ Func: func(c *internal.CallCtxt) {
+ hashName, key, data := c.String(0), c.Bytes(1), c.Bytes(2)
+ if c.Do() {
+ c.Ret, c.Err = Sign(hashName, key, data)
+ }
+ },
+ }},
+}
diff --git a/pkg/crypto/hmac/testdata/hmac.txtar b/pkg/crypto/hmac/testdata/hmac.txtar
new file mode 100644
index 0000000..cbfa73b
--- /dev/null
+++ b/pkg/crypto/hmac/testdata/hmac.txtar
@@ -0,0 +1,16 @@
+-- in.cue --
+import "crypto/hmac"
+import "encoding/hex"
+
+t1: hex.Encode(hmac.Sign(hmac.SHA1, hex.Decode("303132333435363738393a3b3c3d3e3f40414243"), "Sample #2"))
+t2: hex.Encode(hmac.Sign(hmac.MD5, "Jefe", "what do ya want for nothing?"))
+t3: hex.Encode(hmac.Sign(hmac.SHA256, hex.Decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), "Hi There"))
+t4: hex.Encode(hmac.Sign(hmac.SHA224, hex.Decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b"), "Sample message for keylen<blocklen"))
+t5: hex.Encode(hmac.Sign(hmac.SHA384, hex.Decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"), "Sample message for keylen<blocklen"))
+-- out/hmac --
+t1: "0922d3405faa3d194f82a45830737d5cc6c75d24"
+t2: "750c783e6ab0b503eaa86e310a5db738"
+t3: "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"
+t4: "e3d249a8cfb67ef8b7a169e9a0a599714a2cecba65999a51beb8fbbe"
+t5: "6eb242bdbb582ca17bebfa481b1e23211464d2b7f8c20b9ff2201637b93646af5ae9ac316e98db45d9cae773675eeed0"
+
diff --git a/pkg/register.go b/pkg/register.go
index b7696b9..69bdb0c 100644
--- a/pkg/register.go
+++ b/pkg/register.go
@@ -15,6 +15,7 @@
package pkg
import (
+ _ "cuelang.org/go/pkg/crypto/hmac"
_ "cuelang.org/go/pkg/crypto/md5"
_ "cuelang.org/go/pkg/crypto/sha1"
_ "cuelang.org/go/pkg/crypto/sha256"