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