xref: /aosp_15_r20/external/tink/go/hybrid/internal/hpke/hpke_test.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1// Copyright 2022 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 hpke
18
19import (
20	"encoding/hex"
21	"encoding/json"
22	"math/big"
23	"os"
24	"path/filepath"
25	"testing"
26
27	"github.com/google/tink/go/testutil"
28)
29
30// TODO(b/201070904): Separate tests into internal_test package.
31
32// aeadIDs are specified at
33// https://www.rfc-editor.org/rfc/rfc9180.html#section-7.3.
34var aeadIDs = []struct {
35	name      string
36	aeadID    uint16
37	keyLength int
38}{
39	{"AES128GCM", aes128GCM, 16},
40	{"AES256GCM", aes256GCM, 32},
41	{"ChaCha20Poly1305", chaCha20Poly1305, 32},
42}
43
44type hpkeID struct {
45	id     int
46	mode   uint8
47	kemID  uint16
48	kdfID  uint16
49	aeadID uint16
50}
51
52type vector struct {
53	info                   []byte
54	senderPubKey           []byte
55	senderPrivKey          []byte
56	recipientPubKey        []byte
57	recipientPrivKey       []byte
58	encapsulatedKey        []byte
59	sharedSecret           []byte
60	keyScheduleCtx         []byte
61	secret                 []byte
62	key                    []byte
63	baseNonce              []byte
64	consecutiveEncryptions []encryptionVector
65	otherEncryptions       []encryptionVector
66}
67
68type encryptionVector struct {
69	key            []byte
70	plaintext      []byte
71	associatedData []byte
72	nonce          []byte
73	ciphertext     []byte
74	sequenceNumber *big.Int
75}
76
77type encryptionString struct {
78	sequenceNumber uint64
79	plaintext      string
80	associatedData string
81	nonce          string
82	ciphertext     string
83}
84
85// TODO(b/201070904): Include all Tink-supported RFC vectors.
86func internetDraftVector(t *testing.T) (hpkeID, vector) {
87	t.Helper()
88
89	// Test vector from HPKE RFC
90	// https://www.rfc-editor.org/rfc/rfc9180.html#appendix-A.1.1.
91	v := struct {
92		mode                                                                                    uint8
93		kemID, kdfID, aeadID                                                                    uint16
94		info, pkEm, skEm, pkRm, skRm, enc, sharedSecret, keyScheduleCtx, secret, key, baseNonce string
95		consecutiveEncryptions, otherEncryptions                                                []encryptionString
96	}{
97		mode:           0,
98		kemID:          32,
99		kdfID:          1,
100		aeadID:         1,
101		info:           "4f6465206f6e2061204772656369616e2055726e",
102		pkEm:           "37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431",
103		skEm:           "52c4a758a802cd8b936eceea314432798d5baf2d7e9235dc084ab1b9cfa2f736",
104		pkRm:           "3948cfe0ad1ddb695d780e59077195da6c56506b027329794ab02bca80815c4d",
105		skRm:           "4612c550263fc8ad58375df3f557aac531d26850903e55a9f23f21d8534e8ac8",
106		enc:            "37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431",
107		sharedSecret:   "fe0e18c9f024ce43799ae393c7e8fe8fce9d218875e8227b0187c04e7d2ea1fc",
108		keyScheduleCtx: "00725611c9d98c07c03f60095cd32d400d8347d45ed67097bbad50fc56da742d07cb6cffde367bb0565ba28bb02c90744a20f5ef37f30523526106f637abb05449",
109		secret:         "12fff91991e93b48de37e7daddb52981084bd8aa64289c3788471d9a9712f397",
110		key:            "4531685d41d65f03dc48f6b8302c05b0",
111		baseNonce:      "56d890e5accaaf011cff4b7d",
112		consecutiveEncryptions: []encryptionString{
113			{
114				sequenceNumber: 0,
115				plaintext:      "4265617574792069732074727574682c20747275746820626561757479",
116				associatedData: "436f756e742d30",
117				nonce:          "56d890e5accaaf011cff4b7d",
118				ciphertext:     "f938558b5d72f1a23810b4be2ab4f84331acc02fc97babc53a52ae8218a355a96d8770ac83d07bea87e13c512a",
119			},
120			{
121				sequenceNumber: 1,
122				plaintext:      "4265617574792069732074727574682c20747275746820626561757479",
123				associatedData: "436f756e742d31",
124				nonce:          "56d890e5accaaf011cff4b7c",
125				ciphertext:     "af2d7e9ac9ae7e270f46ba1f975be53c09f8d875bdc8535458c2494e8a6eab251c03d0c22a56b8ca42c2063b84",
126			},
127			{
128				sequenceNumber: 2,
129				plaintext:      "4265617574792069732074727574682c20747275746820626561757479",
130				associatedData: "436f756e742d32",
131				nonce:          "56d890e5accaaf011cff4b7f",
132				ciphertext:     "498dfcabd92e8acedc281e85af1cb4e3e31c7dc394a1ca20e173cb72516491588d96a19ad4a683518973dcc180",
133			},
134		},
135		otherEncryptions: []encryptionString{
136			{
137				sequenceNumber: 4,
138				plaintext:      "4265617574792069732074727574682c20747275746820626561757479",
139				associatedData: "436f756e742d34",
140				nonce:          "56d890e5accaaf011cff4b79",
141				ciphertext:     "583bd32bc67a5994bb8ceaca813d369bca7b2a42408cddef5e22f880b631215a09fc0012bc69fccaa251c0246d",
142			},
143			{
144				sequenceNumber: 255,
145				plaintext:      "4265617574792069732074727574682c20747275746820626561757479",
146				associatedData: "436f756e742d323535",
147				nonce:          "56d890e5accaaf011cff4b82",
148				ciphertext:     "7175db9717964058640a3a11fb9007941a5d1757fda1a6935c805c21af32505bf106deefec4a49ac38d71c9e0a",
149			},
150			{
151				sequenceNumber: 256,
152				plaintext:      "4265617574792069732074727574682c20747275746820626561757479",
153				associatedData: "436f756e742d323536",
154				nonce:          "56d890e5accaaf011cff4a7d",
155				ciphertext:     "957f9800542b0b8891badb026d79cc54597cb2d225b54c00c5238c25d05c30e3fbeda97d2e0e1aba483a2df9f2",
156			},
157		},
158	}
159
160	var info, senderPubKey, senderPrivKey, recipientPubKey, recipientPrivKey, encapsulatedKey, sharedSecret, keyScheduleCtx, secret, key, baseNonce []byte
161	var err error
162	if info, err = hex.DecodeString(v.info); err != nil {
163		t.Fatalf("hex.DecodeString(info): err %q", err)
164	}
165	if senderPubKey, err = hex.DecodeString(v.pkEm); err != nil {
166		t.Fatalf("hex.DecodeString(pkEm): err %q", err)
167	}
168	if senderPrivKey, err = hex.DecodeString(v.skEm); err != nil {
169		t.Fatalf("hex.DecodeString(skEm): err %q", err)
170	}
171	if recipientPubKey, err = hex.DecodeString(v.pkRm); err != nil {
172		t.Fatalf("hex.DecodeString(pkRm): err %q", err)
173	}
174	if recipientPrivKey, err = hex.DecodeString(v.skRm); err != nil {
175		t.Fatalf("hex.DecodeString(skRm): err %q", err)
176	}
177	if encapsulatedKey, err = hex.DecodeString(v.enc); err != nil {
178		t.Fatalf("hex.DecodeString(enc): err %q", err)
179	}
180	if sharedSecret, err = hex.DecodeString(v.sharedSecret); err != nil {
181		t.Fatalf("hex.DecodeString(sharedSecret): err %q", err)
182	}
183	if keyScheduleCtx, err = hex.DecodeString(v.keyScheduleCtx); err != nil {
184		t.Fatalf("hex.DecodeString(keyScheduleCtx): err %q", err)
185	}
186	if secret, err = hex.DecodeString(v.secret); err != nil {
187		t.Fatalf("hex.DecodeString(secret): err %q", err)
188	}
189	if key, err = hex.DecodeString(v.key); err != nil {
190		t.Fatalf("hex.DecodeString(key): err %q", err)
191	}
192	if baseNonce, err = hex.DecodeString(v.baseNonce); err != nil {
193		t.Fatalf("hex.DecodeString(baseNonce): err %q", err)
194	}
195
196	return hpkeID{0 /*=id */, v.mode, v.kemID, v.kdfID, v.aeadID},
197		vector{
198			info:                   info,
199			senderPubKey:           senderPubKey,
200			senderPrivKey:          senderPrivKey,
201			recipientPubKey:        recipientPubKey,
202			recipientPrivKey:       recipientPrivKey,
203			encapsulatedKey:        encapsulatedKey,
204			sharedSecret:           sharedSecret,
205			keyScheduleCtx:         keyScheduleCtx,
206			secret:                 secret,
207			key:                    key,
208			baseNonce:              baseNonce,
209			consecutiveEncryptions: parseEncryptions(t, v.consecutiveEncryptions),
210			otherEncryptions:       parseEncryptions(t, v.otherEncryptions),
211		}
212}
213
214func parseEncryptions(t *testing.T, encs []encryptionString) []encryptionVector {
215	t.Helper()
216
217	var res []encryptionVector
218	for _, e := range encs {
219		var plaintext, associatedData, nonce, ciphertext []byte
220		var err error
221		if plaintext, err = hex.DecodeString(e.plaintext); err != nil {
222			t.Fatalf("hex.DecodeString(plaintext): err %q", err)
223		}
224		if associatedData, err = hex.DecodeString(e.associatedData); err != nil {
225			t.Fatalf("hex.DecodeString(associatedData): err %q", err)
226		}
227		if nonce, err = hex.DecodeString(e.nonce); err != nil {
228			t.Fatalf("hex.DecodeString(nonce): err %q", err)
229		}
230		if ciphertext, err = hex.DecodeString(e.ciphertext); err != nil {
231			t.Fatalf("hex.DecodeString(ciphertext): err %q", err)
232		}
233
234		res = append(res, encryptionVector{
235			plaintext:      plaintext,
236			associatedData: associatedData,
237			nonce:          nonce,
238			ciphertext:     ciphertext,
239			sequenceNumber: big.NewInt(int64(e.sequenceNumber)),
240		})
241	}
242
243	return res
244}
245
246// aeadRFCVectors returns RFC test vectors for AEAD IDs aes128GCM, aes256GCM,
247// and chaCha20Poly1305.
248func aeadRFCVectors(t *testing.T) map[hpkeID]encryptionVector {
249	t.Helper()
250
251	vecs := []struct {
252		mode                                              uint8
253		kemID, kdfID, aeadID                              uint16
254		key, plaintext, associatedData, nonce, ciphertext string
255	}{
256		// https://www.rfc-editor.org/rfc/rfc9180.html#appendix-A.1.1.1
257		{
258			mode:           0,
259			kemID:          32,
260			kdfID:          1,
261			aeadID:         1,
262			key:            "4531685d41d65f03dc48f6b8302c05b0",
263			plaintext:      "4265617574792069732074727574682c20747275746820626561757479",
264			associatedData: "436f756e742d30",
265			nonce:          "56d890e5accaaf011cff4b7d",
266			ciphertext:     "f938558b5d72f1a23810b4be2ab4f84331acc02fc97babc53a52ae8218a355a96d8770ac83d07bea87e13c512a",
267		},
268		{
269			mode:           0,
270			kemID:          32,
271			kdfID:          1,
272			aeadID:         1,
273			key:            "4531685d41d65f03dc48f6b8302c05b0",
274			plaintext:      "4265617574792069732074727574682c20747275746820626561757479",
275			associatedData: "436f756e742d31",
276			nonce:          "56d890e5accaaf011cff4b7c",
277			ciphertext:     "af2d7e9ac9ae7e270f46ba1f975be53c09f8d875bdc8535458c2494e8a6eab251c03d0c22a56b8ca42c2063b84",
278		},
279		// https://www.rfc-editor.org/rfc/rfc9180.html#appendix-A.6.1.1
280		{
281			mode:           0,
282			kemID:          18,
283			kdfID:          3,
284			aeadID:         2,
285			key:            "751e346ce8f0ddb2305c8a2a85c70d5cf559c53093656be636b9406d4d7d1b70",
286			plaintext:      "4265617574792069732074727574682c20747275746820626561757479",
287			associatedData: "436f756e742d30",
288			nonce:          "55ff7a7d739c69f44b25447b",
289			ciphertext:     "170f8beddfe949b75ef9c387e201baf4132fa7374593dfafa90768788b7b2b200aafcc6d80ea4c795a7c5b841a",
290		},
291		{
292			mode:           0,
293			kemID:          18,
294			kdfID:          3,
295			aeadID:         2,
296			key:            "751e346ce8f0ddb2305c8a2a85c70d5cf559c53093656be636b9406d4d7d1b70",
297			plaintext:      "4265617574792069732074727574682c20747275746820626561757479",
298			associatedData: "436f756e742d31",
299			nonce:          "55ff7a7d739c69f44b25447a",
300			ciphertext:     "d9ee248e220ca24ac00bbbe7e221a832e4f7fa64c4fbab3945b6f3af0c5ecd5e16815b328be4954a05fd352256",
301		},
302		// https://www.rfc-editor.org/rfc/rfc9180.html#appendix-A.2.1.1
303		{
304			mode:           0,
305			kemID:          32,
306			kdfID:          1,
307			aeadID:         3,
308			key:            "ad2744de8e17f4ebba575b3f5f5a8fa1f69c2a07f6e7500bc60ca6e3e3ec1c91",
309			plaintext:      "4265617574792069732074727574682c20747275746820626561757479",
310			associatedData: "436f756e742d30",
311			nonce:          "5c4d98150661b848853b547f",
312			ciphertext:     "1c5250d8034ec2b784ba2cfd69dbdb8af406cfe3ff938e131f0def8c8b60b4db21993c62ce81883d2dd1b51a28",
313		},
314		{
315			mode:           0,
316			kemID:          32,
317			kdfID:          1,
318			aeadID:         3,
319			key:            "ad2744de8e17f4ebba575b3f5f5a8fa1f69c2a07f6e7500bc60ca6e3e3ec1c91",
320			plaintext:      "4265617574792069732074727574682c20747275746820626561757479",
321			associatedData: "436f756e742d31",
322			nonce:          "5c4d98150661b848853b547e",
323			ciphertext:     "6b53c051e4199c518de79594e1c4ab18b96f081549d45ce015be002090bb119e85285337cc95ba5f59992dc98c",
324		},
325	}
326
327	m := make(map[hpkeID]encryptionVector)
328	for i, v := range vecs {
329		var key, plaintext, associatedData, nonce, ciphertext []byte
330		var err error
331		if key, err = hex.DecodeString(v.key); err != nil {
332			t.Fatalf("hex.DecodeString(key): err %q", err)
333		}
334		if plaintext, err = hex.DecodeString(v.plaintext); err != nil {
335			t.Fatalf("hex.DecodeString(plaintext): err %q", err)
336		}
337		if associatedData, err = hex.DecodeString(v.associatedData); err != nil {
338			t.Fatalf("hex.DecodeString(associatedData): err %q", err)
339		}
340		if nonce, err = hex.DecodeString(v.nonce); err != nil {
341			t.Fatalf("hex.DecodeString(nonce): err %q", err)
342		}
343		if ciphertext, err = hex.DecodeString(v.ciphertext); err != nil {
344			t.Fatalf("hex.DecodeString(ciphertext): err %q", err)
345		}
346
347		id := hpkeID{i, v.mode, v.kemID, v.kdfID, v.aeadID}
348		m[id] = encryptionVector{
349			key:            key,
350			plaintext:      plaintext,
351			associatedData: associatedData,
352			nonce:          nonce,
353			ciphertext:     ciphertext,
354		}
355	}
356
357	return m
358}
359
360// baseModeX25519HKDFSHA256Vectors returns BoringSSL test vectors for HPKE base
361// mode with Diffie-Hellman-based X25519, HKDF-SHA256 KEM as per
362// https://www.rfc-editor.org/rfc/rfc9180.html#section-7.1.
363func baseModeX25519HKDFSHA256Vectors(t *testing.T) map[hpkeID]vector {
364	testutil.SkipTestIfTestSrcDirIsNotSet(t)
365	t.Helper()
366
367	srcDir, _ := os.LookupEnv("TEST_SRCDIR")
368	path := filepath.Join(srcDir, os.Getenv("TEST_WORKSPACE"), "/testdata/testvectors/hpke_boringssl.json")
369	f, err := os.Open(path)
370	if err != nil {
371		t.Fatal(err)
372	}
373
374	var vecs []struct {
375		Mode             uint8             `json:"mode"`
376		KEMID            uint16            `json:"kem_id"`
377		KDFID            uint16            `json:"kdf_id"`
378		AEADID           uint16            `json:"aead_id"`
379		Info             testutil.HexBytes `json:"info"`
380		SenderPubKey     testutil.HexBytes `json:"pkEm"`
381		SenderPrivKey    testutil.HexBytes `json:"skEm"`
382		RecipientPubKey  testutil.HexBytes `json:"pkRm"`
383		RecipientPrivKey testutil.HexBytes `json:"skRm"`
384		EncapsulatedKey  testutil.HexBytes `json:"enc"`
385		SharedSecret     testutil.HexBytes `json:"shared_secret"`
386		KeyScheduleCtx   testutil.HexBytes `json:"key_schedule_context"`
387		Secret           testutil.HexBytes `json:"secret"`
388		Key              testutil.HexBytes `json:"key"`
389		BaseNonce        testutil.HexBytes `json:"base_nonce"`
390	}
391	parser := json.NewDecoder(f)
392	if err := parser.Decode(&vecs); err != nil {
393		t.Fatal(err)
394	}
395
396	m := make(map[hpkeID]vector)
397	for i, v := range vecs {
398		if v.Mode != baseMode || v.KEMID != x25519HKDFSHA256 {
399			continue
400		}
401
402		id := hpkeID{i, v.Mode, v.KEMID, v.KDFID, v.AEADID}
403		m[id] = vector{
404			info:             v.Info,
405			senderPubKey:     v.SenderPubKey,
406			senderPrivKey:    v.SenderPrivKey,
407			recipientPubKey:  v.RecipientPubKey,
408			recipientPrivKey: v.RecipientPrivKey,
409			encapsulatedKey:  v.EncapsulatedKey,
410			sharedSecret:     v.SharedSecret,
411			keyScheduleCtx:   v.KeyScheduleCtx,
412			secret:           v.Secret,
413			key:              v.Key,
414			baseNonce:        v.BaseNonce,
415		}
416	}
417
418	return m
419}
420
421func TestHpkeSuiteIDMemoryAllocatedIsExact(t *testing.T) {
422	suiteID := hpkeSuiteID(1, 2, 3)
423	if len(suiteID) != cap(suiteID) {
424		t.Errorf("want len(suiteID) == cap(suiteID), got %d != %d", len(suiteID), cap(suiteID))
425	}
426}
427
428func TestKeyScheduleContextMemoryAllocatedIsExact(t *testing.T) {
429	context := keyScheduleContext(1, []byte{1, 2, 3}, []byte{1, 2, 3, 4, 5})
430	if len(context) != cap(context) {
431		t.Errorf("want len(context) == cap(context), got %d != %d", len(context), cap(context))
432	}
433}
434
435func TestLabelIKMMemoryAllocatedIsExact(t *testing.T) {
436	ikm := labelIKM("abcde", []byte{1, 2, 3}, []byte{1, 2, 3, 4, 5})
437	if len(ikm) != cap(ikm) {
438		t.Errorf("want len(ikm) == cap(ikm), got %d != %d", len(ikm), cap(ikm))
439	}
440}
441
442func TestLabelInfoMemoryAllocatedIsExact(t *testing.T) {
443	info, err := labelInfo("abcde", []byte{1, 2, 3}, []byte{1, 2, 3, 4, 5}, 42)
444	if err != nil {
445		t.Errorf("labelInfo() err = %v, want nil", err)
446	}
447	if len(info) != cap(info) {
448		t.Errorf("want len(info) == cap(info), got %d != %d", len(info), cap(info))
449	}
450}
451