github.com/ooni/psiphon/tunnel-core@v0.0.0-20230105123940-fe12a24c96ee/oovendor/quic-go/internal/handshake/aead.go (about)

     1  package handshake
     2  
     3  import (
     4  	"crypto/cipher"
     5  	"encoding/binary"
     6  
     7  	"github.com/ooni/psiphon/tunnel-core/oovendor/quic-go/internal/protocol"
     8  	"github.com/ooni/psiphon/tunnel-core/oovendor/quic-go/internal/qtls"
     9  	"github.com/ooni/psiphon/tunnel-core/oovendor/quic-go/internal/utils"
    10  )
    11  
    12  func createAEAD(suite *qtls.CipherSuiteTLS13, trafficSecret []byte) cipher.AEAD {
    13  	key := hkdfExpandLabel(suite.Hash, trafficSecret, []byte{}, "quic key", suite.KeyLen)
    14  	iv := hkdfExpandLabel(suite.Hash, trafficSecret, []byte{}, "quic iv", suite.IVLen())
    15  	return suite.AEAD(key, iv)
    16  }
    17  
    18  type longHeaderSealer struct {
    19  	aead            cipher.AEAD
    20  	headerProtector headerProtector
    21  
    22  	// use a single slice to avoid allocations
    23  	nonceBuf []byte
    24  }
    25  
    26  var _ LongHeaderSealer = &longHeaderSealer{}
    27  
    28  func newLongHeaderSealer(aead cipher.AEAD, headerProtector headerProtector) LongHeaderSealer {
    29  	return &longHeaderSealer{
    30  		aead:            aead,
    31  		headerProtector: headerProtector,
    32  		nonceBuf:        make([]byte, aead.NonceSize()),
    33  	}
    34  }
    35  
    36  func (s *longHeaderSealer) Seal(dst, src []byte, pn protocol.PacketNumber, ad []byte) []byte {
    37  	binary.BigEndian.PutUint64(s.nonceBuf[len(s.nonceBuf)-8:], uint64(pn))
    38  	// The AEAD we're using here will be the qtls.aeadAESGCM13.
    39  	// It uses the nonce provided here and XOR it with the IV.
    40  	return s.aead.Seal(dst, s.nonceBuf, src, ad)
    41  }
    42  
    43  func (s *longHeaderSealer) EncryptHeader(sample []byte, firstByte *byte, pnBytes []byte) {
    44  	s.headerProtector.EncryptHeader(sample, firstByte, pnBytes)
    45  }
    46  
    47  func (s *longHeaderSealer) Overhead() int {
    48  	return s.aead.Overhead()
    49  }
    50  
    51  type longHeaderOpener struct {
    52  	aead            cipher.AEAD
    53  	headerProtector headerProtector
    54  	highestRcvdPN   protocol.PacketNumber // highest packet number received (which could be successfully unprotected)
    55  
    56  	// use a single slice to avoid allocations
    57  	nonceBuf []byte
    58  }
    59  
    60  var _ LongHeaderOpener = &longHeaderOpener{}
    61  
    62  func newLongHeaderOpener(aead cipher.AEAD, headerProtector headerProtector) LongHeaderOpener {
    63  	return &longHeaderOpener{
    64  		aead:            aead,
    65  		headerProtector: headerProtector,
    66  		nonceBuf:        make([]byte, aead.NonceSize()),
    67  	}
    68  }
    69  
    70  func (o *longHeaderOpener) DecodePacketNumber(wirePN protocol.PacketNumber, wirePNLen protocol.PacketNumberLen) protocol.PacketNumber {
    71  	return protocol.DecodePacketNumber(wirePNLen, o.highestRcvdPN, wirePN)
    72  }
    73  
    74  func (o *longHeaderOpener) Open(dst, src []byte, pn protocol.PacketNumber, ad []byte) ([]byte, error) {
    75  	binary.BigEndian.PutUint64(o.nonceBuf[len(o.nonceBuf)-8:], uint64(pn))
    76  	// The AEAD we're using here will be the qtls.aeadAESGCM13.
    77  	// It uses the nonce provided here and XOR it with the IV.
    78  	dec, err := o.aead.Open(dst, o.nonceBuf, src, ad)
    79  	if err == nil {
    80  		o.highestRcvdPN = utils.MaxPacketNumber(o.highestRcvdPN, pn)
    81  	} else {
    82  		err = ErrDecryptionFailed
    83  	}
    84  	return dec, err
    85  }
    86  
    87  func (o *longHeaderOpener) DecryptHeader(sample []byte, firstByte *byte, pnBytes []byte) {
    88  	o.headerProtector.DecryptHeader(sample, firstByte, pnBytes)
    89  }
    90  
    91  type handshakeSealer struct {
    92  	LongHeaderSealer
    93  
    94  	dropInitialKeys func()
    95  	dropped         bool
    96  }
    97  
    98  func newHandshakeSealer(
    99  	aead cipher.AEAD,
   100  	headerProtector headerProtector,
   101  	dropInitialKeys func(),
   102  	perspective protocol.Perspective,
   103  ) LongHeaderSealer {
   104  	sealer := newLongHeaderSealer(aead, headerProtector)
   105  	// The client drops Initial keys when sending the first Handshake packet.
   106  	if perspective == protocol.PerspectiveServer {
   107  		return sealer
   108  	}
   109  	return &handshakeSealer{
   110  		LongHeaderSealer: sealer,
   111  		dropInitialKeys:  dropInitialKeys,
   112  	}
   113  }
   114  
   115  func (s *handshakeSealer) Seal(dst, src []byte, pn protocol.PacketNumber, ad []byte) []byte {
   116  	data := s.LongHeaderSealer.Seal(dst, src, pn, ad)
   117  	if !s.dropped {
   118  		s.dropInitialKeys()
   119  		s.dropped = true
   120  	}
   121  	return data
   122  }
   123  
   124  type handshakeOpener struct {
   125  	LongHeaderOpener
   126  
   127  	dropInitialKeys func()
   128  	dropped         bool
   129  }
   130  
   131  func newHandshakeOpener(
   132  	aead cipher.AEAD,
   133  	headerProtector headerProtector,
   134  	dropInitialKeys func(),
   135  	perspective protocol.Perspective,
   136  ) LongHeaderOpener {
   137  	opener := newLongHeaderOpener(aead, headerProtector)
   138  	// The server drops Initial keys when first successfully processing a Handshake packet.
   139  	if perspective == protocol.PerspectiveClient {
   140  		return opener
   141  	}
   142  	return &handshakeOpener{
   143  		LongHeaderOpener: opener,
   144  		dropInitialKeys:  dropInitialKeys,
   145  	}
   146  }
   147  
   148  func (o *handshakeOpener) Open(dst, src []byte, pn protocol.PacketNumber, ad []byte) ([]byte, error) {
   149  	dec, err := o.LongHeaderOpener.Open(dst, src, pn, ad)
   150  	if err == nil && !o.dropped {
   151  		o.dropInitialKeys()
   152  		o.dropped = true
   153  	}
   154  	return dec, err
   155  }