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/internal/boring" 26 "crypto/subtle" 27 "hash" 28) 29 30// FIPS 198-1: 31// https://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf 32 33// key is zero padded to the block size of the hash function 34// ipad = 0x36 byte repeated for key length 35// opad = 0x5c byte repeated for key length 36// hmac = H([key ^ opad] H([key ^ ipad] text)) 37 38// marshalable is the combination of encoding.BinaryMarshaler and 39// encoding.BinaryUnmarshaler. Their method definitions are repeated here to 40// avoid a dependency on the encoding package. 41type marshalable interface { 42 MarshalBinary() ([]byte, error) 43 UnmarshalBinary([]byte) error 44} 45 46type hmac struct { 47 opad, ipad []byte 48 outer, inner hash.Hash 49 50 // If marshaled is true, then opad and ipad do not contain a padded 51 // copy of the key, but rather the marshaled state of outer/inner after 52 // opad/ipad has been fed into it. 53 marshaled bool 54} 55 56func (h *hmac) Sum(in []byte) []byte { 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 72func (h *hmac) Write(p []byte) (n int, err error) { 73 return h.inner.Write(p) 74} 75 76func (h *hmac) Size() int { return h.outer.Size() } 77func (h *hmac) BlockSize() int { return h.inner.BlockSize() } 78 79func (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 // If the underlying hash is marshalable, we can save some time by 91 // saving a copy of the hash state now, and restoring it on future 92 // calls to Reset and Sum instead of writing ipad/opad every time. 93 // 94 // If either hash is unmarshalable for whatever reason, 95 // it's safe to bail out here. 96 marshalableInner, innerOK := h.inner.(marshalable) 97 if !innerOK { 98 return 99 } 100 marshalableOuter, outerOK := h.outer.(marshalable) 101 if !outerOK { 102 return 103 } 104 105 imarshal, err := marshalableInner.MarshalBinary() 106 if err != nil { 107 return 108 } 109 110 h.outer.Reset() 111 h.outer.Write(h.opad) 112 omarshal, err := marshalableOuter.MarshalBinary() 113 if err != nil { 114 return 115 } 116 117 // Marshaling succeeded; save the marshaled state for later 118 h.ipad = imarshal 119 h.opad = omarshal 120 h.marshaled = true 121} 122 123// New returns a new HMAC hash using the given [hash.Hash] type and key. 124// New functions like sha256.New from [crypto/sha256] can be used as h. 125// h must return a new Hash every time it is called. 126// Note that unlike other hash implementations in the standard library, 127// the returned Hash does not implement [encoding.BinaryMarshaler] 128// or [encoding.BinaryUnmarshaler]. 129func New(h func() hash.Hash, key []byte) hash.Hash { 130 if boring.Enabled { 131 hm := boring.NewHMAC(h, key) 132 if hm != nil { 133 return hm 134 } 135 // BoringCrypto did not recognize h, so fall through to standard Go code. 136 } 137 hm := new(hmac) 138 hm.outer = h() 139 hm.inner = h() 140 unique := true 141 func() { 142 defer func() { 143 // The comparison might panic if the underlying types are not comparable. 144 _ = recover() 145 }() 146 if hm.outer == hm.inner { 147 unique = false 148 } 149 }() 150 if !unique { 151 panic("crypto/hmac: hash generation function does not produce unique values") 152 } 153 blocksize := hm.inner.BlockSize() 154 hm.ipad = make([]byte, blocksize) 155 hm.opad = make([]byte, blocksize) 156 if len(key) > blocksize { 157 // If key is too big, hash it. 158 hm.outer.Write(key) 159 key = hm.outer.Sum(nil) 160 } 161 copy(hm.ipad, key) 162 copy(hm.opad, key) 163 for i := range hm.ipad { 164 hm.ipad[i] ^= 0x36 165 } 166 for i := range hm.opad { 167 hm.opad[i] ^= 0x5c 168 } 169 hm.inner.Write(hm.ipad) 170 171 return hm 172} 173 174// Equal compares two MACs for equality without leaking timing information. 175func Equal(mac1, mac2 []byte) bool { 176 // We don't have to be constant time if the lengths of the MACs are 177 // different as that suggests that a completely different hash function 178 // was used. 179 return subtle.ConstantTimeCompare(mac1, mac2) == 1 180} 181