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