xref: /aosp_15_r20/external/tink/go/hybrid/internal/hpke/hpke.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1// Copyright 2021 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
17// Package hpke provides implementations of Hybrid Public Key Encryption.
18package hpke
19
20import (
21	"encoding/binary"
22	"fmt"
23)
24
25const (
26	// All identifier values are specified in
27	// https://www.rfc-editor.org/rfc/rfc9180.html.
28	// Mode identifiers.
29	baseMode uint8 = 0x00
30
31	// KEM algorithm identifiers.
32	x25519HKDFSHA256 uint16 = 0x0020
33
34	// KDF algorithm identifiers.
35	hkdfSHA256 uint16 = 0x0001
36
37	// AEAD algorithm identifiers.
38	aes128GCM        uint16 = 0x0001
39	aes256GCM        uint16 = 0x0002
40	chaCha20Poly1305 uint16 = 0x0003
41
42	sha256 = "SHA256"
43	hpkeV1 = "HPKE-v1"
44)
45
46var (
47	emptySalt           = []byte{}
48	emptyIKM            = []byte{}
49	emptyAssociatedData = []byte{}
50)
51
52// kemSuiteID generates the KEM suite ID from kemID according to
53// https://www.rfc-editor.org/rfc/rfc9180.html#section-4.1-5.
54func kemSuiteID(kemID uint16) []byte {
55	return binary.BigEndian.AppendUint16([]byte("KEM"), kemID)
56}
57
58// hpkeSuiteID generates the HPKE suite ID according to
59// https://www.rfc-editor.org/rfc/rfc9180.html#section-5.1-8.
60func hpkeSuiteID(kemID, kdfID, aeadID uint16) []byte {
61	// Allocate memory for the return value with the exact amount of bytes needed.
62	res := make([]byte, 0, 4+2+2+2)
63	res = append(res, "HPKE"...)
64	res = binary.BigEndian.AppendUint16(res, kemID)
65	res = binary.BigEndian.AppendUint16(res, kdfID)
66	res = binary.BigEndian.AppendUint16(res, aeadID)
67	return res
68}
69
70// keyScheduleContext creates the key_schedule_context defined at
71// https://www.rfc-editor.org/rfc/rfc9180.html#section-5.1-10.
72func keyScheduleContext(mode uint8, pskIDHash, infoHash []byte) []byte {
73	// Allocate memory for the return value with the exact amount of bytes needed.
74	res := make([]byte, 0, 1+len(pskIDHash)+len(infoHash))
75	res = append(res, mode)
76	res = append(res, pskIDHash...)
77	res = append(res, infoHash...)
78	return res
79}
80
81// labelIKM returns a labeled IKM according to LabeledExtract() defined at
82// https://www.rfc-editor.org/rfc/rfc9180.html#section-4.
83func labelIKM(label string, ikm, suiteID []byte) []byte {
84	// Allocate memory for the return value with the exact amount of bytes needed.
85	res := make([]byte, 0, len(hpkeV1)+len(suiteID)+len(label)+len(ikm))
86	res = append(res, hpkeV1...)
87	res = append(res, suiteID...)
88	res = append(res, label...)
89	res = append(res, ikm...)
90	return res
91}
92
93// labelInfo returns a labeled info according to LabeledExpand() defined at
94// https://www.rfc-editor.org/rfc/rfc9180.html#section-4.
95func labelInfo(label string, info, suiteID []byte, length int) ([]byte, error) {
96	length16 := uint16(length)
97	if int(length16) != length {
98		return nil, fmt.Errorf("length %d must be a valid uint16 value", length)
99	}
100
101	// Allocate memory for the return value with the exact amount of bytes needed.
102	res := make([]byte, 0, 2+len(hpkeV1)+len(suiteID)+len(label)+len(info))
103	res = binary.BigEndian.AppendUint16(res, length16)
104	res = append(res, hpkeV1...)
105	res = append(res, suiteID...)
106	res = append(res, label...)
107	res = append(res, info...)
108	return res, nil
109}
110