xref: /aosp_15_r20/external/tink/go/keyderivation/prf_based_deriver.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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