crypto.go (3209B)
1 // Copyright 2017 The Hugo Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 // Package crypto provides template functions for cryptographic operations.
15 package crypto
16
17 import (
18 "crypto/hmac"
19 "crypto/md5"
20 "crypto/sha1"
21 "crypto/sha256"
22 "crypto/sha512"
23 "encoding/hex"
24 "fmt"
25 "hash"
26 "hash/fnv"
27
28 "github.com/spf13/cast"
29 )
30
31 // New returns a new instance of the crypto-namespaced template functions.
32 func New() *Namespace {
33 return &Namespace{}
34 }
35
36 // Namespace provides template functions for the "crypto" namespace.
37 type Namespace struct{}
38
39 // MD5 hashes the given input and returns its MD5 checksum.
40 func (ns *Namespace) MD5(in any) (string, error) {
41 conv, err := cast.ToStringE(in)
42 if err != nil {
43 return "", err
44 }
45
46 hash := md5.Sum([]byte(conv))
47 return hex.EncodeToString(hash[:]), nil
48 }
49
50 // SHA1 hashes the given input and returns its SHA1 checksum.
51 func (ns *Namespace) SHA1(in any) (string, error) {
52 conv, err := cast.ToStringE(in)
53 if err != nil {
54 return "", err
55 }
56
57 hash := sha1.Sum([]byte(conv))
58 return hex.EncodeToString(hash[:]), nil
59 }
60
61 // SHA256 hashes the given input and returns its SHA256 checksum.
62 func (ns *Namespace) SHA256(in any) (string, error) {
63 conv, err := cast.ToStringE(in)
64 if err != nil {
65 return "", err
66 }
67
68 hash := sha256.Sum256([]byte(conv))
69 return hex.EncodeToString(hash[:]), nil
70 }
71
72 // FNV32a hashes using fnv32a algorithm
73 func (ns *Namespace) FNV32a(in any) (int, error) {
74 conv, err := cast.ToStringE(in)
75 if err != nil {
76 return 0, err
77 }
78 algorithm := fnv.New32a()
79 algorithm.Write([]byte(conv))
80 return int(algorithm.Sum32()), nil
81 }
82
83 // HMAC returns a cryptographic hash that uses a key to sign a message.
84 func (ns *Namespace) HMAC(h any, k any, m any, e ...any) (string, error) {
85 ha, err := cast.ToStringE(h)
86 if err != nil {
87 return "", err
88 }
89
90 var hash func() hash.Hash
91 switch ha {
92 case "md5":
93 hash = md5.New
94 case "sha1":
95 hash = sha1.New
96 case "sha256":
97 hash = sha256.New
98 case "sha512":
99 hash = sha512.New
100 default:
101 return "", fmt.Errorf("hmac: %s is not a supported hash function", ha)
102 }
103
104 msg, err := cast.ToStringE(m)
105 if err != nil {
106 return "", err
107 }
108
109 key, err := cast.ToStringE(k)
110 if err != nil {
111 return "", err
112 }
113
114 mac := hmac.New(hash, []byte(key))
115 _, err = mac.Write([]byte(msg))
116 if err != nil {
117 return "", err
118 }
119
120 var encoding = "hex"
121 if len(e) > 0 && e[0] != nil {
122 encoding, err = cast.ToStringE(e[0])
123 if err != nil {
124 return "", err
125 }
126 }
127
128 switch encoding {
129 case "binary":
130 return string(mac.Sum(nil)[:]), nil
131 case "hex":
132 return hex.EncodeToString(mac.Sum(nil)[:]), nil
133 default:
134 return "", fmt.Errorf("%q is not a supported encoding method", encoding)
135 }
136
137 }