hkdf.mx raw

   1  // Copyright 2024 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 hkdf implements the HMAC-based Extract-and-Expand Key Derivation
   6  // Function (HKDF) as defined in RFC 5869.
   7  //
   8  // HKDF is a cryptographic key derivation function (KDF) with the goal of
   9  // expanding limited input keying material into one or more cryptographically
  10  // strong secret keys.
  11  package hkdf
  12  
  13  import (
  14  	"crypto/internal/fips140/hkdf"
  15  	"crypto/internal/fips140hash"
  16  	"crypto/internal/fips140only"
  17  	"errors"
  18  	"hash"
  19  )
  20  
  21  // Extract generates a pseudorandom key for use with [Expand] from an input
  22  // secret and an optional independent salt.
  23  //
  24  // Only use this function if you need to reuse the extracted key with multiple
  25  // Expand invocations and different context values. Most common scenarios,
  26  // including the generation of multiple keys, should use [Key] instead.
  27  func Extract[H hash.Hash](h func() H, secret, salt []byte) ([]byte, error) {
  28  	fh := fips140hash.UnwrapNew(h)
  29  	if err := checkFIPS140Only(fh, secret); err != nil {
  30  		return nil, err
  31  	}
  32  	return hkdf.Extract(fh, secret, salt), nil
  33  }
  34  
  35  // Expand derives a key from the given hash, key, and optional context info,
  36  // returning a []byte of length keyLength that can be used as cryptographic key.
  37  // The extraction step is skipped.
  38  //
  39  // The key should have been generated by [Extract], or be a uniformly
  40  // random or pseudorandom cryptographically strong key. See RFC 5869, Section
  41  // 3.3. Most common scenarios will want to use [Key] instead.
  42  func Expand[H hash.Hash](h func() H, pseudorandomKey []byte, info []byte, keyLength int) ([]byte, error) {
  43  	fh := fips140hash.UnwrapNew(h)
  44  	if err := checkFIPS140Only(fh, pseudorandomKey); err != nil {
  45  		return nil, err
  46  	}
  47  
  48  	limit := fh().Size() * 255
  49  	if keyLength > limit {
  50  		return nil, errors.New("hkdf: requested key length too large")
  51  	}
  52  
  53  	return hkdf.Expand(fh, pseudorandomKey, info, keyLength), nil
  54  }
  55  
  56  // Key derives a key from the given hash, secret, salt and context info,
  57  // returning a []byte of length keyLength that can be used as cryptographic key.
  58  // Salt and info can be nil.
  59  func Key[Hash hash.Hash](h func() Hash, secret, salt []byte, info []byte, keyLength int) ([]byte, error) {
  60  	fh := fips140hash.UnwrapNew(h)
  61  	if err := checkFIPS140Only(fh, secret); err != nil {
  62  		return nil, err
  63  	}
  64  
  65  	limit := fh().Size() * 255
  66  	if keyLength > limit {
  67  		return nil, errors.New("hkdf: requested key length too large")
  68  	}
  69  
  70  	return hkdf.Key(fh, secret, salt, info, keyLength), nil
  71  }
  72  
  73  func checkFIPS140Only[Hash hash.Hash](h func() Hash, key []byte) error {
  74  	if !fips140only.Enabled {
  75  		return nil
  76  	}
  77  	if len(key) < 112/8 {
  78  		return errors.New("crypto/hkdf: use of keys shorter than 112 bits is not allowed in FIPS 140-only mode")
  79  	}
  80  	if !fips140only.ApprovedHash(h()) {
  81  		return errors.New("crypto/hkdf: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
  82  	}
  83  	return nil
  84  }
  85