xref: /aosp_15_r20/external/tink/go/streamingaead/streamingaead_factory_test.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_test
18
19import (
20	"bytes"
21	"fmt"
22	"io"
23	"log"
24	"strings"
25	"testing"
26
27	"google.golang.org/protobuf/proto"
28	"github.com/google/tink/go/keyset"
29	"github.com/google/tink/go/mac"
30	"github.com/google/tink/go/streamingaead"
31	"github.com/google/tink/go/subtle/random"
32	"github.com/google/tink/go/testkeyset"
33	"github.com/google/tink/go/testutil"
34	"github.com/google/tink/go/tink"
35	ghpb "github.com/google/tink/go/proto/aes_gcm_hkdf_streaming_go_proto"
36	commonpb "github.com/google/tink/go/proto/common_go_proto"
37	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
38)
39
40const (
41	aesGCMHKDFTypeURL = "type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey"
42)
43
44func TestFactoryMultipleKeys(t *testing.T) {
45	keyset := testutil.NewTestAESGCMHKDFKeyset()
46
47	keysetHandle, err := testkeyset.NewHandle(keyset)
48	if err != nil {
49		log.Fatal(err)
50	}
51
52	a, err := streamingaead.New(keysetHandle)
53	if err != nil {
54		t.Errorf("streamingaead.New failed: %s", err)
55	}
56
57	t.Run("Encrypt with a primary RAW key and decrypt with the keyset", func(t *testing.T) {
58		if err := validateFactoryCipher(a, a); err != nil {
59			t.Errorf("invalid cipher: %s", err)
60		}
61	})
62
63	t.Run("Encrypt with a non-primary RAW key and decrypt with the keyset", func(t *testing.T) {
64		rawKey := keyset.Key[1]
65		if rawKey.OutputPrefixType != tinkpb.OutputPrefixType_RAW {
66			t.Errorf("expect a raw key")
67		}
68		keyset2 := testutil.NewKeyset(rawKey.KeyId, []*tinkpb.Keyset_Key{rawKey})
69		keysetHandle2, _ := testkeyset.NewHandle(keyset2)
70		a2, err := streamingaead.New(keysetHandle2)
71		if err != nil {
72			t.Errorf("streamingaead.New failed: %s", err)
73		}
74		if err := validateFactoryCipher(a2, a); err != nil {
75			t.Errorf("invalid cipher: %s", err)
76		}
77	})
78
79	t.Run("Encrypt with a random key not in the keyset, decrypt with the keyset should fail", func(t *testing.T) {
80		keyset2 := testutil.NewTestAESGCMHKDFKeyset()
81		keysetHandle2, _ := testkeyset.NewHandle(keyset2)
82		a2, err := streamingaead.New(keysetHandle2)
83		if err != nil {
84			t.Errorf("streamingaead.New failed: %s", err)
85		}
86		err = validateFactoryCipher(a2, a)
87		if err == nil || !strings.Contains(err.Error(), "decryption failed") {
88			t.Errorf("expect decryption to fail with random key: %s", err)
89		}
90	})
91}
92
93func validateFactoryCipher(encryptCipher tink.StreamingAEAD, decryptCipher tink.StreamingAEAD) error {
94	tt := []int{1, 16, 4095, 4096, 4097, 16384}
95
96	for _, t := range tt {
97		if err := encryptDecrypt(encryptCipher, decryptCipher, t, 32); err != nil {
98			return fmt.Errorf("failed plaintext-size=%d: %s", t, err)
99		}
100	}
101	return nil
102}
103
104func encryptDecrypt(encryptCipher, decryptCipher tink.StreamingAEAD, ptSize, aadSize int) error {
105	pt := random.GetRandomBytes(uint32(ptSize))
106	aad := random.GetRandomBytes(uint32(aadSize))
107
108	buf := &bytes.Buffer{}
109	w, err := encryptCipher.NewEncryptingWriter(buf, aad)
110	if err != nil {
111		return fmt.Errorf("cannot create encrypt writer: %v", err)
112	}
113	if _, err := w.Write(pt); err != nil {
114		return fmt.Errorf("error writing data: %v", err)
115	}
116	if err := w.Close(); err != nil {
117		return fmt.Errorf("error closing writer: %v", err)
118	}
119
120	r, err := decryptCipher.NewDecryptingReader(buf, aad)
121	if err != nil {
122		return fmt.Errorf("cannot create decrypt reader: %v", err)
123	}
124	ptGot := make([]byte, len(pt)+1)
125	n, err := io.ReadFull(r, ptGot)
126	if err != nil && err != io.ErrUnexpectedEOF {
127		return fmt.Errorf("decryption failed: %v", err)
128	}
129	ptGot = ptGot[:n]
130	if !bytes.Equal(pt, ptGot) {
131		return fmt.Errorf("decryption failed")
132	}
133	return nil
134}
135
136func TestFactoryWithInvalidPrimitiveSetType(t *testing.T) {
137	wrongKH, err := keyset.NewHandle(mac.HMACSHA256Tag128KeyTemplate())
138	if err != nil {
139		t.Fatalf("failed to build *keyset.Handle: %s", err)
140	}
141
142	_, err = streamingaead.New(wrongKH)
143	if err == nil {
144		t.Fatal("New() should fail with wrong *keyset.Handle")
145	}
146}
147
148func TestFactoryWithValidPrimitiveSetType(t *testing.T) {
149	goodKH, err := keyset.NewHandle(streamingaead.AES128GCMHKDF4KBKeyTemplate())
150	if err != nil {
151		t.Fatalf("failed to build *keyset.Handle: %s", err)
152	}
153
154	_, err = streamingaead.New(goodKH)
155	if err != nil {
156		t.Fatalf("New() failed with good *keyset.Handle: %s", err)
157	}
158}
159
160func TestFactoryWithKeysetWithTinkKeys(t *testing.T) {
161	key := &ghpb.AesGcmHkdfStreamingKey{
162		Version:  0,
163		KeyValue: []byte("0123456789abcdef"),
164		Params: &ghpb.AesGcmHkdfStreamingParams{
165			CiphertextSegmentSize: 512,
166			DerivedKeySize:        16,
167			HkdfHashType:          commonpb.HashType_SHA1,
168		},
169	}
170	value1, err := proto.Marshal(key)
171	if err != nil {
172		t.Fatalf("proto.Marshal(key) err = %q, want nil", err)
173	}
174	key.KeyValue = []byte("ABCDEF0123456789")
175	value2, err := proto.Marshal(key)
176	if err != nil {
177		t.Fatalf("proto.Marshal(key) err = %q, want nil", err)
178	}
179
180	keyset := &tinkpb.Keyset{
181		PrimaryKeyId: 1,
182		Key: []*tinkpb.Keyset_Key{{
183			KeyData: &tinkpb.KeyData{
184				TypeUrl:         aesGCMHKDFTypeURL,
185				Value:           value1,
186				KeyMaterialType: tinkpb.KeyData_SYMMETRIC,
187			},
188			OutputPrefixType: tinkpb.OutputPrefixType_TINK,
189			KeyId:            1,
190			Status:           tinkpb.KeyStatusType_ENABLED,
191		}, &tinkpb.Keyset_Key{
192			KeyData: &tinkpb.KeyData{
193				TypeUrl:         aesGCMHKDFTypeURL,
194				Value:           value2,
195				KeyMaterialType: tinkpb.KeyData_SYMMETRIC,
196			},
197			OutputPrefixType: tinkpb.OutputPrefixType_RAW,
198			KeyId:            2,
199			Status:           tinkpb.KeyStatusType_ENABLED,
200		}},
201	}
202
203	keysetHandle, err := testkeyset.NewHandle(keyset)
204	if err != nil {
205		t.Fatalf("testkeyset.NewHandle(keyset) err = %q, want nil", err)
206	}
207	a, err := streamingaead.New(keysetHandle)
208	if err != nil {
209		t.Errorf("streamingaead.New(keysetHandle) err = %q, want nil", err)
210	}
211
212	if err := validateFactoryCipher(a, a); err != nil {
213		t.Errorf("Encryption & Decryption with TINK key should succeed")
214	}
215}
216