shithub: hugo

Download patch

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
 
 	}