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

View as plain text