...

Source file src/crypto/hmac/hmac.go

Documentation: crypto/hmac

		 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  

View as plain text