Skip to content

Commit

Permalink
handshake: optimize AEAD handling for long header sealers and openers (
Browse files Browse the repository at this point in the history
  • Loading branch information
marten-seemann committed Mar 3, 2024
1 parent f856163 commit 71f5ae5
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 26 deletions.
39 changes: 18 additions & 21 deletions internal/handshake/aead.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package handshake

import (
"crypto/cipher"
"encoding/binary"

"github.com/quic-go/quic-go/internal/protocol"
)

func createAEAD(suite *cipherSuite, trafficSecret []byte, v protocol.Version) cipher.AEAD {
func createAEAD(suite *cipherSuite, trafficSecret []byte, v protocol.Version) *xorNonceAEAD {
keyLabel := hkdfLabelKeyV1
ivLabel := hkdfLabelIVV1
if v == protocol.Version2 {
Expand All @@ -20,28 +19,26 @@ func createAEAD(suite *cipherSuite, trafficSecret []byte, v protocol.Version) ci
}

type longHeaderSealer struct {
aead cipher.AEAD
aead *xorNonceAEAD
headerProtector headerProtector

// use a single slice to avoid allocations
nonceBuf []byte
nonceBuf [8]byte
}

var _ LongHeaderSealer = &longHeaderSealer{}

func newLongHeaderSealer(aead cipher.AEAD, headerProtector headerProtector) LongHeaderSealer {
func newLongHeaderSealer(aead *xorNonceAEAD, headerProtector headerProtector) LongHeaderSealer {
if aead.NonceSize() != 8 {
panic("unexpected nonce size")
}
return &longHeaderSealer{
aead: aead,
headerProtector: headerProtector,
nonceBuf: make([]byte, aead.NonceSize()),
}
}

func (s *longHeaderSealer) Seal(dst, src []byte, pn protocol.PacketNumber, ad []byte) []byte {
binary.BigEndian.PutUint64(s.nonceBuf[len(s.nonceBuf)-8:], uint64(pn))
// The AEAD we're using here will be the qtls.aeadAESGCM13.
// It uses the nonce provided here and XOR it with the IV.
return s.aead.Seal(dst, s.nonceBuf, src, ad)
binary.BigEndian.PutUint64(s.nonceBuf[:], uint64(pn))
return s.aead.Seal(dst, s.nonceBuf[:], src, ad)
}

func (s *longHeaderSealer) EncryptHeader(sample []byte, firstByte *byte, pnBytes []byte) {
Expand All @@ -53,21 +50,23 @@ func (s *longHeaderSealer) Overhead() int {
}

type longHeaderOpener struct {
aead cipher.AEAD
aead *xorNonceAEAD
headerProtector headerProtector
highestRcvdPN protocol.PacketNumber // highest packet number received (which could be successfully unprotected)

// use a single slice to avoid allocations
nonceBuf []byte
// use a single array to avoid allocations
nonceBuf [8]byte
}

var _ LongHeaderOpener = &longHeaderOpener{}

func newLongHeaderOpener(aead cipher.AEAD, headerProtector headerProtector) LongHeaderOpener {
func newLongHeaderOpener(aead *xorNonceAEAD, headerProtector headerProtector) LongHeaderOpener {
if aead.NonceSize() != 8 {
panic("unexpected nonce size")
}
return &longHeaderOpener{
aead: aead,
headerProtector: headerProtector,
nonceBuf: make([]byte, aead.NonceSize()),
}
}

Expand All @@ -76,10 +75,8 @@ func (o *longHeaderOpener) DecodePacketNumber(wirePN protocol.PacketNumber, wire
}

func (o *longHeaderOpener) Open(dst, src []byte, pn protocol.PacketNumber, ad []byte) ([]byte, error) {
binary.BigEndian.PutUint64(o.nonceBuf[len(o.nonceBuf)-8:], uint64(pn))
// The AEAD we're using here will be the qtls.aeadAESGCM13.
// It uses the nonce provided here and XOR it with the IV.
dec, err := o.aead.Open(dst, o.nonceBuf, src, ad)
binary.BigEndian.PutUint64(o.nonceBuf[:], uint64(pn))
dec, err := o.aead.Open(dst, o.nonceBuf[:], src, ad)
if err == nil {
o.highestRcvdPN = max(o.highestRcvdPN, pn)
} else {
Expand Down
4 changes: 2 additions & 2 deletions internal/handshake/aead_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ var _ = Describe("Long Header AEAD", func() {
aead, err := cipher.NewGCM(block)
Expect(err).ToNot(HaveOccurred())

return newLongHeaderSealer(aead, newHeaderProtector(cs, hpKey, true, v)),
newLongHeaderOpener(aead, newHeaderProtector(cs, hpKey, true, v))
return newLongHeaderSealer(&xorNonceAEAD{aead: aead}, newHeaderProtector(cs, hpKey, true, v)),
newLongHeaderOpener(&xorNonceAEAD{aead: aead}, newHeaderProtector(cs, hpKey, true, v))
}

Context("message encryption", func() {
Expand Down
6 changes: 3 additions & 3 deletions internal/handshake/cipher_suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type cipherSuite struct {
ID uint16
Hash crypto.Hash
KeyLen int
AEAD func(key, nonceMask []byte) cipher.AEAD
AEAD func(key, nonceMask []byte) *xorNonceAEAD
}

func (s cipherSuite) IVLen() int { return aeadNonceLength }
Expand All @@ -36,7 +36,7 @@ func getCipherSuite(id uint16) *cipherSuite {
}
}

func aeadAESGCMTLS13(key, nonceMask []byte) cipher.AEAD {
func aeadAESGCMTLS13(key, nonceMask []byte) *xorNonceAEAD {
if len(nonceMask) != aeadNonceLength {
panic("tls: internal error: wrong nonce length")
}
Expand All @@ -54,7 +54,7 @@ func aeadAESGCMTLS13(key, nonceMask []byte) cipher.AEAD {
return ret
}

func aeadChaCha20Poly1305(key, nonceMask []byte) cipher.AEAD {
func aeadChaCha20Poly1305(key, nonceMask []byte) *xorNonceAEAD {
if len(nonceMask) != aeadNonceLength {
panic("tls: internal error: wrong nonce length")
}
Expand Down

0 comments on commit 71f5ae5

Please sign in to comment.