xref: /aosp_15_r20/external/tink/go/streamingaead/aes_gcm_hkdf_key_manager.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1// Copyright 2020 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 streamingaead
18
19import (
20	"errors"
21	"fmt"
22	"io"
23
24	"google.golang.org/protobuf/proto"
25	subtleaead "github.com/google/tink/go/aead/subtle"
26	"github.com/google/tink/go/keyset"
27	"github.com/google/tink/go/streamingaead/subtle"
28	"github.com/google/tink/go/subtle/random"
29	ghpb "github.com/google/tink/go/proto/aes_gcm_hkdf_streaming_go_proto"
30	commonpb "github.com/google/tink/go/proto/common_go_proto"
31	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
32)
33
34const (
35	aesGCMHKDFKeyVersion = 0
36	aesGCMHKDFTypeURL    = "type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey"
37)
38
39var (
40	errInvalidAESGCMHKDFKey       = errors.New("aes_gcm_hkdf_key_manager: invalid key")
41	errInvalidAESGCMHKDFKeyFormat = errors.New("aes_gcm_hkdf_key_manager: invalid key format")
42)
43
44// aesGCMHKDFKeyManager is an implementation of KeyManager interface.
45// It generates new AESGCMHKDFKey keys and produces new instances of AESGCMHKDF subtle.
46type aesGCMHKDFKeyManager struct{}
47
48// Primitive creates an AESGCMHKDF subtle for the given serialized AESGCMHKDFKey proto.
49func (km *aesGCMHKDFKeyManager) Primitive(serializedKey []byte) (interface{}, error) {
50	if len(serializedKey) == 0 {
51		return nil, errInvalidAESGCMHKDFKey
52	}
53	key := &ghpb.AesGcmHkdfStreamingKey{}
54	if err := proto.Unmarshal(serializedKey, key); err != nil {
55		return nil, errInvalidAESGCMHKDFKey
56	}
57	if err := km.validateKey(key); err != nil {
58		return nil, err
59	}
60	ret, err := subtle.NewAESGCMHKDF(
61		key.KeyValue,
62		key.Params.HkdfHashType.String(),
63		int(key.Params.DerivedKeySize),
64		int(key.Params.CiphertextSegmentSize),
65		// no first segment offset
66		0)
67	if err != nil {
68		return nil, fmt.Errorf("aes_gcm_hkdf_key_manager: cannot create new primitive: %s", err)
69	}
70	return ret, nil
71}
72
73// NewKey creates a new key according to specification in the given serialized
74// AesGcmHkdfStreamingKeyFormat.
75func (km *aesGCMHKDFKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) {
76	if len(serializedKeyFormat) == 0 {
77		return nil, errInvalidAESGCMHKDFKeyFormat
78	}
79	keyFormat := &ghpb.AesGcmHkdfStreamingKeyFormat{}
80	if err := proto.Unmarshal(serializedKeyFormat, keyFormat); err != nil {
81		return nil, errInvalidAESGCMHKDFKeyFormat
82	}
83	if err := km.validateKeyFormat(keyFormat); err != nil {
84		return nil, fmt.Errorf("aes_gcm_hkdf_key_manager: invalid key format: %s", err)
85	}
86	return &ghpb.AesGcmHkdfStreamingKey{
87		Version:  aesGCMHKDFKeyVersion,
88		KeyValue: random.GetRandomBytes(keyFormat.KeySize),
89		Params:   keyFormat.Params,
90	}, nil
91}
92
93// NewKeyData creates a new KeyData according to specification in the given serialized AesGcmHkdfStreamingKeyFormat.
94// It should be used solely by the key management API.
95func (km *aesGCMHKDFKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) {
96	key, err := km.NewKey(serializedKeyFormat)
97	if err != nil {
98		return nil, err
99	}
100	serializedKey, err := proto.Marshal(key)
101	if err != nil {
102		return nil, err
103	}
104	return &tinkpb.KeyData{
105		TypeUrl:         km.TypeURL(),
106		Value:           serializedKey,
107		KeyMaterialType: km.KeyMaterialType(),
108	}, nil
109}
110
111// DoesSupport indicates if this key manager supports the given key type.
112func (km *aesGCMHKDFKeyManager) DoesSupport(typeURL string) bool {
113	return typeURL == aesGCMHKDFTypeURL
114}
115
116// TypeURL returns the key type of keys managed by this key manager.
117func (km *aesGCMHKDFKeyManager) TypeURL() string {
118	return aesGCMHKDFTypeURL
119}
120
121// KeyMaterialType returns the key material type of this key manager.
122func (km *aesGCMHKDFKeyManager) KeyMaterialType() tinkpb.KeyData_KeyMaterialType {
123	return tinkpb.KeyData_SYMMETRIC
124}
125
126// DeriveKey derives a new key from serializedKeyFormat and pseudorandomness.
127func (km *aesGCMHKDFKeyManager) DeriveKey(serializedKeyFormat []byte, pseudorandomness io.Reader) (proto.Message, error) {
128	if len(serializedKeyFormat) == 0 {
129		return nil, errInvalidAESGCMHKDFKeyFormat
130	}
131	keyFormat := &ghpb.AesGcmHkdfStreamingKeyFormat{}
132	if err := proto.Unmarshal(serializedKeyFormat, keyFormat); err != nil {
133		return nil, errInvalidAESGCMHKDFKeyFormat
134	}
135	if err := km.validateKeyFormat(keyFormat); err != nil {
136		return nil, fmt.Errorf("aes_gcm_hkdf_key_manager: invalid key format: %v", err)
137	}
138	if err := keyset.ValidateKeyVersion(keyFormat.GetVersion(), aesGCMHKDFKeyVersion); err != nil {
139		return nil, fmt.Errorf("aes_gcm_hkdf_key_manager: invalid key version: %s", err)
140	}
141
142	keyValue := make([]byte, keyFormat.GetKeySize())
143	if _, err := io.ReadFull(pseudorandomness, keyValue); err != nil {
144		return nil, fmt.Errorf("aes_gcm_hkdf_key_manager: not enough pseudorandomness given")
145	}
146	return &ghpb.AesGcmHkdfStreamingKey{
147		Version:  aesGCMHKDFKeyVersion,
148		KeyValue: keyValue,
149		Params:   keyFormat.Params,
150	}, nil
151}
152
153// validateKey validates the given AESGCMHKDFKey.
154func (km *aesGCMHKDFKeyManager) validateKey(key *ghpb.AesGcmHkdfStreamingKey) error {
155	if err := keyset.ValidateKeyVersion(key.Version, aesGCMHKDFKeyVersion); err != nil {
156		return fmt.Errorf("aes_gcm_hkdf_key_manager: %s", err)
157	}
158	keySize := uint32(len(key.KeyValue))
159	if err := subtleaead.ValidateAESKeySize(keySize); err != nil {
160		return fmt.Errorf("aes_gcm_hkdf_key_manager: %s", err)
161	}
162	if err := km.validateParams(key.Params); err != nil {
163		return fmt.Errorf("aes_gcm_hkdf_key_manager: %s", err)
164	}
165	return nil
166}
167
168// validateKeyFormat validates the given AESGCMHKDFKeyFormat.
169func (km *aesGCMHKDFKeyManager) validateKeyFormat(format *ghpb.AesGcmHkdfStreamingKeyFormat) error {
170	if err := subtleaead.ValidateAESKeySize(format.KeySize); err != nil {
171		return fmt.Errorf("aes_gcm_hkdf_key_manager: %s", err)
172	}
173	if err := km.validateParams(format.Params); err != nil {
174		return fmt.Errorf("aes_gcm_hkdf_key_manager: %s", err)
175	}
176	return nil
177}
178
179// validateKeyFormat validates the given AESGCMHKDFKeyFormat.
180func (km *aesGCMHKDFKeyManager) validateParams(params *ghpb.AesGcmHkdfStreamingParams) error {
181	if err := subtleaead.ValidateAESKeySize(params.DerivedKeySize); err != nil {
182		return fmt.Errorf("aes_gcm_hkdf_key_manager: %s", err)
183	}
184	if params.HkdfHashType != commonpb.HashType_SHA1 && params.HkdfHashType != commonpb.HashType_SHA256 && params.HkdfHashType != commonpb.HashType_SHA512 {
185		return errors.New("unknown HKDF hash type")
186	}
187	if params.CiphertextSegmentSize > 0x7fffffff {
188		return errors.New("CiphertextSegmentSize must be at most 2^31 - 1")
189	}
190	minSegmentSize := params.DerivedKeySize + subtle.AESGCMHKDFNoncePrefixSizeInBytes + subtle.AESGCMHKDFTagSizeInBytes + 2
191	if params.CiphertextSegmentSize < minSegmentSize {
192		return fmt.Errorf("ciphertext segment_size must be at least (derivedKeySize + noncePrefixInBytes + tagSizeInBytes + 2)")
193	}
194	return nil
195}
196