xref: /aosp_15_r20/external/tink/go/aead/xchacha20poly1305_key_manager.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1*e7b1675dSTing-Kang Chang// Copyright 2018 Google LLC
2*e7b1675dSTing-Kang Chang//
3*e7b1675dSTing-Kang Chang// Licensed under the Apache License, Version 2.0 (the "License");
4*e7b1675dSTing-Kang Chang// you may not use this file except in compliance with the License.
5*e7b1675dSTing-Kang Chang// You may obtain a copy of the License at
6*e7b1675dSTing-Kang Chang//
7*e7b1675dSTing-Kang Chang//      http://www.apache.org/licenses/LICENSE-2.0
8*e7b1675dSTing-Kang Chang//
9*e7b1675dSTing-Kang Chang// Unless required by applicable law or agreed to in writing, software
10*e7b1675dSTing-Kang Chang// distributed under the License is distributed on an "AS IS" BASIS,
11*e7b1675dSTing-Kang Chang// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e7b1675dSTing-Kang Chang// See the License for the specific language governing permissions and
13*e7b1675dSTing-Kang Chang// limitations under the License.
14*e7b1675dSTing-Kang Chang//
15*e7b1675dSTing-Kang Chang////////////////////////////////////////////////////////////////////////////////
16*e7b1675dSTing-Kang Chang
17*e7b1675dSTing-Kang Changpackage aead
18*e7b1675dSTing-Kang Chang
19*e7b1675dSTing-Kang Changimport (
20*e7b1675dSTing-Kang Chang	"fmt"
21*e7b1675dSTing-Kang Chang	"io"
22*e7b1675dSTing-Kang Chang
23*e7b1675dSTing-Kang Chang	"golang.org/x/crypto/chacha20poly1305"
24*e7b1675dSTing-Kang Chang	"google.golang.org/protobuf/proto"
25*e7b1675dSTing-Kang Chang	"github.com/google/tink/go/aead/subtle"
26*e7b1675dSTing-Kang Chang	"github.com/google/tink/go/core/registry"
27*e7b1675dSTing-Kang Chang	"github.com/google/tink/go/keyset"
28*e7b1675dSTing-Kang Chang	"github.com/google/tink/go/subtle/random"
29*e7b1675dSTing-Kang Chang
30*e7b1675dSTing-Kang Chang	tpb "github.com/google/tink/go/proto/tink_go_proto"
31*e7b1675dSTing-Kang Chang	xpb "github.com/google/tink/go/proto/xchacha20_poly1305_go_proto"
32*e7b1675dSTing-Kang Chang)
33*e7b1675dSTing-Kang Chang
34*e7b1675dSTing-Kang Changconst (
35*e7b1675dSTing-Kang Chang	xChaCha20Poly1305KeyVersion = 0
36*e7b1675dSTing-Kang Chang	xChaCha20Poly1305TypeURL    = "type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key"
37*e7b1675dSTing-Kang Chang)
38*e7b1675dSTing-Kang Chang
39*e7b1675dSTing-Kang Changvar (
40*e7b1675dSTing-Kang Chang	errInvalidXChaCha20Poly1305Key       = fmt.Errorf("xchacha20poly1305_key_manager: invalid key")
41*e7b1675dSTing-Kang Chang	errInvalidXChaCha20Poly1305KeyFormat = fmt.Errorf("xchacha20poly1305_key_manager: invalid key format")
42*e7b1675dSTing-Kang Chang)
43*e7b1675dSTing-Kang Chang
44*e7b1675dSTing-Kang Chang// xChaCha20Poly1305KeyManager generates XChaCha20Poly1305Key keys and produces
45*e7b1675dSTing-Kang Chang// instances of XChaCha20Poly1305.
46*e7b1675dSTing-Kang Changtype xChaCha20Poly1305KeyManager struct{}
47*e7b1675dSTing-Kang Chang
48*e7b1675dSTing-Kang Chang// Assert that xChaCha20Poly1305KeyManager implements the KeyManager interface.
49*e7b1675dSTing-Kang Changvar _ registry.KeyManager = (*xChaCha20Poly1305KeyManager)(nil)
50*e7b1675dSTing-Kang Chang
51*e7b1675dSTing-Kang Chang// Primitive constructs a XChaCha20Poly1305 for the given serialized
52*e7b1675dSTing-Kang Chang// XChaCha20Poly1305Key.
53*e7b1675dSTing-Kang Changfunc (km *xChaCha20Poly1305KeyManager) Primitive(serializedKey []byte) (interface{}, error) {
54*e7b1675dSTing-Kang Chang	if len(serializedKey) == 0 {
55*e7b1675dSTing-Kang Chang		return nil, errInvalidXChaCha20Poly1305Key
56*e7b1675dSTing-Kang Chang	}
57*e7b1675dSTing-Kang Chang	key := new(xpb.XChaCha20Poly1305Key)
58*e7b1675dSTing-Kang Chang	if err := proto.Unmarshal(serializedKey, key); err != nil {
59*e7b1675dSTing-Kang Chang		return nil, errInvalidXChaCha20Poly1305Key
60*e7b1675dSTing-Kang Chang	}
61*e7b1675dSTing-Kang Chang	if err := km.validateKey(key); err != nil {
62*e7b1675dSTing-Kang Chang		return nil, err
63*e7b1675dSTing-Kang Chang	}
64*e7b1675dSTing-Kang Chang	ret, err := subtle.NewXChaCha20Poly1305(key.KeyValue)
65*e7b1675dSTing-Kang Chang	if err != nil {
66*e7b1675dSTing-Kang Chang		return nil, fmt.Errorf("xchacha20poly1305_key_manager: cannot create new primitive: %v", err)
67*e7b1675dSTing-Kang Chang	}
68*e7b1675dSTing-Kang Chang	return ret, nil
69*e7b1675dSTing-Kang Chang}
70*e7b1675dSTing-Kang Chang
71*e7b1675dSTing-Kang Chang// NewKey generates a new XChaCha20Poly1305Key. It ignores serializedKeyFormat
72*e7b1675dSTing-Kang Chang// because the key size and other params are fixed.
73*e7b1675dSTing-Kang Changfunc (km *xChaCha20Poly1305KeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) {
74*e7b1675dSTing-Kang Chang	return &xpb.XChaCha20Poly1305Key{
75*e7b1675dSTing-Kang Chang		Version:  xChaCha20Poly1305KeyVersion,
76*e7b1675dSTing-Kang Chang		KeyValue: random.GetRandomBytes(chacha20poly1305.KeySize),
77*e7b1675dSTing-Kang Chang	}, nil
78*e7b1675dSTing-Kang Chang}
79*e7b1675dSTing-Kang Chang
80*e7b1675dSTing-Kang Chang// NewKeyData generates a new KeyData. It ignores serializedKeyFormat because
81*e7b1675dSTing-Kang Chang// the key size and other params are fixed. This should be used solely by the
82*e7b1675dSTing-Kang Chang// key management API.
83*e7b1675dSTing-Kang Changfunc (km *xChaCha20Poly1305KeyManager) NewKeyData(serializedKeyFormat []byte) (*tpb.KeyData, error) {
84*e7b1675dSTing-Kang Chang	key := &xpb.XChaCha20Poly1305Key{
85*e7b1675dSTing-Kang Chang		Version:  xChaCha20Poly1305KeyVersion,
86*e7b1675dSTing-Kang Chang		KeyValue: random.GetRandomBytes(chacha20poly1305.KeySize),
87*e7b1675dSTing-Kang Chang	}
88*e7b1675dSTing-Kang Chang	serializedKey, err := proto.Marshal(key)
89*e7b1675dSTing-Kang Chang	if err != nil {
90*e7b1675dSTing-Kang Chang		return nil, err
91*e7b1675dSTing-Kang Chang	}
92*e7b1675dSTing-Kang Chang	return &tpb.KeyData{
93*e7b1675dSTing-Kang Chang		TypeUrl:         xChaCha20Poly1305TypeURL,
94*e7b1675dSTing-Kang Chang		Value:           serializedKey,
95*e7b1675dSTing-Kang Chang		KeyMaterialType: km.KeyMaterialType(),
96*e7b1675dSTing-Kang Chang	}, nil
97*e7b1675dSTing-Kang Chang}
98*e7b1675dSTing-Kang Chang
99*e7b1675dSTing-Kang Chang// DoesSupport checks whether this key manager supports the given key type.
100*e7b1675dSTing-Kang Changfunc (km *xChaCha20Poly1305KeyManager) DoesSupport(typeURL string) bool {
101*e7b1675dSTing-Kang Chang	return typeURL == xChaCha20Poly1305TypeURL
102*e7b1675dSTing-Kang Chang}
103*e7b1675dSTing-Kang Chang
104*e7b1675dSTing-Kang Chang// TypeURL returns the type URL of keys managed by this key manager.
105*e7b1675dSTing-Kang Changfunc (km *xChaCha20Poly1305KeyManager) TypeURL() string {
106*e7b1675dSTing-Kang Chang	return xChaCha20Poly1305TypeURL
107*e7b1675dSTing-Kang Chang}
108*e7b1675dSTing-Kang Chang
109*e7b1675dSTing-Kang Chang// KeyMaterialType returns the key material type of this key manager.
110*e7b1675dSTing-Kang Changfunc (km *xChaCha20Poly1305KeyManager) KeyMaterialType() tpb.KeyData_KeyMaterialType {
111*e7b1675dSTing-Kang Chang	return tpb.KeyData_SYMMETRIC
112*e7b1675dSTing-Kang Chang}
113*e7b1675dSTing-Kang Chang
114*e7b1675dSTing-Kang Chang// DeriveKey derives a new key from serializedKeyFormat and pseudorandomness.
115*e7b1675dSTing-Kang Chang// Unlike NewKey, DeriveKey validates serializedKeyFormat's version.
116*e7b1675dSTing-Kang Changfunc (km *xChaCha20Poly1305KeyManager) DeriveKey(serializedKeyFormat []byte, pseudorandomness io.Reader) (proto.Message, error) {
117*e7b1675dSTing-Kang Chang	keyFormat := new(xpb.XChaCha20Poly1305KeyFormat)
118*e7b1675dSTing-Kang Chang	if err := proto.Unmarshal(serializedKeyFormat, keyFormat); err != nil {
119*e7b1675dSTing-Kang Chang		return nil, fmt.Errorf("xchacha20poly1305_key_manager: %v", err)
120*e7b1675dSTing-Kang Chang	}
121*e7b1675dSTing-Kang Chang	err := keyset.ValidateKeyVersion(keyFormat.Version, xChaCha20Poly1305KeyVersion)
122*e7b1675dSTing-Kang Chang	if err != nil {
123*e7b1675dSTing-Kang Chang		return nil, fmt.Errorf("xchacha20poly1305_key_manager: %v", err)
124*e7b1675dSTing-Kang Chang	}
125*e7b1675dSTing-Kang Chang
126*e7b1675dSTing-Kang Chang	keyValue := make([]byte, chacha20poly1305.KeySize)
127*e7b1675dSTing-Kang Chang	if _, err := io.ReadFull(pseudorandomness, keyValue); err != nil {
128*e7b1675dSTing-Kang Chang		return nil, fmt.Errorf("xchacha20poly1305_key_manager: not enough pseudorandomness given")
129*e7b1675dSTing-Kang Chang	}
130*e7b1675dSTing-Kang Chang	return &xpb.XChaCha20Poly1305Key{
131*e7b1675dSTing-Kang Chang		Version:  xChaCha20Poly1305KeyVersion,
132*e7b1675dSTing-Kang Chang		KeyValue: keyValue,
133*e7b1675dSTing-Kang Chang	}, nil
134*e7b1675dSTing-Kang Chang}
135*e7b1675dSTing-Kang Chang
136*e7b1675dSTing-Kang Chang// validateKey validates the given XChaCha20Poly1305Key.
137*e7b1675dSTing-Kang Changfunc (km *xChaCha20Poly1305KeyManager) validateKey(key *xpb.XChaCha20Poly1305Key) error {
138*e7b1675dSTing-Kang Chang	err := keyset.ValidateKeyVersion(key.Version, xChaCha20Poly1305KeyVersion)
139*e7b1675dSTing-Kang Chang	if err != nil {
140*e7b1675dSTing-Kang Chang		return fmt.Errorf("xchacha20poly1305_key_manager: %v", err)
141*e7b1675dSTing-Kang Chang	}
142*e7b1675dSTing-Kang Chang	keySize := uint32(len(key.KeyValue))
143*e7b1675dSTing-Kang Chang	if keySize != chacha20poly1305.KeySize {
144*e7b1675dSTing-Kang Chang		return fmt.Errorf("xchacha20poly1305_key_manager: key size != %d", chacha20poly1305.KeySize)
145*e7b1675dSTing-Kang Chang	}
146*e7b1675dSTing-Kang Chang	return nil
147*e7b1675dSTing-Kang Chang}
148