ref: 7eeebe1e5a86a4ad622bc41f88fcb93b619f5a16
parent: 740fa4a91d01fa1c0b151bae0c97a13eea61f5f9
author: Edouard <m@edouard.paris>
date: Fri Jun 5 16:04:11 EDT 2020
tpl/crypto: Add hmac
--- /dev/null
+++ b/docs/content/en/functions/hmac.md
@@ -1,0 +1,34 @@
+---
+title: hmac
+linktitle: hmac
+description: Compute the cryptographic checksum of a message.
+godocref:
+date: 2020-05-29
+publishdate: 2020-05-29
+lastmod: 2020-05-29
+categories: [functions]
+menu:
+ docs:
+ parent: "functions"
+keywords: [hmac,checksum]
+signature: ["hmac HASH_TYPE KEY MESSAGE"]
+workson: []
+hugoversion:
+relatedfuncs: [hmac]
+deprecated: false
+aliases: [hmac]
+---
+
+`hmac` returns a cryptographic hash that uses a key to sign a message.
+
+```
+{{ hmac "sha256" "Secret key" "Hello world, gophers!"}},
+<!-- returns the string "b6d11b6c53830b9d87036272ca9fe9d19306b8f9d8aa07b15da27d89e6e34f40"
+```
+
+Supported hash functions:
+
+* md5
+* sha1
+* sha256
+* sha512
--- a/docs/data/docs.json
+++ b/docs/data/docs.json
@@ -3059,6 +3059,23 @@
"6ec43b78da9669f50e4e422575c54bf87536954ccd58280219c393f2ce352b46"
]
]
+ },
+ "HMAC": {
+ "Description": "HMAC hashes the concatenation of a message and a secret key with the given hash function and returns its checksum.",
+ "Args": [
+ "hash function",
+ "message",
+ "key"
+ ],
+ "Aliases": [
+ "hmac"
+ ],
+ "Examples": [
+ [
+ "{{ hmac \"sha256\" \"Hello Gopher!\" \"Hello world, gophers!\" }}",
+ "32aea97d5688891fb35175c5518012323a3079994b909dd6f1bc481e4d0e7ce9"
+ ]
+ ]
}
},
"data": {
--- a/tpl/crypto/crypto.go
+++ b/tpl/crypto/crypto.go
@@ -15,10 +15,14 @@
package crypto
import (
+ "crypto/hmac"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
+ "crypto/sha512"
"encoding/hex"
+ "fmt"
+ "hash"
"github.com/spf13/cast"
)
@@ -62,4 +66,44 @@
hash := sha256.Sum256([]byte(conv))
return hex.EncodeToString(hash[:]), nil
+}
+
+// HMAC returns a cryptographic hash that uses a key to sign a message.
+func (ns *Namespace) HMAC(h interface{}, k interface{}, m interface{}) (string, error) {
+ ha, err := cast.ToStringE(h)
+ if err != nil {
+ return "", err
+ }
+
+ var hash func() hash.Hash
+ switch ha {
+ case "md5":
+ hash = md5.New
+ case "sha1":
+ hash = sha1.New
+ case "sha256":
+ hash = sha256.New
+ case "sha512":
+ hash = sha512.New
+ default:
+ return "", fmt.Errorf("hmac: %s is not a supported hash function", ha)
+ }
+
+ msg, err := cast.ToStringE(m)
+ if err != nil {
+ return "", err
+ }
+
+ key, err := cast.ToStringE(k)
+ if err != nil {
+ return "", err
+ }
+
+ mac := hmac.New(hash, []byte(key))
+ _, err = mac.Write([]byte(msg))
+ if err != nil {
+ return "", err
+ }
+
+ return hex.EncodeToString(mac.Sum(nil)[:]), nil
}
--- a/tpl/crypto/crypto_test.go
+++ b/tpl/crypto/crypto_test.go
@@ -100,3 +100,34 @@
c.Assert(result, qt.Equals, test.expect, errMsg)
}
}
+
+func TestHMAC(t *testing.T) {
+ t.Parallel()
+ c := qt.New(t)
+ ns := New()
+
+ for i, test := range []struct {
+ hash interface{}
+ key interface{}
+ msg interface{}
+ expect interface{}
+ }{
+ {"md5", "Secret key", "Hello world, gophers!", "36eb69b6bf2de96b6856fdee8bf89754"},
+ {"sha1", "Secret key", "Hello world, gophers!", "84a76647de6cd47ac6ae4258e3753f711172ce68"},
+ {"sha256", "Secret key", "Hello world, gophers!", "b6d11b6c53830b9d87036272ca9fe9d19306b8f9d8aa07b15da27d89e6e34f40"},
+ {"sha512", "Secret key", "Hello world, gophers!", "dc3e586cd936865e2abc4c12665e9cc568b2dad714df3c9037cbea159d036cfc4209da9e3fcd30887ff441056941966899f6fb7eec9646ff9ddb592595a8eb7f"},
+ {"", t, "", false},
+ } {
+ errMsg := qt.Commentf("[%d] %v, %v, %v", i, test.hash, test.key, test.msg)
+
+ result, err := ns.HMAC(test.hash, test.key, test.msg)
+
+ if b, ok := test.expect.(bool); ok && !b {
+ c.Assert(err, qt.Not(qt.IsNil), errMsg)
+ continue
+ }
+
+ c.Assert(err, qt.IsNil, errMsg)
+ c.Assert(result, qt.Equals, test.expect, errMsg)
+ }
+}
--- a/tpl/crypto/init.go
+++ b/tpl/crypto/init.go
@@ -51,6 +51,13 @@
},
)
+ ns.AddMethodMapping(ctx.HMAC,
+ []string{"hmac"},
+ [][2]string{
+ {`{{ hmac "sha256" "Secret key" "Hello world, gophers!" }}`, `b6d11b6c53830b9d87036272ca9fe9d19306b8f9d8aa07b15da27d89e6e34f40`},
+ },
+ )
+
return ns
}