github.com/xraypb/Xray-core@v1.8.1/proxy/vmess/encoding/server.go (about) 1 package encoding 2 3 import ( 4 "bytes" 5 "crypto/aes" 6 "crypto/cipher" 7 "crypto/md5" 8 "crypto/sha256" 9 "encoding/binary" 10 "hash/fnv" 11 "io" 12 "sync" 13 "time" 14 15 "github.com/xraypb/Xray-core/common" 16 "github.com/xraypb/Xray-core/common/bitmask" 17 "github.com/xraypb/Xray-core/common/buf" 18 "github.com/xraypb/Xray-core/common/crypto" 19 "github.com/xraypb/Xray-core/common/drain" 20 "github.com/xraypb/Xray-core/common/net" 21 "github.com/xraypb/Xray-core/common/protocol" 22 "github.com/xraypb/Xray-core/common/task" 23 "github.com/xraypb/Xray-core/proxy/vmess" 24 vmessaead "github.com/xraypb/Xray-core/proxy/vmess/aead" 25 "golang.org/x/crypto/chacha20poly1305" 26 ) 27 28 type sessionID struct { 29 user [16]byte 30 key [16]byte 31 nonce [16]byte 32 } 33 34 // SessionHistory keeps track of historical session ids, to prevent replay attacks. 35 type SessionHistory struct { 36 sync.RWMutex 37 cache map[sessionID]time.Time 38 task *task.Periodic 39 } 40 41 // NewSessionHistory creates a new SessionHistory object. 42 func NewSessionHistory() *SessionHistory { 43 h := &SessionHistory{ 44 cache: make(map[sessionID]time.Time, 128), 45 } 46 h.task = &task.Periodic{ 47 Interval: time.Second * 30, 48 Execute: h.removeExpiredEntries, 49 } 50 return h 51 } 52 53 // Close implements common.Closable. 54 func (h *SessionHistory) Close() error { 55 return h.task.Close() 56 } 57 58 func (h *SessionHistory) addIfNotExits(session sessionID) bool { 59 h.Lock() 60 61 if expire, found := h.cache[session]; found && expire.After(time.Now()) { 62 h.Unlock() 63 return false 64 } 65 66 h.cache[session] = time.Now().Add(time.Minute * 3) 67 h.Unlock() 68 common.Must(h.task.Start()) 69 return true 70 } 71 72 func (h *SessionHistory) removeExpiredEntries() error { 73 now := time.Now() 74 75 h.Lock() 76 defer h.Unlock() 77 78 if len(h.cache) == 0 { 79 return newError("nothing to do") 80 } 81 82 for session, expire := range h.cache { 83 if expire.Before(now) { 84 delete(h.cache, session) 85 } 86 } 87 88 if len(h.cache) == 0 { 89 h.cache = make(map[sessionID]time.Time, 128) 90 } 91 92 return nil 93 } 94 95 // ServerSession keeps information for a session in VMess server. 96 type ServerSession struct { 97 userValidator *vmess.TimedUserValidator 98 sessionHistory *SessionHistory 99 requestBodyKey [16]byte 100 requestBodyIV [16]byte 101 responseBodyKey [16]byte 102 responseBodyIV [16]byte 103 responseWriter io.Writer 104 responseHeader byte 105 106 isAEADRequest bool 107 108 isAEADForced bool 109 } 110 111 // NewServerSession creates a new ServerSession, using the given UserValidator. 112 // The ServerSession instance doesn't take ownership of the validator. 113 func NewServerSession(validator *vmess.TimedUserValidator, sessionHistory *SessionHistory) *ServerSession { 114 return &ServerSession{ 115 userValidator: validator, 116 sessionHistory: sessionHistory, 117 } 118 } 119 120 // SetAEADForced sets isAEADForced for a ServerSession. 121 func (s *ServerSession) SetAEADForced(isAEADForced bool) { 122 s.isAEADForced = isAEADForced 123 } 124 125 func parseSecurityType(b byte) protocol.SecurityType { 126 if _, f := protocol.SecurityType_name[int32(b)]; f { 127 st := protocol.SecurityType(b) 128 // For backward compatibility. 129 if st == protocol.SecurityType_UNKNOWN { 130 st = protocol.SecurityType_LEGACY 131 } 132 return st 133 } 134 return protocol.SecurityType_UNKNOWN 135 } 136 137 // DecodeRequestHeader decodes and returns (if successful) a RequestHeader from an input stream. 138 func (s *ServerSession) DecodeRequestHeader(reader io.Reader, isDrain bool) (*protocol.RequestHeader, error) { 139 buffer := buf.New() 140 141 drainer, err := drain.NewBehaviorSeedLimitedDrainer(int64(s.userValidator.GetBehaviorSeed()), 16+38, 3266, 64) 142 if err != nil { 143 return nil, newError("failed to initialize drainer").Base(err) 144 } 145 146 drainConnection := func(e error) error { 147 // We read a deterministic generated length of data before closing the connection to offset padding read pattern 148 drainer.AcknowledgeReceive(int(buffer.Len())) 149 if isDrain { 150 return drain.WithError(drainer, reader, e) 151 } 152 return e 153 } 154 155 defer func() { 156 buffer.Release() 157 }() 158 159 if _, err := buffer.ReadFullFrom(reader, protocol.IDBytesLen); err != nil { 160 return nil, newError("failed to read request header").Base(err) 161 } 162 163 var decryptor io.Reader 164 var vmessAccount *vmess.MemoryAccount 165 166 user, foundAEAD, errorAEAD := s.userValidator.GetAEAD(buffer.Bytes()) 167 168 var fixedSizeAuthID [16]byte 169 copy(fixedSizeAuthID[:], buffer.Bytes()) 170 171 switch { 172 case foundAEAD: 173 vmessAccount = user.Account.(*vmess.MemoryAccount) 174 var fixedSizeCmdKey [16]byte 175 copy(fixedSizeCmdKey[:], vmessAccount.ID.CmdKey()) 176 aeadData, shouldDrain, bytesRead, errorReason := vmessaead.OpenVMessAEADHeader(fixedSizeCmdKey, fixedSizeAuthID, reader) 177 if errorReason != nil { 178 if shouldDrain { 179 drainer.AcknowledgeReceive(bytesRead) 180 return nil, drainConnection(newError("AEAD read failed").Base(errorReason)) 181 } else { 182 return nil, drainConnection(newError("AEAD read failed, drain skipped").Base(errorReason)) 183 } 184 } 185 decryptor = bytes.NewReader(aeadData) 186 s.isAEADRequest = true 187 188 case errorAEAD == vmessaead.ErrNotFound: 189 userLegacy, timestamp, valid, userValidationError := s.userValidator.Get(buffer.Bytes()) 190 if !valid || userValidationError != nil { 191 return nil, drainConnection(newError("invalid user").Base(userValidationError)) 192 } 193 if s.isAEADForced { 194 return nil, drainConnection(newError("invalid user: VMessAEAD is enforced and a non VMessAEAD connection is received. You can still disable this security feature with environment variable xray.vmess.aead.forced = false . You will not be able to enable legacy header workaround in the future.")) 195 } 196 if s.userValidator.ShouldShowLegacyWarn() { 197 newError("Critical Warning: potentially invalid user: a non VMessAEAD connection is received. From 2022 Jan 1st, this kind of connection will be rejected by default. You should update or replace your client software now. This message will not be shown for further violation on this inbound.").AtWarning().WriteToLog() 198 } 199 user = userLegacy 200 iv := hashTimestamp(md5.New(), timestamp) 201 vmessAccount = userLegacy.Account.(*vmess.MemoryAccount) 202 203 aesStream := crypto.NewAesDecryptionStream(vmessAccount.ID.CmdKey(), iv) 204 decryptor = crypto.NewCryptionReader(aesStream, reader) 205 206 default: 207 return nil, drainConnection(newError("invalid user").Base(errorAEAD)) 208 } 209 210 drainer.AcknowledgeReceive(int(buffer.Len())) 211 buffer.Clear() 212 if _, err := buffer.ReadFullFrom(decryptor, 38); err != nil { 213 return nil, newError("failed to read request header").Base(err) 214 } 215 216 request := &protocol.RequestHeader{ 217 User: user, 218 Version: buffer.Byte(0), 219 } 220 221 copy(s.requestBodyIV[:], buffer.BytesRange(1, 17)) // 16 bytes 222 copy(s.requestBodyKey[:], buffer.BytesRange(17, 33)) // 16 bytes 223 var sid sessionID 224 copy(sid.user[:], vmessAccount.ID.Bytes()) 225 sid.key = s.requestBodyKey 226 sid.nonce = s.requestBodyIV 227 if !s.sessionHistory.addIfNotExits(sid) { 228 if !s.isAEADRequest { 229 drainErr := s.userValidator.BurnTaintFuse(fixedSizeAuthID[:]) 230 if drainErr != nil { 231 return nil, drainConnection(newError("duplicated session id, possibly under replay attack, and failed to taint userHash").Base(drainErr)) 232 } 233 return nil, drainConnection(newError("duplicated session id, possibly under replay attack, userHash tainted")) 234 } else { 235 return nil, newError("duplicated session id, possibly under replay attack, but this is a AEAD request") 236 } 237 } 238 239 s.responseHeader = buffer.Byte(33) // 1 byte 240 request.Option = bitmask.Byte(buffer.Byte(34)) // 1 byte 241 paddingLen := int(buffer.Byte(35) >> 4) 242 request.Security = parseSecurityType(buffer.Byte(35) & 0x0F) 243 // 1 bytes reserved 244 request.Command = protocol.RequestCommand(buffer.Byte(37)) 245 246 switch request.Command { 247 case protocol.RequestCommandMux: 248 request.Address = net.DomainAddress("v1.mux.cool") 249 request.Port = 0 250 251 case protocol.RequestCommandTCP, protocol.RequestCommandUDP: 252 if addr, port, err := addrParser.ReadAddressPort(buffer, decryptor); err == nil { 253 request.Address = addr 254 request.Port = port 255 } 256 } 257 258 if paddingLen > 0 { 259 if _, err := buffer.ReadFullFrom(decryptor, int32(paddingLen)); err != nil { 260 if !s.isAEADRequest { 261 burnErr := s.userValidator.BurnTaintFuse(fixedSizeAuthID[:]) 262 if burnErr != nil { 263 return nil, newError("failed to read padding, failed to taint userHash").Base(burnErr).Base(err) 264 } 265 return nil, newError("failed to read padding, userHash tainted").Base(err) 266 } 267 return nil, newError("failed to read padding").Base(err) 268 } 269 } 270 271 if _, err := buffer.ReadFullFrom(decryptor, 4); err != nil { 272 if !s.isAEADRequest { 273 burnErr := s.userValidator.BurnTaintFuse(fixedSizeAuthID[:]) 274 if burnErr != nil { 275 return nil, newError("failed to read checksum, failed to taint userHash").Base(burnErr).Base(err) 276 } 277 return nil, newError("failed to read checksum, userHash tainted").Base(err) 278 } 279 return nil, newError("failed to read checksum").Base(err) 280 } 281 282 fnv1a := fnv.New32a() 283 common.Must2(fnv1a.Write(buffer.BytesTo(-4))) 284 actualHash := fnv1a.Sum32() 285 expectedHash := binary.BigEndian.Uint32(buffer.BytesFrom(-4)) 286 287 if actualHash != expectedHash { 288 if !s.isAEADRequest { 289 Autherr := newError("invalid auth, legacy userHash tainted") 290 burnErr := s.userValidator.BurnTaintFuse(fixedSizeAuthID[:]) 291 if burnErr != nil { 292 Autherr = newError("invalid auth, can't taint legacy userHash").Base(burnErr) 293 } 294 // It is possible that we are under attack described in https://github.com/xray/xray-core/issues/2523 295 return nil, drainConnection(Autherr) 296 } else { 297 return nil, newError("invalid auth, but this is a AEAD request") 298 } 299 } 300 301 if request.Address == nil { 302 return nil, newError("invalid remote address") 303 } 304 305 if request.Security == protocol.SecurityType_UNKNOWN || request.Security == protocol.SecurityType_AUTO { 306 return nil, newError("unknown security type: ", request.Security) 307 } 308 309 return request, nil 310 } 311 312 // DecodeRequestBody returns Reader from which caller can fetch decrypted body. 313 func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reader io.Reader) (buf.Reader, error) { 314 var sizeParser crypto.ChunkSizeDecoder = crypto.PlainChunkSizeParser{} 315 if request.Option.Has(protocol.RequestOptionChunkMasking) { 316 sizeParser = NewShakeSizeParser(s.requestBodyIV[:]) 317 } 318 var padding crypto.PaddingLengthGenerator 319 if request.Option.Has(protocol.RequestOptionGlobalPadding) { 320 var ok bool 321 padding, ok = sizeParser.(crypto.PaddingLengthGenerator) 322 if !ok { 323 return nil, newError("invalid option: RequestOptionGlobalPadding") 324 } 325 } 326 327 switch request.Security { 328 case protocol.SecurityType_NONE: 329 if request.Option.Has(protocol.RequestOptionChunkStream) { 330 if request.Command.TransferType() == protocol.TransferTypeStream { 331 return crypto.NewChunkStreamReader(sizeParser, reader), nil 332 } 333 334 auth := &crypto.AEADAuthenticator{ 335 AEAD: new(NoOpAuthenticator), 336 NonceGenerator: crypto.GenerateEmptyBytes(), 337 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 338 } 339 return crypto.NewAuthenticationReader(auth, sizeParser, reader, protocol.TransferTypePacket, padding), nil 340 } 341 return buf.NewReader(reader), nil 342 343 case protocol.SecurityType_LEGACY: 344 aesStream := crypto.NewAesDecryptionStream(s.requestBodyKey[:], s.requestBodyIV[:]) 345 cryptionReader := crypto.NewCryptionReader(aesStream, reader) 346 if request.Option.Has(protocol.RequestOptionChunkStream) { 347 auth := &crypto.AEADAuthenticator{ 348 AEAD: new(FnvAuthenticator), 349 NonceGenerator: crypto.GenerateEmptyBytes(), 350 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 351 } 352 return crypto.NewAuthenticationReader(auth, sizeParser, cryptionReader, request.Command.TransferType(), padding), nil 353 } 354 return buf.NewReader(cryptionReader), nil 355 356 case protocol.SecurityType_AES128_GCM: 357 aead := crypto.NewAesGcm(s.requestBodyKey[:]) 358 auth := &crypto.AEADAuthenticator{ 359 AEAD: aead, 360 NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())), 361 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 362 } 363 if request.Option.Has(protocol.RequestOptionAuthenticatedLength) { 364 AuthenticatedLengthKey := vmessaead.KDF16(s.requestBodyKey[:], "auth_len") 365 AuthenticatedLengthKeyAEAD := crypto.NewAesGcm(AuthenticatedLengthKey) 366 367 lengthAuth := &crypto.AEADAuthenticator{ 368 AEAD: AuthenticatedLengthKeyAEAD, 369 NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())), 370 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 371 } 372 sizeParser = NewAEADSizeParser(lengthAuth) 373 } 374 return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding), nil 375 376 case protocol.SecurityType_CHACHA20_POLY1305: 377 aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(s.requestBodyKey[:])) 378 379 auth := &crypto.AEADAuthenticator{ 380 AEAD: aead, 381 NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())), 382 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 383 } 384 if request.Option.Has(protocol.RequestOptionAuthenticatedLength) { 385 AuthenticatedLengthKey := vmessaead.KDF16(s.requestBodyKey[:], "auth_len") 386 AuthenticatedLengthKeyAEAD, err := chacha20poly1305.New(GenerateChacha20Poly1305Key(AuthenticatedLengthKey)) 387 common.Must(err) 388 389 lengthAuth := &crypto.AEADAuthenticator{ 390 AEAD: AuthenticatedLengthKeyAEAD, 391 NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())), 392 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 393 } 394 sizeParser = NewAEADSizeParser(lengthAuth) 395 } 396 return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding), nil 397 398 default: 399 return nil, newError("invalid option: Security") 400 } 401 } 402 403 // EncodeResponseHeader writes encoded response header into the given writer. 404 func (s *ServerSession) EncodeResponseHeader(header *protocol.ResponseHeader, writer io.Writer) { 405 var encryptionWriter io.Writer 406 if !s.isAEADRequest { 407 s.responseBodyKey = md5.Sum(s.requestBodyKey[:]) 408 s.responseBodyIV = md5.Sum(s.requestBodyIV[:]) 409 } else { 410 BodyKey := sha256.Sum256(s.requestBodyKey[:]) 411 copy(s.responseBodyKey[:], BodyKey[:16]) 412 BodyIV := sha256.Sum256(s.requestBodyIV[:]) 413 copy(s.responseBodyIV[:], BodyIV[:16]) 414 } 415 416 aesStream := crypto.NewAesEncryptionStream(s.responseBodyKey[:], s.responseBodyIV[:]) 417 encryptionWriter = crypto.NewCryptionWriter(aesStream, writer) 418 s.responseWriter = encryptionWriter 419 420 aeadEncryptedHeaderBuffer := bytes.NewBuffer(nil) 421 422 if s.isAEADRequest { 423 encryptionWriter = aeadEncryptedHeaderBuffer 424 } 425 426 common.Must2(encryptionWriter.Write([]byte{s.responseHeader, byte(header.Option)})) 427 err := MarshalCommand(header.Command, encryptionWriter) 428 if err != nil { 429 common.Must2(encryptionWriter.Write([]byte{0x00, 0x00})) 430 } 431 432 if s.isAEADRequest { 433 aeadResponseHeaderLengthEncryptionKey := vmessaead.KDF16(s.responseBodyKey[:], vmessaead.KDFSaltConstAEADRespHeaderLenKey) 434 aeadResponseHeaderLengthEncryptionIV := vmessaead.KDF(s.responseBodyIV[:], vmessaead.KDFSaltConstAEADRespHeaderLenIV)[:12] 435 436 aeadResponseHeaderLengthEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderLengthEncryptionKey)).(cipher.Block) 437 aeadResponseHeaderLengthEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderLengthEncryptionKeyAESBlock)).(cipher.AEAD) 438 439 aeadResponseHeaderLengthEncryptionBuffer := bytes.NewBuffer(nil) 440 441 decryptedResponseHeaderLengthBinaryDeserializeBuffer := uint16(aeadEncryptedHeaderBuffer.Len()) 442 443 common.Must(binary.Write(aeadResponseHeaderLengthEncryptionBuffer, binary.BigEndian, decryptedResponseHeaderLengthBinaryDeserializeBuffer)) 444 445 AEADEncryptedLength := aeadResponseHeaderLengthEncryptionAEAD.Seal(nil, aeadResponseHeaderLengthEncryptionIV, aeadResponseHeaderLengthEncryptionBuffer.Bytes(), nil) 446 common.Must2(io.Copy(writer, bytes.NewReader(AEADEncryptedLength))) 447 448 aeadResponseHeaderPayloadEncryptionKey := vmessaead.KDF16(s.responseBodyKey[:], vmessaead.KDFSaltConstAEADRespHeaderPayloadKey) 449 aeadResponseHeaderPayloadEncryptionIV := vmessaead.KDF(s.responseBodyIV[:], vmessaead.KDFSaltConstAEADRespHeaderPayloadIV)[:12] 450 451 aeadResponseHeaderPayloadEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderPayloadEncryptionKey)).(cipher.Block) 452 aeadResponseHeaderPayloadEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderPayloadEncryptionKeyAESBlock)).(cipher.AEAD) 453 454 aeadEncryptedHeaderPayload := aeadResponseHeaderPayloadEncryptionAEAD.Seal(nil, aeadResponseHeaderPayloadEncryptionIV, aeadEncryptedHeaderBuffer.Bytes(), nil) 455 common.Must2(io.Copy(writer, bytes.NewReader(aeadEncryptedHeaderPayload))) 456 } 457 } 458 459 // EncodeResponseBody returns a Writer that auto-encrypt content written by caller. 460 func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writer io.Writer) (buf.Writer, error) { 461 var sizeParser crypto.ChunkSizeEncoder = crypto.PlainChunkSizeParser{} 462 if request.Option.Has(protocol.RequestOptionChunkMasking) { 463 sizeParser = NewShakeSizeParser(s.responseBodyIV[:]) 464 } 465 var padding crypto.PaddingLengthGenerator 466 if request.Option.Has(protocol.RequestOptionGlobalPadding) { 467 var ok bool 468 padding, ok = sizeParser.(crypto.PaddingLengthGenerator) 469 if !ok { 470 return nil, newError("invalid option: RequestOptionGlobalPadding") 471 } 472 } 473 474 switch request.Security { 475 case protocol.SecurityType_NONE: 476 if request.Option.Has(protocol.RequestOptionChunkStream) { 477 if request.Command.TransferType() == protocol.TransferTypeStream { 478 return crypto.NewChunkStreamWriter(sizeParser, writer), nil 479 } 480 481 auth := &crypto.AEADAuthenticator{ 482 AEAD: new(NoOpAuthenticator), 483 NonceGenerator: crypto.GenerateEmptyBytes(), 484 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 485 } 486 return crypto.NewAuthenticationWriter(auth, sizeParser, writer, protocol.TransferTypePacket, padding), nil 487 } 488 return buf.NewWriter(writer), nil 489 490 case protocol.SecurityType_LEGACY: 491 if request.Option.Has(protocol.RequestOptionChunkStream) { 492 auth := &crypto.AEADAuthenticator{ 493 AEAD: new(FnvAuthenticator), 494 NonceGenerator: crypto.GenerateEmptyBytes(), 495 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 496 } 497 return crypto.NewAuthenticationWriter(auth, sizeParser, s.responseWriter, request.Command.TransferType(), padding), nil 498 } 499 return &buf.SequentialWriter{Writer: s.responseWriter}, nil 500 501 case protocol.SecurityType_AES128_GCM: 502 aead := crypto.NewAesGcm(s.responseBodyKey[:]) 503 auth := &crypto.AEADAuthenticator{ 504 AEAD: aead, 505 NonceGenerator: GenerateChunkNonce(s.responseBodyIV[:], uint32(aead.NonceSize())), 506 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 507 } 508 if request.Option.Has(protocol.RequestOptionAuthenticatedLength) { 509 AuthenticatedLengthKey := vmessaead.KDF16(s.requestBodyKey[:], "auth_len") 510 AuthenticatedLengthKeyAEAD := crypto.NewAesGcm(AuthenticatedLengthKey) 511 512 lengthAuth := &crypto.AEADAuthenticator{ 513 AEAD: AuthenticatedLengthKeyAEAD, 514 NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())), 515 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 516 } 517 sizeParser = NewAEADSizeParser(lengthAuth) 518 } 519 return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding), nil 520 521 case protocol.SecurityType_CHACHA20_POLY1305: 522 aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(s.responseBodyKey[:])) 523 524 auth := &crypto.AEADAuthenticator{ 525 AEAD: aead, 526 NonceGenerator: GenerateChunkNonce(s.responseBodyIV[:], uint32(aead.NonceSize())), 527 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 528 } 529 if request.Option.Has(protocol.RequestOptionAuthenticatedLength) { 530 AuthenticatedLengthKey := vmessaead.KDF16(s.requestBodyKey[:], "auth_len") 531 AuthenticatedLengthKeyAEAD, err := chacha20poly1305.New(GenerateChacha20Poly1305Key(AuthenticatedLengthKey)) 532 common.Must(err) 533 534 lengthAuth := &crypto.AEADAuthenticator{ 535 AEAD: AuthenticatedLengthKeyAEAD, 536 NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())), 537 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 538 } 539 sizeParser = NewAEADSizeParser(lengthAuth) 540 } 541 return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding), nil 542 543 default: 544 return nil, newError("invalid option: Security") 545 } 546 }