Source file src/crypto/internal/fips140/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  // 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 = make([]byte, blocksize)
   187  	hm.opad = make([]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  

View as plain text