hmac.mx raw

   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  // Package hmac implements HMAC according to [FIPS 198-1].
   6  //
   7  // [FIPS 198-1]: https://doi.org/10.6028/NIST.FIPS.198-1
   8  package hmac
   9  
  10  import (
  11  	"crypto/internal/fips140"
  12  	"crypto/internal/fips140/sha256"
  13  	"crypto/internal/fips140/sha3"
  14  	"crypto/internal/fips140/sha512"
  15  	"errors"
  16  	"hash"
  17  )
  18  
  19  // key is zero padded to the block size of the hash function
  20  // ipad = 0x36 byte repeated for key length
  21  // opad = 0x5c byte repeated for key length
  22  // hmac = H([key ^ opad] H([key ^ ipad] text))
  23  
  24  // marshalable is the combination of encoding.BinaryMarshaler and
  25  // encoding.BinaryUnmarshaler. Their method definitions are repeated here to
  26  // avoid a dependency on the encoding package.
  27  type marshalable interface {
  28  	MarshalBinary() ([]byte, error)
  29  	UnmarshalBinary([]byte) error
  30  }
  31  
  32  type HMAC struct {
  33  	// opad and ipad may share underlying storage with HMAC clones.
  34  	opad, ipad   []byte
  35  	outer, inner hash.Hash
  36  
  37  	// If marshaled is true, then opad and ipad do not contain a padded
  38  	// copy of the key, but rather the marshaled state of outer/inner after
  39  	// opad/ipad has been fed into it.
  40  	marshaled bool
  41  
  42  	// forHKDF and keyLen are stored to inform the service indicator decision.
  43  	forHKDF bool
  44  	keyLen  int
  45  }
  46  
  47  func (h *HMAC) Sum(in []byte) []byte {
  48  	// Per FIPS 140-3 IG C.M, key lengths below 112 bits are only allowed for
  49  	// legacy use (i.e. verification only) and we don't support that. However,
  50  	// HKDF uses the HMAC key for the salt, which is allowed to be shorter.
  51  	if h.keyLen < 112/8 && !h.forHKDF {
  52  		fips140.RecordNonApproved()
  53  	}
  54  	switch h.inner.(type) {
  55  	case *sha256.Digest, *sha512.Digest, *sha3.Digest:
  56  	default:
  57  		fips140.RecordNonApproved()
  58  	}
  59  
  60  	origLen := len(in)
  61  	in = h.inner.Sum(in)
  62  
  63  	if h.marshaled {
  64  		if err := h.outer.(marshalable).UnmarshalBinary(h.opad); err != nil {
  65  			panic(err)
  66  		}
  67  	} else {
  68  		h.outer.Reset()
  69  		h.outer.Write(h.opad)
  70  	}
  71  	h.outer.Write(in[origLen:])
  72  	return h.outer.Sum(in[:origLen])
  73  }
  74  
  75  func (h *HMAC) Write(p []byte) (n int, err error) {
  76  	return h.inner.Write(p)
  77  }
  78  
  79  func (h *HMAC) Size() int      { return h.outer.Size() }
  80  func (h *HMAC) BlockSize() int { return h.inner.BlockSize() }
  81  
  82  func (h *HMAC) Reset() {
  83  	if h.marshaled {
  84  		if err := h.inner.(marshalable).UnmarshalBinary(h.ipad); err != nil {
  85  			panic(err)
  86  		}
  87  		return
  88  	}
  89  
  90  	h.inner.Reset()
  91  	h.inner.Write(h.ipad)
  92  
  93  	// If the underlying hash is marshalable, we can save some time by saving a
  94  	// copy of the hash state now, and restoring it on future calls to Reset and
  95  	// Sum instead of writing ipad/opad every time.
  96  	//
  97  	// We do this on Reset to avoid slowing down the common single-use case.
  98  	//
  99  	// This is allowed by FIPS 198-1, Section 6: "Conceptually, the intermediate
 100  	// results of the compression function on the B-byte blocks (K0 ⊕ ipad) and
 101  	// (K0 ⊕ opad) can be precomputed once, at the time of generation of the key
 102  	// K, or before its first use. These intermediate results can be stored and
 103  	// then used to initialize H each time that a message needs to be
 104  	// authenticated using the same key. [...] These stored intermediate values
 105  	// shall be treated and protected in the same manner as secret keys."
 106  	marshalableInner, innerOK := h.inner.(marshalable)
 107  	if !innerOK {
 108  		return
 109  	}
 110  	marshalableOuter, outerOK := h.outer.(marshalable)
 111  	if !outerOK {
 112  		return
 113  	}
 114  
 115  	imarshal, err := marshalableInner.MarshalBinary()
 116  	if err != nil {
 117  		return
 118  	}
 119  
 120  	h.outer.Reset()
 121  	h.outer.Write(h.opad)
 122  	omarshal, err := marshalableOuter.MarshalBinary()
 123  	if err != nil {
 124  		return
 125  	}
 126  
 127  	// Marshaling succeeded; save the marshaled state for later
 128  	h.ipad = imarshal
 129  	h.opad = omarshal
 130  	h.marshaled = true
 131  }
 132  
 133  type errCloneUnsupported struct{}
 134  
 135  func (e errCloneUnsupported) Error() string {
 136  	return "crypto/hmac: hash does not support hash.Cloner"
 137  }
 138  
 139  func (e errCloneUnsupported) Unwrap() error {
 140  	return errors.ErrUnsupported
 141  }
 142  
 143  // Clone implements [hash.Cloner] if the underlying hash does.
 144  // Otherwise, it returns an error wrapping [errors.ErrUnsupported].
 145  func (h *HMAC) Clone() (hash.Cloner, error) {
 146  	r := *h
 147  	ic, ok := h.inner.(hash.Cloner)
 148  	if !ok {
 149  		return nil, errCloneUnsupported{}
 150  	}
 151  	oc, ok := h.outer.(hash.Cloner)
 152  	if !ok {
 153  		return nil, errCloneUnsupported{}
 154  	}
 155  	var err error
 156  	r.inner, err = ic.Clone()
 157  	if err != nil {
 158  		return nil, errCloneUnsupported{}
 159  	}
 160  	r.outer, err = oc.Clone()
 161  	if err != nil {
 162  		return nil, errCloneUnsupported{}
 163  	}
 164  	return &r, nil
 165  }
 166  
 167  // New returns a new HMAC hash using the given [hash.Hash] type and key.
 168  func New[H hash.Hash](h func() H, key []byte) *HMAC {
 169  	hm := &HMAC{keyLen: len(key)}
 170  	hm.outer = h()
 171  	hm.inner = h()
 172  	unique := true
 173  	func() {
 174  		defer func() {
 175  			// The comparison might panic if the underlying types are not comparable.
 176  			_ = recover()
 177  		}()
 178  		if hm.outer == hm.inner {
 179  			unique = false
 180  		}
 181  	}()
 182  	if !unique {
 183  		panic("crypto/hmac: hash generation function does not produce unique values")
 184  	}
 185  	blocksize := hm.inner.BlockSize()
 186  	hm.ipad = []byte{:blocksize}
 187  	hm.opad = []byte{:blocksize}
 188  	if len(key) > blocksize {
 189  		// If key is too big, hash it.
 190  		hm.outer.Write(key)
 191  		key = hm.outer.Sum(nil)
 192  	}
 193  	copy(hm.ipad, key)
 194  	copy(hm.opad, key)
 195  	for i := range hm.ipad {
 196  		hm.ipad[i] ^= 0x36
 197  	}
 198  	for i := range hm.opad {
 199  		hm.opad[i] ^= 0x5c
 200  	}
 201  	hm.inner.Write(hm.ipad)
 202  
 203  	return hm
 204  }
 205  
 206  // MarkAsUsedInKDF records that this HMAC instance is used as part of a KDF.
 207  func MarkAsUsedInKDF(h *HMAC) {
 208  	h.forHKDF = true
 209  }
 210