Source file src/crypto/hkdf/hkdf.go

     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 string, 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 string, 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  

View as plain text