func (this *AesCfb) NewEncodingStream(key []byte, iv []byte, writer io.Writer) (io.Writer, error) { stream, err := crypto.NewAesEncryptionStream(key, iv) if err != nil { return nil, err } aesWriter := crypto.NewCryptionWriter(stream, writer) return aesWriter, nil }
func (this *VMessInboundHandler) HandleConnection(connection *net.TCPConn) error { defer connection.Close() connReader := v2net.NewTimeOutReader(16, connection) requestReader := protocol.NewVMessRequestReader(this.clients) request, err := requestReader.Read(connReader) if err != nil { log.Access(connection.RemoteAddr().String(), "", log.AccessRejected, err.Error()) log.Warning("VMessIn: Invalid request from (%s): %v", connection.RemoteAddr().String(), err) return err } log.Access(connection.RemoteAddr().String(), request.Address.String(), log.AccessAccepted, "") log.Debug("VMessIn: Received request for %s", request.Address.String()) ray := this.space.PacketDispatcher().DispatchToOutbound(v2net.NewPacket(request.Destination(), nil, true)) input := ray.InboundInput() output := ray.InboundOutput() var readFinish, writeFinish sync.Mutex readFinish.Lock() writeFinish.Lock() userSettings := vmess.GetUserSettings(request.User.Level) connReader.SetTimeOut(userSettings.PayloadReadTimeout) go handleInput(request, connReader, input, &readFinish) responseKey := md5.Sum(request.RequestKey) responseIV := md5.Sum(request.RequestIV) aesStream, err := v2crypto.NewAesEncryptionStream(responseKey[:], responseIV[:]) if err != nil { log.Error("VMessIn: Failed to create AES decryption stream: %v", err) close(input) return err } responseWriter := v2crypto.NewCryptionWriter(aesStream, connection) // Optimize for small response packet buffer := alloc.NewLargeBuffer().Clear() defer buffer.Release() buffer.AppendBytes(request.ResponseHeader[0] ^ request.ResponseHeader[1]) buffer.AppendBytes(request.ResponseHeader[2] ^ request.ResponseHeader[3]) buffer.AppendBytes(byte(0), byte(0)) if data, open := <-output; open { buffer.Append(data.Value) data.Release() responseWriter.Write(buffer.Value) go handleOutput(request, responseWriter, output, &writeFinish) writeFinish.Lock() } connection.CloseWrite() readFinish.Lock() return nil }
// ToBytes returns a VMessRequest in the form of byte array. func (this *VMessRequest) ToBytes(timestampGenerator RandomTimestampGenerator, buffer *alloc.Buffer) (*alloc.Buffer, error) { if buffer == nil { buffer = alloc.NewSmallBuffer().Clear() } timestamp := timestampGenerator.Next() idHash := IDHash(this.User.AnyValidID().Bytes()) idHash.Write(timestamp.Bytes()) hashStart := buffer.Len() buffer.Slice(0, hashStart+16) idHash.Sum(buffer.Value[hashStart:hashStart]) encryptionBegin := buffer.Len() buffer.AppendBytes(this.Version) buffer.Append(this.RequestIV) buffer.Append(this.RequestKey) buffer.AppendBytes(this.ResponseHeader, this.Option, byte(0), byte(0)) buffer.AppendBytes(this.Command) buffer.Append(this.Port.Bytes()) switch { case this.Address.IsIPv4(): buffer.AppendBytes(addrTypeIPv4) buffer.Append(this.Address.IP()) case this.Address.IsIPv6(): buffer.AppendBytes(addrTypeIPv6) buffer.Append(this.Address.IP()) case this.Address.IsDomain(): buffer.AppendBytes(addrTypeDomain, byte(len(this.Address.Domain()))) buffer.Append([]byte(this.Address.Domain())) } encryptionEnd := buffer.Len() fnv1a := fnv.New32a() fnv1a.Write(buffer.Value[encryptionBegin:encryptionEnd]) fnvHash := fnv1a.Sum32() buffer.AppendBytes(byte(fnvHash>>24), byte(fnvHash>>16), byte(fnvHash>>8), byte(fnvHash)) encryptionEnd += 4 timestampHash := md5.New() timestampHash.Write(timestamp.HashBytes()) iv := timestampHash.Sum(nil) aesStream, err := v2crypto.NewAesEncryptionStream(this.User.ID.CmdKey(), iv) if err != nil { return nil, err } aesStream.XORKeyStream(buffer.Value[encryptionBegin:encryptionEnd], buffer.Value[encryptionBegin:encryptionEnd]) return buffer, nil }
func (this *VMessOutboundHandler) handleRequest(conn net.Conn, request *protocol.VMessRequest, firstPacket v2net.Packet, input <-chan *alloc.Buffer, finish *sync.Mutex) { defer finish.Unlock() aesStream, err := v2crypto.NewAesEncryptionStream(request.RequestKey[:], request.RequestIV[:]) if err != nil { log.Error("VMessOut: Failed to create AES encryption stream: ", err) return } encryptRequestWriter := v2crypto.NewCryptionWriter(aesStream, conn) buffer := alloc.NewBuffer().Clear() defer buffer.Release() buffer, err = request.ToBytes(protocol.NewRandomTimestampGenerator(protocol.Timestamp(time.Now().Unix()), 30), buffer) if err != nil { log.Error("VMessOut: Failed to serialize VMess request: ", err) return } // Send first packet of payload together with request, in favor of small requests. firstChunk := firstPacket.Chunk() moreChunks := firstPacket.MoreChunks() for firstChunk == nil && moreChunks { firstChunk, moreChunks = <-input } if firstChunk == nil && !moreChunks { log.Warning("VMessOut: Nothing to send. Existing...") return } if request.IsChunkStream() { vmessio.Authenticate(firstChunk) } aesStream.XORKeyStream(firstChunk.Value, firstChunk.Value) buffer.Append(firstChunk.Value) firstChunk.Release() _, err = conn.Write(buffer.Value) if err != nil { log.Error("VMessOut: Failed to write VMess request: ", err) return } if moreChunks { var streamWriter v2io.Writer streamWriter = v2io.NewAdaptiveWriter(encryptRequestWriter) if request.IsChunkStream() { streamWriter = vmessio.NewAuthChunkWriter(streamWriter) } v2io.ChanToWriter(streamWriter, input) } return }
// ToBytes returns a VMessRequest in the form of byte array. func (this *VMessRequest) ToBytes(idHash user.CounterHash, randomRangeInt64 user.RandomInt64InRange, buffer *alloc.Buffer) (*alloc.Buffer, error) { if buffer == nil { buffer = alloc.NewSmallBuffer().Clear() } counter := randomRangeInt64(time.Now().Unix(), 30) hash := idHash.Hash(this.User.ID().Bytes[:], counter) buffer.Append(hash) encryptionBegin := buffer.Len() buffer.AppendBytes(this.Version) buffer.Append(this.RequestIV) buffer.Append(this.RequestKey) buffer.Append(this.ResponseHeader) buffer.AppendBytes(this.Command) buffer.Append(this.Address.PortBytes()) switch { case this.Address.IsIPv4(): buffer.AppendBytes(addrTypeIPv4) buffer.Append(this.Address.IP()) case this.Address.IsIPv6(): buffer.AppendBytes(addrTypeIPv6) buffer.Append(this.Address.IP()) case this.Address.IsDomain(): buffer.AppendBytes(addrTypeDomain, byte(len(this.Address.Domain()))) buffer.Append([]byte(this.Address.Domain())) } encryptionEnd := buffer.Len() fnv1a := fnv.New32a() fnv1a.Write(buffer.Value[encryptionBegin:encryptionEnd]) fnvHash := fnv1a.Sum32() buffer.AppendBytes(byte(fnvHash>>24), byte(fnvHash>>16), byte(fnvHash>>8), byte(fnvHash)) encryptionEnd += 4 aesStream, err := v2crypto.NewAesEncryptionStream(this.User.ID().CmdKey(), user.Int64Hash(counter)) if err != nil { return nil, err } aesStream.XORKeyStream(buffer.Value[encryptionBegin:encryptionEnd], buffer.Value[encryptionBegin:encryptionEnd]) return buffer, nil }
func (this *ServerSession) EncodeResponseHeader(header *protocol.ResponseHeader, writer io.Writer) { responseBodyKey := md5.Sum(this.requestBodyKey) responseBodyIV := md5.Sum(this.requestBodyIV) this.responseBodyKey = responseBodyKey[:] this.responseBodyIV = responseBodyIV[:] aesStream := crypto.NewAesEncryptionStream(this.responseBodyKey, this.responseBodyIV) encryptionWriter := crypto.NewCryptionWriter(aesStream, writer) this.responseWriter = encryptionWriter encryptionWriter.Write([]byte{this.responseHeader, 0x00}) err := MarshalCommand(header.Command, encryptionWriter) if err != nil { encryptionWriter.Write([]byte{0x00, 0x00}) } }
func handleRequest(conn net.Conn, request *protocol.VMessRequest, firstPacket v2net.Packet, input <-chan *alloc.Buffer, finish *sync.Mutex) { defer finish.Unlock() aesStream, err := v2crypto.NewAesEncryptionStream(request.RequestKey[:], request.RequestIV[:]) if err != nil { log.Error("VMessOut: Failed to create AES encryption stream: %v", err) return } encryptRequestWriter := v2crypto.NewCryptionWriter(aesStream, conn) buffer := alloc.NewBuffer().Clear() defer buffer.Release() buffer, err = request.ToBytes(user.NewTimeHash(user.HMACHash{}), user.GenerateRandomInt64InRange, buffer) if err != nil { log.Error("VMessOut: Failed to serialize VMess request: %v", err) return } // Send first packet of payload together with request, in favor of small requests. firstChunk := firstPacket.Chunk() moreChunks := firstPacket.MoreChunks() for firstChunk == nil && moreChunks { firstChunk, moreChunks = <-input } if firstChunk == nil && !moreChunks { log.Warning("VMessOut: Nothing to send. Existing...") return } aesStream.XORKeyStream(firstChunk.Value, firstChunk.Value) buffer.Append(firstChunk.Value) firstChunk.Release() _, err = conn.Write(buffer.Value) if err != nil { log.Error("VMessOut: Failed to write VMess request: %v", err) return } if moreChunks { v2net.ChanToWriter(encryptRequestWriter, input) } return }
func (this *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, writer io.Writer) { timestamp := protocol.NewTimestampGenerator(protocol.NowTime(), 30)() idHash := this.idHash(header.User.AnyValidID().Bytes()) idHash.Write(timestamp.Bytes()) writer.Write(idHash.Sum(nil)) buffer := alloc.NewSmallBuffer().Clear() defer buffer.Release() buffer.AppendBytes(Version) buffer.Append(this.requestBodyIV) buffer.Append(this.requestBodyKey) buffer.AppendBytes(this.responseHeader, byte(header.Option), byte(0), byte(0)) buffer.AppendBytes(byte(header.Command)) buffer.Append(header.Port.Bytes()) switch { case header.Address.IsIPv4(): buffer.AppendBytes(AddrTypeIPv4) buffer.Append(header.Address.IP()) case header.Address.IsIPv6(): buffer.AppendBytes(AddrTypeIPv6) buffer.Append(header.Address.IP()) case header.Address.IsDomain(): buffer.AppendBytes(AddrTypeDomain, byte(len(header.Address.Domain()))) buffer.Append([]byte(header.Address.Domain())) } fnv1a := fnv.New32a() fnv1a.Write(buffer.Value) fnvHash := fnv1a.Sum32() buffer.AppendBytes(byte(fnvHash>>24), byte(fnvHash>>16), byte(fnvHash>>8), byte(fnvHash)) timestampHash := md5.New() timestampHash.Write(hashTimestamp(timestamp)) iv := timestampHash.Sum(nil) aesStream := crypto.NewAesEncryptionStream(header.User.ID.CmdKey(), iv) aesStream.XORKeyStream(buffer.Value, buffer.Value) writer.Write(buffer.Value) return }
func (this *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, writer io.Writer) { timestamp := protocol.NewTimestampGenerator(protocol.NowTime(), 30)() idHash := this.idHash(header.User.Account.(*protocol.VMessAccount).AnyValidID().Bytes()) idHash.Write(timestamp.Bytes(nil)) writer.Write(idHash.Sum(nil)) buffer := make([]byte, 0, 512) buffer = append(buffer, Version) buffer = append(buffer, this.requestBodyIV...) buffer = append(buffer, this.requestBodyKey...) buffer = append(buffer, this.responseHeader, byte(header.Option), byte(0), byte(0), byte(header.Command)) buffer = header.Port.Bytes(buffer) switch { case header.Address.IsIPv4(): buffer = append(buffer, AddrTypeIPv4) buffer = append(buffer, header.Address.IP()...) case header.Address.IsIPv6(): buffer = append(buffer, AddrTypeIPv6) buffer = append(buffer, header.Address.IP()...) case header.Address.IsDomain(): buffer = append(buffer, AddrTypeDomain, byte(len(header.Address.Domain()))) buffer = append(buffer, header.Address.Domain()...) } fnv1a := fnv.New32a() fnv1a.Write(buffer) buffer = fnv1a.Sum(buffer) timestampHash := md5.New() timestampHash.Write(hashTimestamp(timestamp)) iv := timestampHash.Sum(nil) account := header.User.Account.(*protocol.VMessAccount) aesStream := crypto.NewAesEncryptionStream(account.ID.CmdKey(), iv) aesStream.XORKeyStream(buffer, buffer) writer.Write(buffer) return }
func (this *ClientSession) EncodeRequestBody(writer io.Writer) io.Writer { aesStream := crypto.NewAesEncryptionStream(this.requestBodyKey, this.requestBodyIV) return crypto.NewCryptionWriter(aesStream, writer) }
func (this *VMessInboundHandler) HandleConnection(connection *hub.TCPConn) { defer connection.Close() connReader := v2net.NewTimeOutReader(16, connection) requestReader := protocol.NewVMessRequestReader(this.clients) request, err := requestReader.Read(connReader) if err != nil { log.Access(connection.RemoteAddr(), serial.StringLiteral(""), log.AccessRejected, serial.StringLiteral(err.Error())) log.Warning("VMessIn: Invalid request from ", connection.RemoteAddr(), ": ", err) return } log.Access(connection.RemoteAddr(), request.Address, log.AccessAccepted, serial.StringLiteral("")) log.Debug("VMessIn: Received request for ", request.Address) ray := this.packetDispatcher.DispatchToOutbound(v2net.NewPacket(request.Destination(), nil, true)) input := ray.InboundInput() output := ray.InboundOutput() var readFinish, writeFinish sync.Mutex readFinish.Lock() writeFinish.Lock() userSettings := vmess.GetUserSettings(request.User.Level) connReader.SetTimeOut(userSettings.PayloadReadTimeout) go handleInput(request, connReader, input, &readFinish) responseKey := md5.Sum(request.RequestKey) responseIV := md5.Sum(request.RequestIV) aesStream, err := v2crypto.NewAesEncryptionStream(responseKey[:], responseIV[:]) if err != nil { log.Error("VMessIn: Failed to create AES decryption stream: ", err) close(input) return } responseWriter := v2crypto.NewCryptionWriter(aesStream, connection) // Optimize for small response packet buffer := alloc.NewLargeBuffer().Clear() defer buffer.Release() buffer.AppendBytes(request.ResponseHeader, byte(0)) this.generateCommand(buffer) if data, open := <-output; open { if request.IsChunkStream() { vmessio.Authenticate(data) } buffer.Append(data.Value) data.Release() responseWriter.Write(buffer.Value) go func(finish *sync.Mutex) { var writer v2io.Writer writer = v2io.NewAdaptiveWriter(responseWriter) if request.IsChunkStream() { writer = vmessio.NewAuthChunkWriter(writer) } v2io.ChanToWriter(writer, output) finish.Unlock() }(&writeFinish) writeFinish.Lock() } connection.CloseWrite() readFinish.Lock() }
func (this *AesCfb) NewEncodingStream(key []byte, iv []byte) (cipher.Stream, error) { stream := crypto.NewAesEncryptionStream(key, iv) return stream, nil }