Source file src/crypto/hmac/hmac.go
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 /* 6 Package hmac implements the Keyed-Hash Message Authentication Code (HMAC) as 7 defined in U.S. Federal Information Processing Standards Publication 198. 8 An HMAC is a cryptographic hash that uses a key to sign a message. 9 The receiver verifies the hash by recomputing it using the same key. 10 11 Receivers should be careful to use Equal to compare MACs in order to avoid 12 timing 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 */ 22 package hmac 23 24 import ( 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. 40 type marshalable interface { 41 MarshalBinary() ([]byte, error) 42 UnmarshalBinary([]byte) error 43 } 44 45 type 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 55 func (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 71 func (h *hmac) Write(p []byte) (n int, err error) { 72 return h.inner.Write(p) 73 } 74 75 func (h *hmac) Size() int { return h.outer.Size() } 76 func (h *hmac) BlockSize() int { return h.inner.BlockSize() } 77 78 func (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. 128 func 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. 167 func 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