crypto/hpke: expose crypto/internal/hpke

Fixes #75300

Change-Id: I6a83e0d040dba3366819d2afff704f886a6a6964
Reviewed-on: https://go-review.googlesource.com/c/go/+/723560
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Daniel McCarney <daniel@binaryparadox.net>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
TryBot-Bypass: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
This commit is contained in:
Filippo Valsorda 2025-11-22 23:03:14 +01:00 committed by Gopher Robot
parent a5ebc6b67c
commit e3088d6eb8
15 changed files with 84 additions and 23 deletions

View file

@ -10,3 +10,54 @@ pkg crypto/ecdh, type KeyExchanger interface, ECDH(*PublicKey) ([]uint8, error)
pkg crypto/ecdh, type KeyExchanger interface, PublicKey() *PublicKey #75300
pkg crypto/mlkem, method (*DecapsulationKey1024) Encapsulator() crypto.Encapsulator #75300
pkg crypto/mlkem, method (*DecapsulationKey768) Encapsulator() crypto.Encapsulator #75300
pkg crypto/hpke, func AES128GCM() AEAD #75300
pkg crypto/hpke, func AES256GCM() AEAD #75300
pkg crypto/hpke, func ChaCha20Poly1305() AEAD #75300
pkg crypto/hpke, func DHKEM(ecdh.Curve) KEM #75300
pkg crypto/hpke, func ExportOnly() AEAD #75300
pkg crypto/hpke, func HKDFSHA256() KDF #75300
pkg crypto/hpke, func HKDFSHA384() KDF #75300
pkg crypto/hpke, func HKDFSHA512() KDF #75300
pkg crypto/hpke, func MLKEM1024() KEM #75300
pkg crypto/hpke, func MLKEM1024P384() KEM #75300
pkg crypto/hpke, func MLKEM768() KEM #75300
pkg crypto/hpke, func MLKEM768P256() KEM #75300
pkg crypto/hpke, func MLKEM768X25519() KEM #75300
pkg crypto/hpke, func NewAEAD(uint16) (AEAD, error) #75300
pkg crypto/hpke, func NewDHKEMPrivateKey(ecdh.KeyExchanger) (PrivateKey, error) #75300
pkg crypto/hpke, func NewDHKEMPublicKey(*ecdh.PublicKey) (PublicKey, error) #75300
pkg crypto/hpke, func NewHybridPrivateKey(crypto.Decapsulator, ecdh.KeyExchanger) (PrivateKey, error) #75300
pkg crypto/hpke, func NewHybridPublicKey(crypto.Encapsulator, *ecdh.PublicKey) (PublicKey, error) #75300
pkg crypto/hpke, func NewKDF(uint16) (KDF, error) #75300
pkg crypto/hpke, func NewKEM(uint16) (KEM, error) #75300
pkg crypto/hpke, func NewMLKEMPrivateKey(crypto.Decapsulator) (PrivateKey, error) #75300
pkg crypto/hpke, func NewMLKEMPublicKey(crypto.Encapsulator) (PublicKey, error) #75300
pkg crypto/hpke, func NewRecipient([]uint8, PrivateKey, KDF, AEAD, []uint8) (*Recipient, error) #75300
pkg crypto/hpke, func NewSender(PublicKey, KDF, AEAD, []uint8) ([]uint8, *Sender, error) #75300
pkg crypto/hpke, func Open(PrivateKey, KDF, AEAD, []uint8, []uint8) ([]uint8, error) #75300
pkg crypto/hpke, func SHAKE128() KDF #75300
pkg crypto/hpke, func SHAKE256() KDF #75300
pkg crypto/hpke, func Seal(PublicKey, KDF, AEAD, []uint8, []uint8) ([]uint8, error) #75300
pkg crypto/hpke, method (*Recipient) Export(string, int) ([]uint8, error) #75300
pkg crypto/hpke, method (*Recipient) Open([]uint8, []uint8) ([]uint8, error) #75300
pkg crypto/hpke, method (*Sender) Export(string, int) ([]uint8, error) #75300
pkg crypto/hpke, method (*Sender) Seal([]uint8, []uint8) ([]uint8, error) #75300
pkg crypto/hpke, type AEAD interface, ID() uint16 #75300
pkg crypto/hpke, type AEAD interface, unexported methods #75300
pkg crypto/hpke, type KDF interface, ID() uint16 #75300
pkg crypto/hpke, type KDF interface, unexported methods #75300
pkg crypto/hpke, type KEM interface, DeriveKeyPair([]uint8) (PrivateKey, error) #75300
pkg crypto/hpke, type KEM interface, GenerateKey() (PrivateKey, error) #75300
pkg crypto/hpke, type KEM interface, ID() uint16 #75300
pkg crypto/hpke, type KEM interface, NewPrivateKey([]uint8) (PrivateKey, error) #75300
pkg crypto/hpke, type KEM interface, NewPublicKey([]uint8) (PublicKey, error) #75300
pkg crypto/hpke, type KEM interface, unexported methods #75300
pkg crypto/hpke, type PrivateKey interface, Bytes() ([]uint8, error) #75300
pkg crypto/hpke, type PrivateKey interface, KEM() KEM #75300
pkg crypto/hpke, type PrivateKey interface, PublicKey() PublicKey #75300
pkg crypto/hpke, type PrivateKey interface, unexported methods #75300
pkg crypto/hpke, type PublicKey interface, Bytes() []uint8 #75300
pkg crypto/hpke, type PublicKey interface, KEM() KEM #75300
pkg crypto/hpke, type PublicKey interface, unexported methods #75300
pkg crypto/hpke, type Recipient struct #75300
pkg crypto/hpke, type Sender struct #75300

View file

@ -0,0 +1,7 @@
### crypto/hpke
The new [crypto/hpke] package implements Hybrid Public Key Encryption
(HPKE) as specified in [RFC 9180], including support for post-quantum
hybrid KEMs.
[RFC 9180]: https://rfc-editor.org/rfc/rfc9180.html

View file

@ -0,0 +1 @@
<!-- crypto/hpke is documented in its own section. -->

View file

@ -10,8 +10,8 @@ package hpke
import (
"crypto/cipher"
"encoding/binary"
"errors"
"internal/byteorder"
)
type context struct {
@ -45,14 +45,14 @@ func newContext(sharedSecret []byte, kemID uint16, kdf KDF, aead AEAD, info []by
if kdf.oneStage() {
secrets := make([]byte, 0, 2+2+len(sharedSecret))
secrets = binary.BigEndian.AppendUint16(secrets, 0) // empty psk
secrets = binary.BigEndian.AppendUint16(secrets, uint16(len(sharedSecret)))
secrets = byteorder.BEAppendUint16(secrets, 0) // empty psk
secrets = byteorder.BEAppendUint16(secrets, uint16(len(sharedSecret)))
secrets = append(secrets, sharedSecret...)
ksContext := make([]byte, 0, 1+2+2+len(info))
ksContext = append(ksContext, 0) // mode 0
ksContext = binary.BigEndian.AppendUint16(ksContext, 0) // empty psk_id
ksContext = binary.BigEndian.AppendUint16(ksContext, uint16(len(info)))
ksContext = append(ksContext, 0) // mode 0
ksContext = byteorder.BEAppendUint16(ksContext, 0) // empty psk_id
ksContext = byteorder.BEAppendUint16(ksContext, uint16(len(info)))
ksContext = append(ksContext, info...)
secret, err := kdf.labeledDerive(sid, secrets, "secret", ksContext,
@ -245,7 +245,7 @@ func (r *Recipient) Export(exporterContext string, length int) ([]byte, error) {
func (ctx *context) nextNonce() []byte {
nonce := make([]byte, ctx.aead.NonceSize())
binary.BigEndian.PutUint64(nonce[len(nonce)-8:], ctx.seqNum)
byteorder.BEPutUint64(nonce[len(nonce)-8:], ctx.seqNum)
for i := range ctx.baseNonce {
nonce[i] ^= ctx.baseNonce[i]
}
@ -255,8 +255,8 @@ func (ctx *context) nextNonce() []byte {
func suiteID(kemID, kdfID, aeadID uint16) []byte {
suiteID := make([]byte, 0, 4+2+2+2)
suiteID = append(suiteID, []byte("HPKE")...)
suiteID = binary.BigEndian.AppendUint16(suiteID, kemID)
suiteID = binary.BigEndian.AppendUint16(suiteID, kdfID)
suiteID = binary.BigEndian.AppendUint16(suiteID, aeadID)
suiteID = byteorder.BEAppendUint16(suiteID, kemID)
suiteID = byteorder.BEAppendUint16(suiteID, kdfID)
suiteID = byteorder.BEAppendUint16(suiteID, aeadID)
return suiteID
}

View file

@ -9,10 +9,10 @@ import (
"crypto/sha256"
"crypto/sha3"
"crypto/sha512"
"encoding/binary"
"errors"
"fmt"
"hash"
"internal/byteorder"
)
// The KDF is one of the three components of an HPKE ciphersuite, implementing
@ -93,7 +93,7 @@ func (kdf *hkdfKDF) labeledExtract(suiteID []byte, salt []byte, label string, in
func (kdf *hkdfKDF) labeledExpand(suiteID []byte, randomKey []byte, label string, info []byte, length uint16) ([]byte, error) {
labeledInfo := make([]byte, 0, 2+7+len(suiteID)+len(label)+len(info))
labeledInfo = binary.BigEndian.AppendUint16(labeledInfo, length)
labeledInfo = byteorder.BEAppendUint16(labeledInfo, length)
labeledInfo = append(labeledInfo, []byte("HPKE-v1")...)
labeledInfo = append(labeledInfo, suiteID...)
labeledInfo = append(labeledInfo, label...)

View file

@ -7,8 +7,8 @@ package hpke
import (
"crypto/ecdh"
"crypto/rand"
"encoding/binary"
"errors"
"internal/byteorder"
)
// A KEM is a Key Encapsulation Mechanism, one of the three components of an
@ -114,7 +114,7 @@ type dhKEM struct {
}
func (kem *dhKEM) extractAndExpand(dhKey, kemContext []byte) ([]byte, error) {
suiteID := binary.BigEndian.AppendUint16([]byte("KEM"), kem.id)
suiteID := byteorder.BEAppendUint16([]byte("KEM"), kem.id)
eaePRK, err := kem.kdf.labeledExtract(suiteID, nil, "eae_prk", dhKey)
if err != nil {
return nil, err
@ -302,7 +302,7 @@ func (kem *dhKEM) NewPrivateKey(ikm []byte) (PrivateKey, error) {
func (kem *dhKEM) DeriveKeyPair(ikm []byte) (PrivateKey, error) {
// DeriveKeyPair from RFC 9180 Section 7.1.3.
suiteID := binary.BigEndian.AppendUint16([]byte("KEM"), kem.id)
suiteID := byteorder.BEAppendUint16([]byte("KEM"), kem.id)
prk, err := kem.kdf.labeledExtract(suiteID, nil, "dkp_prk", ikm)
if err != nil {
return nil, err

View file

@ -11,8 +11,8 @@ import (
"crypto/mlkem"
"crypto/rand"
"crypto/sha3"
"encoding/binary"
"errors"
"internal/byteorder"
)
var mlkem768X25519 = &hybridKEM{
@ -299,7 +299,7 @@ func newHybridPrivateKey(pq crypto.Decapsulator, t ecdh.KeyExchanger, seed []byt
}
func (kem *hybridKEM) DeriveKeyPair(ikm []byte) (PrivateKey, error) {
suiteID := binary.BigEndian.AppendUint16([]byte("KEM"), kem.id)
suiteID := byteorder.BEAppendUint16([]byte("KEM"), kem.id)
dk, err := SHAKE256().labeledDerive(suiteID, ikm, "DeriveKeyPair", nil, 32)
if err != nil {
return nil, err
@ -496,7 +496,7 @@ func (kem *mlkemKEM) NewPrivateKey(priv []byte) (PrivateKey, error) {
}
func (kem *mlkemKEM) DeriveKeyPair(ikm []byte) (PrivateKey, error) {
suiteID := binary.BigEndian.AppendUint16([]byte("KEM"), kem.id)
suiteID := byteorder.BEAppendUint16([]byte("KEM"), kem.id)
dk, err := SHAKE256().labeledDerive(suiteID, ikm, "DeriveKeyPair", nil, 64)
if err != nil {
return nil, err

View file

@ -6,7 +6,7 @@ package tls
import (
"bytes"
"crypto/internal/hpke"
"crypto/hpke"
"errors"
"fmt"
"strings"

View file

@ -10,9 +10,9 @@ import (
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/hpke"
"crypto/internal/fips140/mlkem"
"crypto/internal/fips140/tls13"
"crypto/internal/hpke"
"crypto/rsa"
"crypto/subtle"
"crypto/tls/internal/fips140tls"

View file

@ -10,9 +10,9 @@ import (
"crypto"
"crypto/hkdf"
"crypto/hmac"
"crypto/hpke"
"crypto/internal/fips140/mlkem"
"crypto/internal/fips140/tls13"
"crypto/internal/hpke"
"crypto/rsa"
"crypto/tls/internal/fips140tls"
"errors"

View file

@ -604,9 +604,11 @@ var depsRules = `
< golang.org/x/crypto/internal/poly1305
< golang.org/x/crypto/chacha20poly1305;
CRYPTO-MATH, NET, container/list, encoding/hex, encoding/pem,
CRYPTO-MATH, golang.org/x/crypto/chacha20poly1305
< crypto/hpke;
CRYPTO-MATH, NET, container/list, encoding/hex, encoding/pem, crypto/hpke,
golang.org/x/crypto/chacha20poly1305, crypto/tls/internal/fips140tls
< crypto/internal/hpke
< crypto/x509/internal/macos
< crypto/x509/pkix
< crypto/x509