1
2
3
4
5
6
7
8 package hmac
9
10 import (
11 "crypto/internal/fips140"
12 "crypto/internal/fips140/sha256"
13 "crypto/internal/fips140/sha3"
14 "crypto/internal/fips140/sha512"
15 )
16
17
18
19
20
21
22
23
24
25 type marshalable interface {
26 MarshalBinary() ([]byte, error)
27 UnmarshalBinary([]byte) error
28 }
29
30 type HMAC struct {
31 opad, ipad []byte
32 outer, inner fips140.Hash
33
34
35
36
37 marshaled bool
38
39
40 forHKDF bool
41 keyLen int
42 }
43
44 func (h *HMAC) Sum(in []byte) []byte {
45
46
47
48 if h.keyLen < 112/8 && !h.forHKDF {
49 fips140.RecordNonApproved()
50 }
51 switch h.inner.(type) {
52 case *sha256.Digest, *sha512.Digest, *sha3.Digest:
53 default:
54 fips140.RecordNonApproved()
55 }
56
57 origLen := len(in)
58 in = h.inner.Sum(in)
59
60 if h.marshaled {
61 if err := h.outer.(marshalable).UnmarshalBinary(h.opad); err != nil {
62 panic(err)
63 }
64 } else {
65 h.outer.Reset()
66 h.outer.Write(h.opad)
67 }
68 h.outer.Write(in[origLen:])
69 return h.outer.Sum(in[:origLen])
70 }
71
72 func (h *HMAC) Write(p []byte) (n int, err error) {
73 return h.inner.Write(p)
74 }
75
76 func (h *HMAC) Size() int { return h.outer.Size() }
77 func (h *HMAC) BlockSize() int { return h.inner.BlockSize() }
78
79 func (h *HMAC) Reset() {
80 if h.marshaled {
81 if err := h.inner.(marshalable).UnmarshalBinary(h.ipad); err != nil {
82 panic(err)
83 }
84 return
85 }
86
87 h.inner.Reset()
88 h.inner.Write(h.ipad)
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103 marshalableInner, innerOK := h.inner.(marshalable)
104 if !innerOK {
105 return
106 }
107 marshalableOuter, outerOK := h.outer.(marshalable)
108 if !outerOK {
109 return
110 }
111
112 imarshal, err := marshalableInner.MarshalBinary()
113 if err != nil {
114 return
115 }
116
117 h.outer.Reset()
118 h.outer.Write(h.opad)
119 omarshal, err := marshalableOuter.MarshalBinary()
120 if err != nil {
121 return
122 }
123
124
125 h.ipad = imarshal
126 h.opad = omarshal
127 h.marshaled = true
128 }
129
130
131 func New[H fips140.Hash](h func() H, key []byte) *HMAC {
132 hm := &HMAC{keyLen: len(key)}
133 hm.outer = h()
134 hm.inner = h()
135 unique := true
136 func() {
137 defer func() {
138
139 _ = recover()
140 }()
141 if hm.outer == hm.inner {
142 unique = false
143 }
144 }()
145 if !unique {
146 panic("crypto/hmac: hash generation function does not produce unique values")
147 }
148 blocksize := hm.inner.BlockSize()
149 hm.ipad = make([]byte, blocksize)
150 hm.opad = make([]byte, blocksize)
151 if len(key) > blocksize {
152
153 hm.outer.Write(key)
154 key = hm.outer.Sum(nil)
155 }
156 copy(hm.ipad, key)
157 copy(hm.opad, key)
158 for i := range hm.ipad {
159 hm.ipad[i] ^= 0x36
160 }
161 for i := range hm.opad {
162 hm.opad[i] ^= 0x5c
163 }
164 hm.inner.Write(hm.ipad)
165
166 return hm
167 }
168
169
170 func MarkAsUsedInKDF(h *HMAC) {
171 h.forHKDF = true
172 }
173
View as plain text