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