github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/src/crypto/hmac/hmac.go (about)

     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  	// CheckMAC returns true if messageMAC is a valid HMAC tag for message.
    15  	func CheckMAC(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:
    30  // http://csrc.nist.gov/publications/fips/fips198/fips-198a.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  type hmac struct {
    38  	size         int
    39  	blocksize    int
    40  	key, tmp     []byte
    41  	outer, inner hash.Hash
    42  }
    43  
    44  func (h *hmac) tmpPad(xor byte) {
    45  	for i, k := range h.key {
    46  		h.tmp[i] = xor ^ k
    47  	}
    48  	for i := len(h.key); i < h.blocksize; i++ {
    49  		h.tmp[i] = xor
    50  	}
    51  }
    52  
    53  func (h *hmac) Sum(in []byte) []byte {
    54  	origLen := len(in)
    55  	in = h.inner.Sum(in)
    56  	h.tmpPad(0x5c)
    57  	copy(h.tmp[h.blocksize:], in[origLen:])
    58  	h.outer.Reset()
    59  	h.outer.Write(h.tmp)
    60  	return h.outer.Sum(in[:origLen])
    61  }
    62  
    63  func (h *hmac) Write(p []byte) (n int, err error) {
    64  	return h.inner.Write(p)
    65  }
    66  
    67  func (h *hmac) Size() int { return h.size }
    68  
    69  func (h *hmac) BlockSize() int { return h.blocksize }
    70  
    71  func (h *hmac) Reset() {
    72  	h.inner.Reset()
    73  	h.tmpPad(0x36)
    74  	h.inner.Write(h.tmp[:h.blocksize])
    75  }
    76  
    77  // New returns a new HMAC hash using the given hash.Hash type and key.
    78  func New(h func() hash.Hash, key []byte) hash.Hash {
    79  	hm := new(hmac)
    80  	hm.outer = h()
    81  	hm.inner = h()
    82  	hm.size = hm.inner.Size()
    83  	hm.blocksize = hm.inner.BlockSize()
    84  	hm.tmp = make([]byte, hm.blocksize+hm.size)
    85  	if len(key) > hm.blocksize {
    86  		// If key is too big, hash it.
    87  		hm.outer.Write(key)
    88  		key = hm.outer.Sum(nil)
    89  	}
    90  	hm.key = make([]byte, len(key))
    91  	copy(hm.key, key)
    92  	hm.Reset()
    93  	return hm
    94  }
    95  
    96  // Equal compares two MACs for equality without leaking timing information.
    97  func Equal(mac1, mac2 []byte) bool {
    98  	// We don't have to be constant time if the lengths of the MACs are
    99  	// different as that suggests that a completely different hash function
   100  	// was used.
   101  	return len(mac1) == len(mac2) && subtle.ConstantTimeCompare(mac1, mac2) == 1
   102  }