xref: /aosp_15_r20/external/tink/go/subtle/hkdf.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1// Copyright 2020 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15////////////////////////////////////////////////////////////////////////////////
16
17package subtle
18
19import (
20	"errors"
21	"fmt"
22	"io"
23
24	"golang.org/x/crypto/hkdf"
25)
26
27const (
28	// Minimum tag size in bytes. This provides minimum 80-bit security strength.
29	minTagSizeInBytes = uint32(10)
30)
31
32var errHKDFInvalidInput = errors.New("HKDF: invalid input")
33
34// validateHKDFParams validates parameters of HKDF constructor.
35func validateHKDFParams(hash string, keySize uint32, tagSize uint32) error {
36	// validate tag size
37	digestSize, err := GetHashDigestSize(hash)
38	if err != nil {
39		return err
40	}
41	if tagSize > 255*digestSize {
42		return fmt.Errorf("tag size too big")
43	}
44	if tagSize < minTagSizeInBytes {
45		return fmt.Errorf("tag size too small")
46	}
47	return nil
48}
49
50// ComputeHKDF extracts a pseudorandom key.
51func ComputeHKDF(hashAlg string, key []byte, salt []byte, info []byte, tagSize uint32) ([]byte, error) {
52	keySize := uint32(len(key))
53	if err := validateHKDFParams(hashAlg, keySize, tagSize); err != nil {
54		return nil, fmt.Errorf("hkdf: %s", err)
55	}
56	hashFunc := GetHashFunc(hashAlg)
57	if hashFunc == nil {
58		return nil, fmt.Errorf("hkdf: invalid hash algorithm")
59	}
60	if len(salt) == 0 {
61		salt = make([]byte, hashFunc().Size())
62	}
63
64	result := make([]byte, tagSize)
65	kdf := hkdf.New(hashFunc, key, salt, info)
66	n, err := io.ReadFull(kdf, result)
67	if n != len(result) || err != nil {
68		return nil, fmt.Errorf("compute of hkdf failed")
69	}
70	return result, nil
71}
72