1// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5/*
6Package hmac implements the Keyed-Hash Message Authentication Code (HMAC) as
7defined in U.S. Federal Information Processing Standards Publication 198.
8An HMAC is a cryptographic hash that uses a key to sign a message.
9The receiver verifies the hash by recomputing it using the same key.
10
11Receivers should be careful to use Equal to compare MACs in order to avoid
12timing side-channels:
13
14	// ValidMAC reports whether messageMAC is a valid HMAC tag for message.
15	func ValidMAC(message, messageMAC, key []byte) bool {
16		mac := hmac.New(sha256.New, key)
17		mac.Write(message)
18		expectedMAC := mac.Sum(nil)
19		return hmac.Equal(messageMAC, expectedMAC)
20	}
21*/
22package hmac
23
24import (
25	"crypto/subtle"
26	"hash"
27)
28
29// FIPS 198-1:
30// https://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf
31
32// key is zero padded to the block size of the hash function
33// ipad = 0x36 byte repeated for key length
34// opad = 0x5c byte repeated for key length
35// hmac = H([key ^ opad] H([key ^ ipad] text))
36
37// Marshalable is the combination of encoding.BinaryMarshaler and
38// encoding.BinaryUnmarshaler. Their method definitions are repeated here to
39// avoid a dependency on the encoding package.
40type marshalable interface {
41	MarshalBinary() ([]byte, error)
42	UnmarshalBinary([]byte) error
43}
44
45type hmac struct {
46	opad, ipad   []byte
47	outer, inner hash.Hash
48
49	// If marshaled is true, then opad and ipad do not contain a padded
50	// copy of the key, but rather the marshaled state of outer/inner after
51	// opad/ipad has been fed into it.
52	marshaled bool
53}
54
55func (h *hmac) Sum(in []byte) []byte {
56	origLen := len(in)
57	in = h.inner.Sum(in)
58
59	if h.marshaled {
60		if err := h.outer.(marshalable).UnmarshalBinary(h.opad); err != nil {
61			panic(err)
62		}
63	} else {
64		h.outer.Reset()
65		h.outer.Write(h.opad)
66	}
67	h.outer.Write(in[origLen:])
68	return h.outer.Sum(in[:origLen])
69}
70
71func (h *hmac) Write(p []byte) (n int, err error) {
72	return h.inner.Write(p)
73}
74
75func (h *hmac) Size() int      { return h.outer.Size() }
76func (h *hmac) BlockSize() int { return h.inner.BlockSize() }
77
78func (h *hmac) Reset() {
79	if h.marshaled {
80		if err := h.inner.(marshalable).UnmarshalBinary(h.ipad); err != nil {
81			panic(err)
82		}
83		return
84	}
85
86	h.inner.Reset()
87	h.inner.Write(h.ipad)
88
89	// If the underlying hash is marshalable, we can save some time by
90	// saving a copy of the hash state now, and restoring it on future
91	// calls to Reset and Sum instead of writing ipad/opad every time.
92	//
93	// If either hash is unmarshalable for whatever reason,
94	// it's safe to bail out here.
95	marshalableInner, innerOK := h.inner.(marshalable)
96	if !innerOK {
97		return
98	}
99	marshalableOuter, outerOK := h.outer.(marshalable)
100	if !outerOK {
101		return
102	}
103
104	imarshal, err := marshalableInner.MarshalBinary()
105	if err != nil {
106		return
107	}
108
109	h.outer.Reset()
110	h.outer.Write(h.opad)
111	omarshal, err := marshalableOuter.MarshalBinary()
112	if err != nil {
113		return
114	}
115
116	// Marshaling succeeded; save the marshaled state for later
117	h.ipad = imarshal
118	h.opad = omarshal
119	h.marshaled = true
120}
121
122// New returns a new HMAC hash using the given hash.Hash type and key.
123// New functions like sha256.New from crypto/sha256 can be used as h.
124// h must return a new Hash every time it is called.
125// Note that unlike other hash implementations in the standard library,
126// the returned Hash does not implement encoding.BinaryMarshaler
127// or encoding.BinaryUnmarshaler.
128func New(h func() hash.Hash, key []byte) hash.Hash {
129	hm := new(hmac)
130	hm.outer = h()
131	hm.inner = h()
132	unique := true
133	func() {
134		defer func() {
135			// The comparison might panic if the underlying types are not comparable.
136			_ = recover()
137		}()
138		if hm.outer == hm.inner {
139			unique = false
140		}
141	}()
142	if !unique {
143		panic("crypto/hmac: hash generation function does not produce unique values")
144	}
145	blocksize := hm.inner.BlockSize()
146	hm.ipad = make([]byte, blocksize)
147	hm.opad = make([]byte, blocksize)
148	if len(key) > blocksize {
149		// If key is too big, hash it.
150		hm.outer.Write(key)
151		key = hm.outer.Sum(nil)
152	}
153	copy(hm.ipad, key)
154	copy(hm.opad, key)
155	for i := range hm.ipad {
156		hm.ipad[i] ^= 0x36
157	}
158	for i := range hm.opad {
159		hm.opad[i] ^= 0x5c
160	}
161	hm.inner.Write(hm.ipad)
162
163	return hm
164}
165
166// Equal compares two MACs for equality without leaking timing information.
167func Equal(mac1, mac2 []byte) bool {
168	// We don't have to be constant time if the lengths of the MACs are
169	// different as that suggests that a completely different hash function
170	// was used.
171	return subtle.ConstantTimeCompare(mac1, mac2) == 1
172}
173