| // Copyright 2024 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Package hkdf implements the HMAC-based Extract-and-Expand Key Derivation |
| // Function (HKDF) as defined in RFC 5869. |
| // |
| // HKDF is a cryptographic key derivation function (KDF) with the goal of |
| // expanding limited input keying material into one or more cryptographically |
| // strong secret keys. |
| package hkdf |
| |
| import ( |
| "crypto/internal/fips140/hkdf" |
| "crypto/internal/fips140hash" |
| "crypto/internal/fips140only" |
| "errors" |
| "hash" |
| ) |
| |
| // Extract generates a pseudorandom key for use with [Expand] from an input |
| // secret and an optional independent salt. |
| // |
| // Only use this function if you need to reuse the extracted key with multiple |
| // Expand invocations and different context values. Most common scenarios, |
| // including the generation of multiple keys, should use [Key] instead. |
| func Extract[H hash.Hash](h func() H, secret, salt []byte) ([]byte, error) { |
| fh := fips140hash.UnwrapNew(h) |
| if err := checkFIPS140Only(fh, secret); err != nil { |
| return nil, err |
| } |
| return hkdf.Extract(fh, secret, salt), nil |
| } |
| |
| // Expand derives a key from the given hash, key, and optional context info, |
| // returning a []byte of length keyLength that can be used as cryptographic key. |
| // The extraction step is skipped. |
| // |
| // The key should have been generated by [Extract], or be a uniformly |
| // random or pseudorandom cryptographically strong key. See RFC 5869, Section |
| // 3.3. Most common scenarios will want to use [Key] instead. |
| func Expand[H hash.Hash](h func() H, pseudorandomKey []byte, info string, keyLength int) ([]byte, error) { |
| fh := fips140hash.UnwrapNew(h) |
| if err := checkFIPS140Only(fh, pseudorandomKey); err != nil { |
| return nil, err |
| } |
| |
| limit := fh().Size() * 255 |
| if keyLength > limit { |
| return nil, errors.New("hkdf: requested key length too large") |
| } |
| |
| return hkdf.Expand(fh, pseudorandomKey, info, keyLength), nil |
| } |
| |
| // Key derives a key from the given hash, secret, salt and context info, |
| // returning a []byte of length keyLength that can be used as cryptographic key. |
| // Salt and info can be nil. |
| func Key[Hash hash.Hash](h func() Hash, secret, salt []byte, info string, keyLength int) ([]byte, error) { |
| fh := fips140hash.UnwrapNew(h) |
| if err := checkFIPS140Only(fh, secret); err != nil { |
| return nil, err |
| } |
| |
| limit := fh().Size() * 255 |
| if keyLength > limit { |
| return nil, errors.New("hkdf: requested key length too large") |
| } |
| |
| return hkdf.Key(fh, secret, salt, info, keyLength), nil |
| } |
| |
| func checkFIPS140Only[Hash hash.Hash](h func() Hash, key []byte) error { |
| if !fips140only.Enforced() { |
| return nil |
| } |
| if len(key) < 112/8 { |
| return errors.New("crypto/hkdf: use of keys shorter than 112 bits is not allowed in FIPS 140-only mode") |
| } |
| if !fips140only.ApprovedHash(h()) { |
| return errors.New("crypto/hkdf: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode") |
| } |
| return nil |
| } |