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