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 }