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