xref: /aosp_15_r20/external/tink/go/aead/xchacha20poly1305_key_manager.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1// Copyright 2018 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 aead
18
19import (
20	"fmt"
21	"io"
22
23	"golang.org/x/crypto/chacha20poly1305"
24	"google.golang.org/protobuf/proto"
25	"github.com/google/tink/go/aead/subtle"
26	"github.com/google/tink/go/core/registry"
27	"github.com/google/tink/go/keyset"
28	"github.com/google/tink/go/subtle/random"
29
30	tpb "github.com/google/tink/go/proto/tink_go_proto"
31	xpb "github.com/google/tink/go/proto/xchacha20_poly1305_go_proto"
32)
33
34const (
35	xChaCha20Poly1305KeyVersion = 0
36	xChaCha20Poly1305TypeURL    = "type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key"
37)
38
39var (
40	errInvalidXChaCha20Poly1305Key       = fmt.Errorf("xchacha20poly1305_key_manager: invalid key")
41	errInvalidXChaCha20Poly1305KeyFormat = fmt.Errorf("xchacha20poly1305_key_manager: invalid key format")
42)
43
44// xChaCha20Poly1305KeyManager generates XChaCha20Poly1305Key keys and produces
45// instances of XChaCha20Poly1305.
46type xChaCha20Poly1305KeyManager struct{}
47
48// Assert that xChaCha20Poly1305KeyManager implements the KeyManager interface.
49var _ registry.KeyManager = (*xChaCha20Poly1305KeyManager)(nil)
50
51// Primitive constructs a XChaCha20Poly1305 for the given serialized
52// XChaCha20Poly1305Key.
53func (km *xChaCha20Poly1305KeyManager) Primitive(serializedKey []byte) (interface{}, error) {
54	if len(serializedKey) == 0 {
55		return nil, errInvalidXChaCha20Poly1305Key
56	}
57	key := new(xpb.XChaCha20Poly1305Key)
58	if err := proto.Unmarshal(serializedKey, key); err != nil {
59		return nil, errInvalidXChaCha20Poly1305Key
60	}
61	if err := km.validateKey(key); err != nil {
62		return nil, err
63	}
64	ret, err := subtle.NewXChaCha20Poly1305(key.KeyValue)
65	if err != nil {
66		return nil, fmt.Errorf("xchacha20poly1305_key_manager: cannot create new primitive: %v", err)
67	}
68	return ret, nil
69}
70
71// NewKey generates a new XChaCha20Poly1305Key. It ignores serializedKeyFormat
72// because the key size and other params are fixed.
73func (km *xChaCha20Poly1305KeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) {
74	return &xpb.XChaCha20Poly1305Key{
75		Version:  xChaCha20Poly1305KeyVersion,
76		KeyValue: random.GetRandomBytes(chacha20poly1305.KeySize),
77	}, nil
78}
79
80// NewKeyData generates a new KeyData. It ignores serializedKeyFormat because
81// the key size and other params are fixed. This should be used solely by the
82// key management API.
83func (km *xChaCha20Poly1305KeyManager) NewKeyData(serializedKeyFormat []byte) (*tpb.KeyData, error) {
84	key := &xpb.XChaCha20Poly1305Key{
85		Version:  xChaCha20Poly1305KeyVersion,
86		KeyValue: random.GetRandomBytes(chacha20poly1305.KeySize),
87	}
88	serializedKey, err := proto.Marshal(key)
89	if err != nil {
90		return nil, err
91	}
92	return &tpb.KeyData{
93		TypeUrl:         xChaCha20Poly1305TypeURL,
94		Value:           serializedKey,
95		KeyMaterialType: km.KeyMaterialType(),
96	}, nil
97}
98
99// DoesSupport checks whether this key manager supports the given key type.
100func (km *xChaCha20Poly1305KeyManager) DoesSupport(typeURL string) bool {
101	return typeURL == xChaCha20Poly1305TypeURL
102}
103
104// TypeURL returns the type URL of keys managed by this key manager.
105func (km *xChaCha20Poly1305KeyManager) TypeURL() string {
106	return xChaCha20Poly1305TypeURL
107}
108
109// KeyMaterialType returns the key material type of this key manager.
110func (km *xChaCha20Poly1305KeyManager) KeyMaterialType() tpb.KeyData_KeyMaterialType {
111	return tpb.KeyData_SYMMETRIC
112}
113
114// DeriveKey derives a new key from serializedKeyFormat and pseudorandomness.
115// Unlike NewKey, DeriveKey validates serializedKeyFormat's version.
116func (km *xChaCha20Poly1305KeyManager) DeriveKey(serializedKeyFormat []byte, pseudorandomness io.Reader) (proto.Message, error) {
117	keyFormat := new(xpb.XChaCha20Poly1305KeyFormat)
118	if err := proto.Unmarshal(serializedKeyFormat, keyFormat); err != nil {
119		return nil, fmt.Errorf("xchacha20poly1305_key_manager: %v", err)
120	}
121	err := keyset.ValidateKeyVersion(keyFormat.Version, xChaCha20Poly1305KeyVersion)
122	if err != nil {
123		return nil, fmt.Errorf("xchacha20poly1305_key_manager: %v", err)
124	}
125
126	keyValue := make([]byte, chacha20poly1305.KeySize)
127	if _, err := io.ReadFull(pseudorandomness, keyValue); err != nil {
128		return nil, fmt.Errorf("xchacha20poly1305_key_manager: not enough pseudorandomness given")
129	}
130	return &xpb.XChaCha20Poly1305Key{
131		Version:  xChaCha20Poly1305KeyVersion,
132		KeyValue: keyValue,
133	}, nil
134}
135
136// validateKey validates the given XChaCha20Poly1305Key.
137func (km *xChaCha20Poly1305KeyManager) validateKey(key *xpb.XChaCha20Poly1305Key) error {
138	err := keyset.ValidateKeyVersion(key.Version, xChaCha20Poly1305KeyVersion)
139	if err != nil {
140		return fmt.Errorf("xchacha20poly1305_key_manager: %v", err)
141	}
142	keySize := uint32(len(key.KeyValue))
143	if keySize != chacha20poly1305.KeySize {
144		return fmt.Errorf("xchacha20poly1305_key_manager: key size != %d", chacha20poly1305.KeySize)
145	}
146	return nil
147}
148