xref: /aosp_15_r20/external/tink/go/aead/kms_envelope_aead.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1// Copyright 2019 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	"encoding/binary"
21	"errors"
22	"fmt"
23
24	"github.com/google/tink/go/core/registry"
25	"github.com/google/tink/go/tink"
26	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
27)
28
29const (
30	lenDEK        = 4
31	maxUint32Size = 4294967295
32)
33
34// KMSEnvelopeAEAD represents an instance of Envelope AEAD.
35type KMSEnvelopeAEAD struct {
36	dekTemplate *tinkpb.KeyTemplate
37	remote      tink.AEAD
38	// if err != nil, then the primitive will always fail with this error.
39	// this is needed because NewKMSEnvelopeAEAD2 doesn't return an error.
40	err error
41}
42
43var tinkAEADKeyTypes map[string]bool = map[string]bool{
44	aesCTRHMACAEADTypeURL:    true,
45	aesGCMTypeURL:            true,
46	chaCha20Poly1305TypeURL:  true,
47	xChaCha20Poly1305TypeURL: true,
48	aesGCMSIVTypeURL:         true,
49}
50
51func isSupporedKMSEnvelopeDEK(dekKeyTypeURL string) bool {
52	_, found := tinkAEADKeyTypes[dekKeyTypeURL]
53	return found
54}
55
56// NewKMSEnvelopeAEAD2 creates an new instance of KMSEnvelopeAEAD.
57//
58// dekTemplate must be a KeyTemplate for any of these Tink AEAD key types (any
59// other key template will be rejected):
60//   - AesCtrHmacAeadKey
61//   - AesGcmKey
62//   - ChaCha20Poly1305Key
63//   - XChaCha20Poly1305
64//   - AesGcmSivKey
65func NewKMSEnvelopeAEAD2(dekTemplate *tinkpb.KeyTemplate, remote tink.AEAD) *KMSEnvelopeAEAD {
66	if !isSupporedKMSEnvelopeDEK(dekTemplate.GetTypeUrl()) {
67		return &KMSEnvelopeAEAD{
68			remote:      nil,
69			dekTemplate: nil,
70			err:         fmt.Errorf("unsupported DEK key type %s", dekTemplate.GetTypeUrl()),
71		}
72	}
73	return &KMSEnvelopeAEAD{
74		remote:      remote,
75		dekTemplate: dekTemplate,
76		err:         nil,
77	}
78}
79
80// Encrypt implements the tink.AEAD interface for encryption.
81func (a *KMSEnvelopeAEAD) Encrypt(pt, aad []byte) ([]byte, error) {
82	if a.err != nil {
83		return nil, a.err
84	}
85	dekKeyData, err := registry.NewKeyData(a.dekTemplate)
86	if err != nil {
87		return nil, err
88	}
89	dek := dekKeyData.GetValue()
90	encryptedDEK, err := a.remote.Encrypt(dek, []byte{})
91	if err != nil {
92		return nil, err
93	}
94	p, err := registry.Primitive(a.dekTemplate.TypeUrl, dek)
95	if err != nil {
96		return nil, err
97	}
98	primitive, ok := p.(tink.AEAD)
99	if !ok {
100		return nil, errors.New("kms_envelope_aead: failed to convert AEAD primitive")
101	}
102
103	payload, err := primitive.Encrypt(pt, aad)
104	if err != nil {
105		return nil, err
106	}
107	if len(encryptedDEK) > maxUint32Size {
108		return nil, errors.New("kms_envelope_aead: encrypted dek too large")
109	}
110	res := make([]byte, 0, lenDEK+len(encryptedDEK)+len(payload))
111	res = binary.BigEndian.AppendUint32(res, uint32(len(encryptedDEK)))
112	res = append(res, encryptedDEK...)
113	res = append(res, payload...)
114	return res, nil
115}
116
117// Decrypt implements the tink.AEAD interface for decryption.
118func (a *KMSEnvelopeAEAD) Decrypt(ct, aad []byte) ([]byte, error) {
119	if a.err != nil {
120		return nil, a.err
121	}
122	// Verify we have enough bytes for the length of the encrypted DEK.
123	if len(ct) <= lenDEK {
124		return nil, errors.New("kms_envelope_aead: invalid ciphertext")
125	}
126
127	// Extract length of encrypted DEK and advance past that length.
128	ed := int(binary.BigEndian.Uint32(ct[:lenDEK]))
129	ct = ct[lenDEK:]
130
131	// Verify we have enough bytes for the encrypted DEK.
132	if ed <= 0 || len(ct) < ed {
133		return nil, errors.New("kms_envelope_aead: invalid ciphertext")
134	}
135
136	// Extract the encrypted DEK and the payload.
137	encryptedDEK := ct[:ed]
138	payload := ct[ed:]
139	ct = nil
140
141	// Decrypt the DEK.
142	dek, err := a.remote.Decrypt(encryptedDEK, []byte{})
143	if err != nil {
144		return nil, err
145	}
146
147	// Get an AEAD primitive corresponding to the DEK.
148	p, err := registry.Primitive(a.dekTemplate.TypeUrl, dek)
149	if err != nil {
150		return nil, fmt.Errorf("kms_envelope_aead: %s", err)
151	}
152	primitive, ok := p.(tink.AEAD)
153	if !ok {
154		return nil, errors.New("kms_envelope_aead: failed to convert AEAD primitive")
155	}
156
157	// Decrypt the payload.
158	return primitive.Decrypt(payload, aad)
159}
160