• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/core/primitiveset"
24	"github.com/google/tink/go/insecurecleartextkeyset"
25	"github.com/google/tink/go/keyset"
26	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
27)
28
29var errNotKeysetDeriverPrimitive = errors.New("keyset_deriver_factory: not a Keyset Deriver primitive")
30
31// New generates a new instance of the Keyset Deriver primitive.
32func New(handle *keyset.Handle) (KeysetDeriver, error) {
33	if handle == nil {
34		return nil, errors.New("keyset_deriver_factory: keyset handle can't be nil")
35	}
36	ps, err := handle.PrimitivesWithKeyManager(nil)
37	if err != nil {
38		return nil, fmt.Errorf("keyset_deriver_factory: cannot obtain primitive set: %v", err)
39	}
40	return newWrappedKeysetDeriver(ps)
41}
42
43// wrappedKeysetDeriver is a Keyset Deriver implementation that uses the underlying primitive set to derive keysets.
44type wrappedKeysetDeriver struct {
45	ps *primitiveset.PrimitiveSet
46}
47
48// Asserts that wrappedKeysetDeriver implements the KeysetDeriver interface.
49var _ KeysetDeriver = (*wrappedKeysetDeriver)(nil)
50
51func newWrappedKeysetDeriver(ps *primitiveset.PrimitiveSet) (*wrappedKeysetDeriver, error) {
52	if _, ok := (ps.Primary.Primitive).(KeysetDeriver); !ok {
53		return nil, errNotKeysetDeriverPrimitive
54	}
55	for _, p := range ps.EntriesInKeysetOrder {
56		if _, ok := (p.Primitive).(KeysetDeriver); !ok {
57			return nil, errNotKeysetDeriverPrimitive
58		}
59	}
60	return &wrappedKeysetDeriver{ps: ps}, nil
61}
62
63func (w *wrappedKeysetDeriver) DeriveKeyset(salt []byte) (*keyset.Handle, error) {
64	keys := make([]*tinkpb.Keyset_Key, 0, len(w.ps.EntriesInKeysetOrder))
65	for _, e := range w.ps.EntriesInKeysetOrder {
66		p, ok := (e.Primitive).(KeysetDeriver)
67		if !ok {
68			return nil, errNotKeysetDeriverPrimitive
69		}
70		handle, err := p.DeriveKeyset(salt)
71		if err != nil {
72			return nil, errors.New("keyset_deriver_factory: keyset derivation failed")
73		}
74		if len(handle.KeysetInfo().GetKeyInfo()) != 1 {
75			return nil, errors.New("keyset_deriver_factory: primitive must derive keyset handle with exactly one key")
76		}
77		ks := insecurecleartextkeyset.KeysetMaterial(handle)
78		if len(ks.GetKey()) != 1 {
79			return nil, errors.New("keyset_deriver_factory: primitive must derive keyset handle with exactly one key")
80		}
81		// Set all fields, except for KeyData, to match the Entry's in the keyset.
82		key := &tinkpb.Keyset_Key{
83			KeyData:          ks.GetKey()[0].GetKeyData(),
84			Status:           e.Status,
85			KeyId:            e.KeyID,
86			OutputPrefixType: e.PrefixType,
87		}
88		keys = append(keys, key)
89	}
90	ks := &tinkpb.Keyset{
91		PrimaryKeyId: w.ps.Primary.KeyID,
92		Key:          keys,
93	}
94	return keysetHandle(ks)
95}
96