github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/proxy/shadowsocks2022/encoding.go (about) 1 package shadowsocks2022 2 3 import ( 4 "bytes" 5 "crypto/cipher" 6 cryptoRand "crypto/rand" 7 "encoding/binary" 8 "io" 9 "time" 10 11 "github.com/lunixbochs/struc" 12 13 "github.com/v2fly/v2ray-core/v5/common" 14 "github.com/v2fly/v2ray-core/v5/common/buf" 15 "github.com/v2fly/v2ray-core/v5/common/crypto" 16 "github.com/v2fly/v2ray-core/v5/common/dice" 17 "github.com/v2fly/v2ray-core/v5/common/net" 18 "github.com/v2fly/v2ray-core/v5/common/protocol" 19 ) 20 21 type TCPRequest struct { 22 keyDerivation KeyDerivation 23 method Method 24 25 c2sSalt RequestSalt 26 c2sNonce crypto.BytesGenerator 27 c2sAEAD cipher.AEAD 28 29 s2cSalt RequestSalt 30 s2cNonce crypto.BytesGenerator 31 s2cAEAD cipher.AEAD 32 33 s2cSaltAssert RequestSalt 34 s2cInitialPayloadSize int 35 } 36 37 func (t *TCPRequest) EncodeTCPRequestHeader(effectivePsk []byte, 38 eih [][]byte, address DestinationAddress, destPort int, initialPayload []byte, out *buf.Buffer, 39 ) error { 40 requestSalt := newRequestSaltWithLength(t.method.GetSessionSubKeyAndSaltLength()) 41 { 42 err := requestSalt.FillAllFrom(cryptoRand.Reader) 43 if err != nil { 44 return newError("failed to fill salt").Base(err) 45 } 46 } 47 t.c2sSalt = requestSalt 48 sessionKey := make([]byte, t.method.GetSessionSubKeyAndSaltLength()) 49 { 50 err := t.keyDerivation.GetSessionSubKey(effectivePsk, requestSalt.Bytes(), sessionKey) 51 if err != nil { 52 return newError("failed to get session sub key").Base(err) 53 } 54 } 55 56 aead, err := t.method.GetStreamAEAD(sessionKey) 57 if err != nil { 58 return newError("failed to get stream AEAD").Base(err) 59 } 60 t.c2sAEAD = aead 61 paddingLength := TCPMinPaddingLength 62 if initialPayload == nil { 63 initialPayload = []byte{} 64 paddingLength += 1 + dice.RollWith(TCPMaxPaddingLength, cryptoRand.Reader) 65 } 66 67 variableLengthHeader := &TCPRequestHeader3VariableLength{ 68 DestinationAddress: address, 69 Contents: struct { 70 PaddingLength uint16 `struc:"sizeof=Padding"` 71 Padding []byte 72 }(struct { 73 PaddingLength uint16 74 Padding []byte 75 }{ 76 PaddingLength: uint16(paddingLength), 77 Padding: make([]byte, paddingLength), 78 }), 79 } 80 variableLengthHeaderBuffer := buf.New() 81 defer variableLengthHeaderBuffer.Release() 82 { 83 err := addrParser.WriteAddressPort(variableLengthHeaderBuffer, address, net.Port(destPort)) 84 if err != nil { 85 return newError("failed to write address port").Base(err) 86 } 87 } 88 { 89 err := struc.Pack(variableLengthHeaderBuffer, &variableLengthHeader.Contents) 90 if err != nil { 91 return newError("failed to pack variable length header").Base(err) 92 } 93 } 94 { 95 _, err := variableLengthHeaderBuffer.Write(initialPayload) 96 if err != nil { 97 return newError("failed to write initial payload").Base(err) 98 } 99 } 100 101 fixedLengthHeader := &TCPRequestHeader2FixedLength{ 102 Type: TCPHeaderTypeClientToServerStream, 103 Timestamp: uint64(time.Now().Unix()), 104 HeaderLength: uint16(variableLengthHeaderBuffer.Len()), 105 } 106 107 fixedLengthHeaderBuffer := buf.New() 108 defer fixedLengthHeaderBuffer.Release() 109 { 110 err := struc.Pack(fixedLengthHeaderBuffer, fixedLengthHeader) 111 if err != nil { 112 return newError("failed to pack fixed length header").Base(err) 113 } 114 } 115 eihHeader := ExtensibleIdentityHeaders(newAESEIH(0)) 116 if len(eih) != 0 { 117 eihGenerator := newAESEIHGeneratorContainer(len(eih), effectivePsk, eih) 118 eihHeaderGenerated, err := eihGenerator.GenerateEIH(t.keyDerivation, t.method, requestSalt.Bytes()) 119 if err != nil { 120 return newError("failed to construct EIH").Base(err) 121 } 122 eihHeader = eihHeaderGenerated 123 } 124 preSessionKeyHeader := &TCPRequestHeader1PreSessionKey{ 125 Salt: requestSalt, 126 EIH: eihHeader, 127 } 128 preSessionKeyHeaderBuffer := buf.New() 129 defer preSessionKeyHeaderBuffer.Release() 130 { 131 err := struc.Pack(preSessionKeyHeaderBuffer, preSessionKeyHeader) 132 if err != nil { 133 return newError("failed to pack pre session key header").Base(err) 134 } 135 } 136 requestNonce := crypto.GenerateInitialAEADNonce() 137 t.c2sNonce = requestNonce 138 { 139 n, err := out.Write(preSessionKeyHeaderBuffer.BytesFrom(0)) 140 if err != nil { 141 return newError("failed to write pre session key header").Base(err) 142 } 143 if int32(n) != preSessionKeyHeaderBuffer.Len() { 144 return newError("failed to write pre session key header") 145 } 146 } 147 { 148 fixedLengthEncrypted := out.Extend(fixedLengthHeaderBuffer.Len() + int32(aead.Overhead())) 149 aead.Seal(fixedLengthEncrypted[:0], requestNonce(), fixedLengthHeaderBuffer.Bytes(), nil) 150 } 151 { 152 variableLengthEncrypted := out.Extend(variableLengthHeaderBuffer.Len() + int32(aead.Overhead())) 153 aead.Seal(variableLengthEncrypted[:0], requestNonce(), variableLengthHeaderBuffer.Bytes(), nil) 154 } 155 return nil 156 } 157 158 func (t *TCPRequest) DecodeTCPResponseHeader(effectivePsk []byte, in io.Reader) error { 159 var preSessionKeyHeader TCPResponseHeader1PreSessionKey 160 preSessionKeyHeader.Salt = newRequestSaltWithLength(t.method.GetSessionSubKeyAndSaltLength()) 161 { 162 err := struc.Unpack(in, &preSessionKeyHeader) 163 if err != nil { 164 return newError("failed to unpack pre session key header").Base(err) 165 } 166 } 167 s2cSalt := preSessionKeyHeader.Salt.Bytes() 168 t.s2cSalt = preSessionKeyHeader.Salt 169 sessionKey := make([]byte, t.method.GetSessionSubKeyAndSaltLength()) 170 { 171 err := t.keyDerivation.GetSessionSubKey(effectivePsk, s2cSalt, sessionKey) 172 if err != nil { 173 return newError("failed to get session sub key").Base(err) 174 } 175 } 176 aead, err := t.method.GetStreamAEAD(sessionKey) 177 if err != nil { 178 return newError("failed to get stream AEAD").Base(err) 179 } 180 t.s2cAEAD = aead 181 182 fixedLengthHeaderEncryptedBuffer := buf.New() 183 defer fixedLengthHeaderEncryptedBuffer.Release() 184 { 185 _, err := fixedLengthHeaderEncryptedBuffer.ReadFullFrom(in, 11+int32(t.method.GetSessionSubKeyAndSaltLength())+int32(aead.Overhead())) 186 if err != nil { 187 return newError("failed to read fixed length header encrypted").Base(err) 188 } 189 } 190 s2cNonce := crypto.GenerateInitialAEADNonce() 191 t.s2cNonce = s2cNonce 192 fixedLengthHeaderDecryptedBuffer := buf.New() 193 defer fixedLengthHeaderDecryptedBuffer.Release() 194 { 195 decryptionBuffer := fixedLengthHeaderDecryptedBuffer.Extend(11 + int32(t.method.GetSessionSubKeyAndSaltLength())) 196 _, err = aead.Open(decryptionBuffer[:0], s2cNonce(), fixedLengthHeaderEncryptedBuffer.Bytes(), nil) 197 if err != nil { 198 return newError("failed to decrypt fixed length header").Base(err) 199 } 200 } 201 var fixedLengthHeader TCPResponseHeader2FixedLength 202 fixedLengthHeader.RequestSalt = newRequestSaltWithLength(t.method.GetSessionSubKeyAndSaltLength()) 203 { 204 err := struc.Unpack(bytes.NewReader(fixedLengthHeaderDecryptedBuffer.Bytes()), &fixedLengthHeader) 205 if err != nil { 206 return newError("failed to unpack fixed length header").Base(err) 207 } 208 } 209 210 if fixedLengthHeader.Type != TCPHeaderTypeServerToClientStream { 211 return newError("unexpected TCP header type") 212 } 213 timeDifference := int64(fixedLengthHeader.Timestamp) - time.Now().Unix() 214 if timeDifference < -30 || timeDifference > 30 { 215 return newError("timestamp is too far away, timeDifference = ", timeDifference) 216 } 217 218 t.s2cSaltAssert = fixedLengthHeader.RequestSalt 219 t.s2cInitialPayloadSize = int(fixedLengthHeader.InitialPayloadLength) 220 return nil 221 } 222 223 func (t *TCPRequest) CheckC2SConnectionConstraint() error { 224 if !bytes.Equal(t.c2sSalt.Bytes(), t.s2cSaltAssert.Bytes()) { 225 return newError("c2s salt not equal to s2c salt assert") 226 } 227 return nil 228 } 229 230 func (t *TCPRequest) CreateClientS2CReader(in io.Reader, initialPayload *buf.Buffer) (buf.Reader, error) { 231 AEADAuthenticator := &crypto.AEADAuthenticator{ 232 AEAD: t.s2cAEAD, 233 NonceGenerator: t.s2cNonce, 234 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 235 } 236 initialPayloadEncrypted := buf.NewWithSize(65535) 237 defer initialPayloadEncrypted.Release() 238 initialPayloadEncryptedBytes := initialPayloadEncrypted.Extend(int32(t.s2cAEAD.Overhead()) + int32(t.s2cInitialPayloadSize)) 239 _, err := io.ReadFull(in, initialPayloadEncryptedBytes) 240 if err != nil { 241 return nil, newError("failed to read initial payload").Base(err) 242 } 243 initialPayloadBytes := initialPayload.Extend(int32(t.s2cInitialPayloadSize)) 244 _, err = t.s2cAEAD.Open(initialPayloadBytes[:0], t.s2cNonce(), initialPayloadEncryptedBytes, nil) 245 if err != nil { 246 return nil, newError("failed to decrypt initial payload").Base(err) 247 } 248 return crypto.NewAuthenticationReader(AEADAuthenticator, &AEADChunkSizeParser{ 249 Auth: AEADAuthenticator, 250 }, in, protocol.TransferTypeStream, nil), nil 251 } 252 253 func (t *TCPRequest) CreateClientC2SWriter(writer io.Writer) buf.Writer { 254 AEADAuthenticator := &crypto.AEADAuthenticator{ 255 AEAD: t.c2sAEAD, 256 NonceGenerator: t.c2sNonce, 257 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 258 } 259 sizeParser := &crypto.AEADChunkSizeParser{ 260 Auth: AEADAuthenticator, 261 } 262 return crypto.NewAuthenticationWriter(AEADAuthenticator, sizeParser, writer, protocol.TransferTypeStream, nil) 263 } 264 265 type AEADChunkSizeParser struct { 266 Auth *crypto.AEADAuthenticator 267 } 268 269 func (p *AEADChunkSizeParser) HasConstantOffset() uint16 { 270 return uint16(p.Auth.Overhead()) 271 } 272 273 func (p *AEADChunkSizeParser) SizeBytes() int32 { 274 return 2 + int32(p.Auth.Overhead()) 275 } 276 277 func (p *AEADChunkSizeParser) Encode(size uint16, b []byte) []byte { 278 binary.BigEndian.PutUint16(b, size-uint16(p.Auth.Overhead())) 279 b, err := p.Auth.Seal(b[:0], b[:2]) 280 common.Must(err) 281 return b 282 } 283 284 func (p *AEADChunkSizeParser) Decode(b []byte) (uint16, error) { 285 b, err := p.Auth.Open(b[:0], b) 286 if err != nil { 287 return 0, err 288 } 289 return binary.BigEndian.Uint16(b), nil 290 }