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