1*e7b1675dSTing-Kang Chang// Copyright 2022 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 keyderivation 18*e7b1675dSTing-Kang Chang 19*e7b1675dSTing-Kang Changimport ( 20*e7b1675dSTing-Kang Chang "errors" 21*e7b1675dSTing-Kang Chang "fmt" 22*e7b1675dSTing-Kang Chang 23*e7b1675dSTing-Kang Chang "github.com/google/tink/go/internal/internalregistry" 24*e7b1675dSTing-Kang Chang "github.com/google/tink/go/keyderivation/internal/streamingprf" 25*e7b1675dSTing-Kang Chang "github.com/google/tink/go/keyset" 26*e7b1675dSTing-Kang Chang tinkpb "github.com/google/tink/go/proto/tink_go_proto" 27*e7b1675dSTing-Kang Chang) 28*e7b1675dSTing-Kang Chang 29*e7b1675dSTing-Kang Changconst hkdfPRFTypeURL = "type.googleapis.com/google.crypto.tink.HkdfPrfKey" 30*e7b1675dSTing-Kang Chang 31*e7b1675dSTing-Kang Chang// prfBasedDeriver uses prf and the Tink registry to derive a keyset handle as 32*e7b1675dSTing-Kang Chang// described by derivedKeyTemplate. 33*e7b1675dSTing-Kang Changtype prfBasedDeriver struct { 34*e7b1675dSTing-Kang Chang prf streamingprf.StreamingPRF 35*e7b1675dSTing-Kang Chang derivedKeyTemplate *tinkpb.KeyTemplate 36*e7b1675dSTing-Kang Chang} 37*e7b1675dSTing-Kang Chang 38*e7b1675dSTing-Kang Chang// Asserts that prfBasedDeriver implements the KeysetDeriver interface. 39*e7b1675dSTing-Kang Changvar _ KeysetDeriver = (*prfBasedDeriver)(nil) 40*e7b1675dSTing-Kang Chang 41*e7b1675dSTing-Kang Changfunc newPRFBasedDeriver(prfKeyData *tinkpb.KeyData, derivedKeyTemplate *tinkpb.KeyTemplate) (*prfBasedDeriver, error) { 42*e7b1675dSTing-Kang Chang // Obtain Streaming PRF from PRF key data. 43*e7b1675dSTing-Kang Chang if prfKeyData == nil { 44*e7b1675dSTing-Kang Chang return nil, errors.New("PRF key data is nil") 45*e7b1675dSTing-Kang Chang } 46*e7b1675dSTing-Kang Chang if prfKeyData.GetTypeUrl() != hkdfPRFTypeURL { 47*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("PRF key data with type URL %q is not supported", prfKeyData.GetTypeUrl()) 48*e7b1675dSTing-Kang Chang } 49*e7b1675dSTing-Kang Chang // For HKDF PRF keys, create a local instance of the HKDF Streaming PRF key 50*e7b1675dSTing-Kang Chang // manager and obtain the Streaming PRF interface through it, instead of 51*e7b1675dSTing-Kang Chang // obtaining it through the registry. This allows us to keep the HKDF 52*e7b1675dSTing-Kang Chang // Streaming PRF key manager out of the registry for smoother deprecation. 53*e7b1675dSTing-Kang Chang // 54*e7b1675dSTing-Kang Chang // TODO(b/260619626): Remove this once PRF and Streaming PRF share the same 55*e7b1675dSTing-Kang Chang // type URL and registry.Primitive() can return multiple interfaces per 56*e7b1675dSTing-Kang Chang // primitive. 57*e7b1675dSTing-Kang Chang hkdfStreamingPRFKeyManager := streamingprf.HKDFStreamingPRFKeyManager{} 58*e7b1675dSTing-Kang Chang p, err := hkdfStreamingPRFKeyManager.Primitive(prfKeyData.GetValue()) 59*e7b1675dSTing-Kang Chang if err != nil { 60*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("failed to retrieve StreamingPRF primitive from key manager: %v", err) 61*e7b1675dSTing-Kang Chang } 62*e7b1675dSTing-Kang Chang prf, ok := p.(streamingprf.StreamingPRF) 63*e7b1675dSTing-Kang Chang if !ok { 64*e7b1675dSTing-Kang Chang return nil, errors.New("primitive is not StreamingPRF") 65*e7b1675dSTing-Kang Chang } 66*e7b1675dSTing-Kang Chang 67*e7b1675dSTing-Kang Chang // Validate derived key template. 68*e7b1675dSTing-Kang Chang if !internalregistry.CanDeriveKeys(derivedKeyTemplate.GetTypeUrl()) { 69*e7b1675dSTing-Kang Chang return nil, errors.New("derived key template is not a derivable key type") 70*e7b1675dSTing-Kang Chang } 71*e7b1675dSTing-Kang Chang 72*e7b1675dSTing-Kang Chang return &prfBasedDeriver{ 73*e7b1675dSTing-Kang Chang prf: prf, 74*e7b1675dSTing-Kang Chang derivedKeyTemplate: derivedKeyTemplate, 75*e7b1675dSTing-Kang Chang }, nil 76*e7b1675dSTing-Kang Chang} 77*e7b1675dSTing-Kang Chang 78*e7b1675dSTing-Kang Changfunc (p *prfBasedDeriver) DeriveKeyset(salt []byte) (*keyset.Handle, error) { 79*e7b1675dSTing-Kang Chang randomness, err := p.prf.Compute(salt) 80*e7b1675dSTing-Kang Chang if err != nil { 81*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("compute randomness from PRF failed: %v", err) 82*e7b1675dSTing-Kang Chang } 83*e7b1675dSTing-Kang Chang keyData, err := internalregistry.DeriveKey(p.derivedKeyTemplate, randomness) 84*e7b1675dSTing-Kang Chang if err != nil { 85*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("derive key failed: %v", err) 86*e7b1675dSTing-Kang Chang } 87*e7b1675dSTing-Kang Chang // Fill in placeholder values for key ID, status, and output prefix type. 88*e7b1675dSTing-Kang Chang // These will be populated with the correct values in the keyset deriver 89*e7b1675dSTing-Kang Chang // factory. This is acceptable because the keyset as-is will never leave Tink, 90*e7b1675dSTing-Kang Chang // and the user only interacts via the keyset deriver factory. 91*e7b1675dSTing-Kang Chang var primaryKeyID uint32 = 0 92*e7b1675dSTing-Kang Chang return keysetHandle(&tinkpb.Keyset{ 93*e7b1675dSTing-Kang Chang PrimaryKeyId: primaryKeyID, 94*e7b1675dSTing-Kang Chang Key: []*tinkpb.Keyset_Key{ 95*e7b1675dSTing-Kang Chang &tinkpb.Keyset_Key{ 96*e7b1675dSTing-Kang Chang KeyData: keyData, 97*e7b1675dSTing-Kang Chang Status: tinkpb.KeyStatusType_UNKNOWN_STATUS, 98*e7b1675dSTing-Kang Chang KeyId: primaryKeyID, 99*e7b1675dSTing-Kang Chang OutputPrefixType: tinkpb.OutputPrefixType_UNKNOWN_PREFIX, 100*e7b1675dSTing-Kang Chang }, 101*e7b1675dSTing-Kang Chang }, 102*e7b1675dSTing-Kang Chang }) 103*e7b1675dSTing-Kang Chang} 104