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