// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////////// package keyderivation import ( "errors" "fmt" "github.com/google/tink/go/internal/internalregistry" "github.com/google/tink/go/keyderivation/internal/streamingprf" "github.com/google/tink/go/keyset" tinkpb "github.com/google/tink/go/proto/tink_go_proto" ) const hkdfPRFTypeURL = "type.googleapis.com/google.crypto.tink.HkdfPrfKey" // prfBasedDeriver uses prf and the Tink registry to derive a keyset handle as // described by derivedKeyTemplate. type prfBasedDeriver struct { prf streamingprf.StreamingPRF derivedKeyTemplate *tinkpb.KeyTemplate } // Asserts that prfBasedDeriver implements the KeysetDeriver interface. var _ KeysetDeriver = (*prfBasedDeriver)(nil) func newPRFBasedDeriver(prfKeyData *tinkpb.KeyData, derivedKeyTemplate *tinkpb.KeyTemplate) (*prfBasedDeriver, error) { // Obtain Streaming PRF from PRF key data. if prfKeyData == nil { return nil, errors.New("PRF key data is nil") } if prfKeyData.GetTypeUrl() != hkdfPRFTypeURL { return nil, fmt.Errorf("PRF key data with type URL %q is not supported", prfKeyData.GetTypeUrl()) } // For HKDF PRF keys, create a local instance of the HKDF Streaming PRF key // manager and obtain the Streaming PRF interface through it, instead of // obtaining it through the registry. This allows us to keep the HKDF // Streaming PRF key manager out of the registry for smoother deprecation. // // TODO(b/260619626): Remove this once PRF and Streaming PRF share the same // type URL and registry.Primitive() can return multiple interfaces per // primitive. hkdfStreamingPRFKeyManager := streamingprf.HKDFStreamingPRFKeyManager{} p, err := hkdfStreamingPRFKeyManager.Primitive(prfKeyData.GetValue()) if err != nil { return nil, fmt.Errorf("failed to retrieve StreamingPRF primitive from key manager: %v", err) } prf, ok := p.(streamingprf.StreamingPRF) if !ok { return nil, errors.New("primitive is not StreamingPRF") } // Validate derived key template. if !internalregistry.CanDeriveKeys(derivedKeyTemplate.GetTypeUrl()) { return nil, errors.New("derived key template is not a derivable key type") } return &prfBasedDeriver{ prf: prf, derivedKeyTemplate: derivedKeyTemplate, }, nil } func (p *prfBasedDeriver) DeriveKeyset(salt []byte) (*keyset.Handle, error) { randomness, err := p.prf.Compute(salt) if err != nil { return nil, fmt.Errorf("compute randomness from PRF failed: %v", err) } keyData, err := internalregistry.DeriveKey(p.derivedKeyTemplate, randomness) if err != nil { return nil, fmt.Errorf("derive key failed: %v", err) } // Fill in placeholder values for key ID, status, and output prefix type. // These will be populated with the correct values in the keyset deriver // factory. This is acceptable because the keyset as-is will never leave Tink, // and the user only interacts via the keyset deriver factory. var primaryKeyID uint32 = 0 return keysetHandle(&tinkpb.Keyset{ PrimaryKeyId: primaryKeyID, Key: []*tinkpb.Keyset_Key{ &tinkpb.Keyset_Key{ KeyData: keyData, Status: tinkpb.KeyStatusType_UNKNOWN_STATUS, KeyId: primaryKeyID, OutputPrefixType: tinkpb.OutputPrefixType_UNKNOWN_PREFIX, }, }, }) }