xref: /aosp_15_r20/external/tink/go/aead/subtle/aes_gcm_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 subtle_test
18
19import (
20	"bytes"
21	"encoding/hex"
22	"fmt"
23	"testing"
24
25	"github.com/google/tink/go/aead/subtle"
26	"github.com/google/tink/go/subtle/random"
27	"github.com/google/tink/go/testutil"
28)
29
30var aesKeySizes = []uint32{
31	16, /*AES-128*/
32	32, /*AES-256*/
33}
34
35// Since the tag size depends on the Seal() function of crypto library,
36// this test checks that the tag size is always 128 bit.
37func TestAESGCMTagLength(t *testing.T) {
38	for _, keySize := range aesKeySizes {
39		key := random.GetRandomBytes(keySize)
40		a, _ := subtle.NewAESGCM(key)
41		ad := random.GetRandomBytes(32)
42		pt := random.GetRandomBytes(32)
43		ct, _ := a.Encrypt(pt, ad)
44		actualTagSize := len(ct) - subtle.AESGCMIVSize - len(pt)
45		if actualTagSize != subtle.AESGCMTagSize {
46			t.Errorf("tag size is not 128 bit, it is %d bit", actualTagSize*8)
47		}
48	}
49}
50
51func TestAESGCMKeySize(t *testing.T) {
52	for _, keySize := range aesKeySizes {
53		if _, err := subtle.NewAESGCM(make([]byte, keySize)); err != nil {
54			t.Errorf("unexpected error when key size is %d btyes", keySize)
55		}
56		if _, err := subtle.NewAESGCM(make([]byte, keySize+1)); err == nil {
57			t.Errorf("expect an error when key size is not supported %d", keySize)
58		}
59	}
60}
61
62func TestAESGCMEncryptDecrypt(t *testing.T) {
63	for _, keySize := range aesKeySizes {
64		key := random.GetRandomBytes(keySize)
65		a, err := subtle.NewAESGCM(key)
66		if err != nil {
67			t.Errorf("unexpected error when creating new cipher: %s", err)
68		}
69		ad := random.GetRandomBytes(5)
70		for ptSize := 0; ptSize < 75; ptSize++ {
71			pt := random.GetRandomBytes(uint32(ptSize))
72			ct, err := a.Encrypt(pt, ad)
73			if err != nil {
74				t.Errorf("unexpected error in encryption: keySize %v, ptSize %v", keySize, ptSize)
75			}
76			decrypted, err := a.Decrypt(ct, ad)
77			if err != nil {
78				t.Errorf("unexpected error in decryption: keySize %v, ptSize %v", keySize, ptSize)
79			}
80			if !bytes.Equal(pt, decrypted) {
81				t.Errorf("decrypted text and plaintext don't match: keySize %v, ptSize %v", keySize, ptSize)
82			}
83		}
84	}
85}
86
87func TestAESGCMLongMessages(t *testing.T) {
88	ptSize := 16
89	for ptSize <= 1<<24 {
90		pt := random.GetRandomBytes(uint32(ptSize))
91		ad := random.GetRandomBytes(uint32(ptSize / 3))
92		for _, keySize := range aesKeySizes {
93			key := random.GetRandomBytes(keySize)
94			a, _ := subtle.NewAESGCM(key)
95			ct, _ := a.Encrypt(pt, ad)
96			decrypted, _ := a.Decrypt(ct, ad)
97			if !bytes.Equal(pt, decrypted) {
98				t.Errorf("decrypted text and plaintext don't match: keySize %v, ptSize %v", keySize, ptSize)
99			}
100		}
101		ptSize += 5 * ptSize / 11
102	}
103}
104
105func TestAESGCMModifyCiphertext(t *testing.T) {
106	ad := random.GetRandomBytes(33)
107	key := random.GetRandomBytes(16)
108	pt := random.GetRandomBytes(32)
109	a, _ := subtle.NewAESGCM(key)
110	ct, _ := a.Encrypt(pt, ad)
111	// flipping bits
112	for i := 0; i < len(ct); i++ {
113		tmp := ct[i]
114		for j := 0; j < 8; j++ {
115			ct[i] ^= 1 << uint8(j)
116			if _, err := a.Decrypt(ct, ad); err == nil {
117				t.Errorf("expect an error when flipping bit of ciphertext: byte %d, bit %d", i, j)
118			}
119			ct[i] = tmp
120		}
121	}
122	// truncated ciphertext
123	for i := 1; i < len(ct); i++ {
124		if _, err := a.Decrypt(ct[:i], ad); err == nil {
125			t.Errorf("expect an error ciphertext is truncated until byte %d", i)
126		}
127	}
128	// modify associated data
129	for i := 0; i < len(ad); i++ {
130		tmp := ad[i]
131		for j := 0; j < 8; j++ {
132			ad[i] ^= 1 << uint8(j)
133			if _, err := a.Decrypt(ct, ad); err == nil {
134				t.Errorf("expect an error when flipping bit of ad: byte %d, bit %d", i, j)
135			}
136			ad[i] = tmp
137		}
138	}
139	// replace ciphertext with a random string with a small, unacceptable size
140	for _, ctSize := range []uint32{subtle.AESGCMIVSize / 2, subtle.AESGCMIVSize - 1} {
141		smallCT := random.GetRandomBytes(ctSize)
142		emptyAD := []byte{}
143		if _, err := a.Decrypt(smallCT, emptyAD); err == nil {
144			t.Error("Decrypt: got success, want err")
145		}
146	}
147}
148
149/**
150 * This is a very simple test for the randomness of the nonce.
151 * The test simply checks that the multiple ciphertexts of the same
152 * message are distinct.
153 */
154func TestAESGCMRandomNonce(t *testing.T) {
155	nSample := 1 << 17
156	key := random.GetRandomBytes(16)
157	pt := []byte{}
158	ad := []byte{}
159	a, _ := subtle.NewAESGCM(key)
160	ctSet := make(map[string]bool)
161	for i := 0; i < nSample; i++ {
162		ct, _ := a.Encrypt(pt, ad)
163		ctHex := hex.EncodeToString(ct)
164		_, existed := ctSet[ctHex]
165		if existed {
166			t.Errorf("nonce is repeated after %d samples", i)
167		}
168		ctSet[ctHex] = true
169	}
170}
171
172func TestAESGCMWycheproofCases(t *testing.T) {
173	testutil.SkipTestIfTestSrcDirIsNotSet(t)
174	suite := new(AEADSuite)
175	if err := testutil.PopulateSuite(suite, "aes_gcm_test.json"); err != nil {
176		t.Fatalf("failed populating suite: %s", err)
177	}
178	for _, group := range suite.TestGroups {
179		if err := subtle.ValidateAESKeySize(group.KeySize / 8); err != nil {
180			continue
181		}
182		if group.IvSize != subtle.AESGCMIVSize*8 {
183			continue
184		}
185		for _, test := range group.Tests {
186			caseName := fmt.Sprintf("%s-%s(%d,%d):Case-%d",
187				suite.Algorithm, group.Type, group.KeySize, group.TagSize, test.CaseID)
188			t.Run(caseName, func(t *testing.T) { runAESGCMWycheproofCase(t, test) })
189		}
190	}
191}
192
193func runAESGCMWycheproofCase(t *testing.T, tc *AEADCase) {
194	var combinedCt []byte
195	combinedCt = append(combinedCt, tc.Iv...)
196	combinedCt = append(combinedCt, tc.Ct...)
197	combinedCt = append(combinedCt, tc.Tag...)
198	// create cipher and do encryption
199	cipher, err := subtle.NewAESGCM(tc.Key)
200	if err != nil {
201		t.Fatalf("cannot create new instance of AESGCM in test case: %s", err)
202	}
203	decrypted, err := cipher.Decrypt(combinedCt, tc.Aad)
204	if err != nil {
205		if tc.Result == "valid" {
206			t.Errorf("unexpected error in test case: %s", err)
207		}
208	} else {
209		if tc.Result == "invalid" {
210			t.Error("decrypted invalid test case")
211		}
212		if !bytes.Equal(decrypted, tc.Msg) {
213			t.Error("incorrect decryption in test case")
214		}
215	}
216}
217