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 "fmt" 21 "hash" 22 "io" 23 24 "golang.org/x/crypto/hkdf" 25 "github.com/google/tink/go/subtle" 26) 27 28const ( 29 // We use a somewhat larger minimum key size than usual, because PRFs might be 30 // used by many users, in which case the security can degrade by a factor 31 // depending on the number of users. (Discussed for example in 32 // https://eprint.iacr.org/2012/159) 33 minHKDFKeySizeInBytes = uint32(32) 34) 35 36// HKDFPRF is a type that can be used to compute several HKDFs with the same key material. 37type HKDFPRF struct { 38 h func() hash.Hash 39 key []byte 40 salt []byte 41} 42 43// NewHKDFPRF creates a new HKDFPRF object and initializes it with the correct key material. 44func NewHKDFPRF(hashAlg string, key []byte, salt []byte) (*HKDFPRF, error) { 45 h := &HKDFPRF{} 46 hashFunc := subtle.GetHashFunc(hashAlg) 47 if hashFunc == nil { 48 return nil, fmt.Errorf("hkdf: invalid hash algorithm") 49 } 50 h.h = hashFunc 51 h.key = key 52 h.salt = salt 53 return h, nil 54} 55 56// ValidateHKDFPRFParams validates parameters of HKDF constructor. 57func ValidateHKDFPRFParams(hash string, keySize uint32, salt []byte) error { 58 // validate key size 59 if keySize < minHKDFKeySizeInBytes { 60 return fmt.Errorf("key too short") 61 } 62 if subtle.GetHashFunc(hash) == nil { 63 return fmt.Errorf("invalid hash function") 64 } 65 if hash != "SHA256" && hash != "SHA512" { 66 return fmt.Errorf("Only SHA-256 and SHA-512 currently allowed for HKDF") 67 } 68 return nil 69} 70 71// ComputePRF computes the HKDF for the given key and data, returning outputLength bytes. 72func (h HKDFPRF) ComputePRF(data []byte, outputLength uint32) ([]byte, error) { 73 kdf := hkdf.New(h.h, h.key, h.salt, data) 74 output := make([]byte, outputLength) 75 _, err := io.ReadAtLeast(kdf, output, int(outputLength)) 76 if err != nil { 77 return nil, fmt.Errorf("Error computing HKDF: %v", err) 78 } 79 return output[:outputLength], nil 80} 81