xref: /aosp_15_r20/external/tink/go/streamingaead/subtle/aes_ctr_hmac_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	"encoding/hex"
21	"testing"
22
23	"github.com/google/tink/go/streamingaead/subtle"
24)
25
26func TestAESCTRHMACEncryptDecrypt(t *testing.T) {
27	testCases := []struct {
28		name               string
29		keySizeInBytes     int
30		tagSizeInBytes     int
31		segmentSize        int
32		firstSegmentOffset int
33		plaintextSize      int
34		chunkSize          int
35	}{
36		{
37			name:               "small-1",
38			keySizeInBytes:     16,
39			tagSizeInBytes:     12,
40			segmentSize:        256,
41			firstSegmentOffset: 0,
42			plaintextSize:      20,
43			chunkSize:          64,
44		},
45		{
46			name:               "small-2",
47			keySizeInBytes:     16,
48			tagSizeInBytes:     12,
49			segmentSize:        512,
50			firstSegmentOffset: 0,
51			plaintextSize:      400,
52			chunkSize:          64,
53		},
54		{
55			name:               "small-offset-1",
56			keySizeInBytes:     16,
57			tagSizeInBytes:     12,
58			segmentSize:        256,
59			firstSegmentOffset: 8,
60			plaintextSize:      20,
61			chunkSize:          64,
62		},
63		{
64			name:               "small-offset-2",
65			keySizeInBytes:     16,
66			tagSizeInBytes:     12,
67			segmentSize:        512,
68			firstSegmentOffset: 8,
69			plaintextSize:      400,
70			chunkSize:          64,
71		},
72		{
73			name:               "empty-1",
74			keySizeInBytes:     16,
75			tagSizeInBytes:     12,
76			segmentSize:        256,
77			firstSegmentOffset: 0,
78			plaintextSize:      0,
79			chunkSize:          128,
80		},
81		{
82			name:               "empty-2",
83			keySizeInBytes:     16,
84			tagSizeInBytes:     12,
85			segmentSize:        256,
86			firstSegmentOffset: 8,
87			plaintextSize:      0,
88			chunkSize:          128,
89		},
90		{
91			name:               "medium-1",
92			keySizeInBytes:     16,
93			tagSizeInBytes:     12,
94			segmentSize:        256,
95			firstSegmentOffset: 0,
96			plaintextSize:      1024,
97			chunkSize:          128,
98		},
99		{
100			name:               "medium-2",
101			keySizeInBytes:     16,
102			tagSizeInBytes:     12,
103			segmentSize:        512,
104			firstSegmentOffset: 0,
105			plaintextSize:      3086,
106			chunkSize:          128,
107		},
108		{
109			name:               "medium-3",
110			keySizeInBytes:     32,
111			tagSizeInBytes:     12,
112			segmentSize:        1024,
113			firstSegmentOffset: 0,
114			plaintextSize:      12345,
115			chunkSize:          128,
116		},
117		{
118			name:               "large-chunks-1",
119			keySizeInBytes:     16,
120			tagSizeInBytes:     12,
121			segmentSize:        256,
122			firstSegmentOffset: 0,
123			plaintextSize:      1024,
124			chunkSize:          4096,
125		},
126		{
127			name:               "large-chunks-2",
128			keySizeInBytes:     16,
129			tagSizeInBytes:     12,
130			segmentSize:        512,
131			firstSegmentOffset: 0,
132			plaintextSize:      5086,
133			chunkSize:          4096,
134		},
135		{
136			name:               "large-chunks-3",
137			keySizeInBytes:     32,
138			tagSizeInBytes:     12,
139			segmentSize:        1024,
140			firstSegmentOffset: 0,
141			plaintextSize:      12345,
142			chunkSize:          5000,
143		},
144		{
145			name:               "medium-offset-1",
146			keySizeInBytes:     16,
147			tagSizeInBytes:     12,
148			segmentSize:        256,
149			firstSegmentOffset: 8,
150			plaintextSize:      1024,
151			chunkSize:          64,
152		},
153		{
154			name:               "medium-offset-2",
155			keySizeInBytes:     16,
156			tagSizeInBytes:     12,
157			segmentSize:        512,
158			firstSegmentOffset: 20,
159			plaintextSize:      3086,
160			chunkSize:          256,
161		},
162		{
163			name:               "medium-offset-3",
164			keySizeInBytes:     32,
165			tagSizeInBytes:     12,
166			segmentSize:        1024,
167			firstSegmentOffset: 10,
168			plaintextSize:      12345,
169			chunkSize:          5000,
170		},
171		{
172			name:               "last-segment-full-1",
173			keySizeInBytes:     16,
174			tagSizeInBytes:     12,
175			segmentSize:        256,
176			firstSegmentOffset: 0,
177			plaintextSize:      216,
178			chunkSize:          64,
179		},
180		{
181			name:               "last-segment-full-2",
182			keySizeInBytes:     16,
183			tagSizeInBytes:     12,
184			segmentSize:        256,
185			firstSegmentOffset: 16,
186			plaintextSize:      200,
187			chunkSize:          256,
188		},
189		{
190			name:               "last-segment-full-3",
191			keySizeInBytes:     16,
192			tagSizeInBytes:     12,
193			segmentSize:        256,
194			firstSegmentOffset: 16,
195			plaintextSize:      440,
196			chunkSize:          1024,
197		},
198		{
199			name:               "single-byte-1",
200			keySizeInBytes:     16,
201			tagSizeInBytes:     12,
202			segmentSize:        256,
203			firstSegmentOffset: 0,
204			plaintextSize:      1024,
205			chunkSize:          1,
206		},
207		{
208			name:               "single-byte-2",
209			keySizeInBytes:     32,
210			tagSizeInBytes:     12,
211			segmentSize:        512,
212			firstSegmentOffset: 0,
213			plaintextSize:      5086,
214			chunkSize:          1,
215		},
216	}
217
218	for _, tc := range testCases {
219		t.Run(tc.name, func(t *testing.T) {
220			cipher, err := subtle.NewAESCTRHMAC(ikm, "SHA256", tc.keySizeInBytes, "SHA256", tc.tagSizeInBytes, tc.segmentSize, tc.firstSegmentOffset)
221			if err != nil {
222				t.Errorf("cannot create cipher: %v", err)
223			}
224			pt, ct, err := encrypt(cipher, aad, tc.plaintextSize)
225			if err != nil {
226				t.Errorf("failure during encryption: %v", err)
227			}
228			if err := decrypt(cipher, aad, pt, ct, tc.chunkSize); err != nil {
229				t.Errorf("failure during decryption: %v", err)
230			}
231		})
232	}
233}
234
235func TestAESCTRHMACModifiedCiphertext(t *testing.T) {
236	ikm, err := hex.DecodeString("000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff")
237	if err != nil {
238		t.Fatal(err)
239	}
240	aad, err := hex.DecodeString("aabbccddeeff")
241	if err != nil {
242		t.Fatal(err)
243	}
244
245	const (
246		keySizeInBytes     = 16
247		tagSizeInBytes     = 12
248		segmentSize        = 256
249		firstSegmentOffset = 8
250		plaintextSize      = 1024
251		chunkSize          = 128
252	)
253
254	cipher, err := subtle.NewAESCTRHMAC(ikm, "SHA256", keySizeInBytes, "SHA256", tagSizeInBytes, segmentSize, firstSegmentOffset)
255	if err != nil {
256		t.Errorf("Cannot create a cipher: %v", err)
257	}
258
259	pt, ct, err := encrypt(cipher, aad, plaintextSize)
260	if err != nil {
261		t.Error(err)
262	}
263
264	t.Run("truncate ciphertext", func(t *testing.T) {
265		for i := 0; i < len(ct); i += 8 {
266			if err := decrypt(cipher, aad, pt, ct[:i], chunkSize); err == nil {
267				t.Error("expected error")
268			}
269		}
270	})
271	t.Run("append to ciphertext", func(t *testing.T) {
272		sizes := []int{1, segmentSize - len(ct)%segmentSize, segmentSize}
273		for _, size := range sizes {
274			ct2 := append(ct, make([]byte, size)...)
275			if err := decrypt(cipher, aad, pt, ct2, chunkSize); err == nil {
276				t.Errorf("expected error")
277			}
278		}
279	})
280	t.Run("flip bits", func(t *testing.T) {
281		for i := range ct {
282			ct2 := make([]byte, len(ct))
283			copy(ct2, ct)
284			ct2[i] ^= byte(1)
285			if err := decrypt(cipher, aad, pt, ct2, chunkSize); err == nil {
286				t.Errorf("expected error")
287			}
288		}
289	})
290	t.Run("delete segments", func(t *testing.T) {
291		for i := 0; i < len(ct)/segmentSize+1; i++ {
292			start, end := segmentPos(segmentSize, firstSegmentOffset, cipher.HeaderLength(), i)
293			if start > len(ct) {
294				break
295			}
296			if end > len(ct) {
297				end = len(ct)
298			}
299			ct2 := append(ct[:start], ct[end:]...)
300			if err := decrypt(cipher, aad, pt, ct2, chunkSize); err == nil {
301				t.Errorf("expected error")
302			}
303		}
304	})
305	t.Run("duplicate segments", func(t *testing.T) {
306		for i := 0; i < len(ct)/segmentSize+1; i++ {
307			start, end := segmentPos(segmentSize, firstSegmentOffset, cipher.HeaderLength(), i)
308			if start > len(ct) {
309				break
310			}
311			if end > len(ct) {
312				end = len(ct)
313			}
314			ct2 := append(ct[:end], ct[start:]...)
315			if err := decrypt(cipher, aad, pt, ct2, chunkSize); err == nil {
316				t.Errorf("expected error")
317			}
318		}
319	})
320	t.Run("modify aad", func(t *testing.T) {
321		for i := range aad {
322			aad2 := make([]byte, len(aad))
323			copy(aad2, aad)
324			aad2[i] ^= byte(1)
325			if err := decrypt(cipher, aad2, pt, ct, chunkSize); err == nil {
326				t.Errorf("expected error")
327			}
328		}
329	})
330}
331