func ReadVMessUDP(buffer []byte, userset user.UserSet) (*VMessUDP, error) { userHash := buffer[:user.IDBytesLen] userId, timeSec, valid := userset.GetUser(userHash) if !valid { return nil, errors.NewAuthenticationError(userHash) } buffer = buffer[user.IDBytesLen:] aesCipher, err := aes.NewCipher(userId.CmdKey()) if err != nil { return nil, err } aesStream := cipher.NewCFBDecrypter(aesCipher, user.Int64Hash(timeSec)) aesStream.XORKeyStream(buffer, buffer) fnvHash := binary.BigEndian.Uint32(buffer[:4]) fnv1a := fnv.New32a() fnv1a.Write(buffer[4:]) fnvHashActual := fnv1a.Sum32() if fnvHash != fnvHashActual { log.Warning("Unexpected fhv hash %d, should be %d", fnvHashActual, fnvHash) return nil, errors.NewCorruptedPacketError() } buffer = buffer[4:] vmess := &VMessUDP{ user: *userId, version: buffer[0], token: binary.BigEndian.Uint16(buffer[1:3]), } // buffer[3] is reserved port := binary.BigEndian.Uint16(buffer[4:6]) addrType := buffer[6] var address v2net.Address switch addrType { case addrTypeIPv4: address = v2net.IPAddress(buffer[7:11], port) buffer = buffer[11:] case addrTypeIPv6: address = v2net.IPAddress(buffer[7:23], port) buffer = buffer[23:] case addrTypeDomain: domainLength := buffer[7] domain := string(buffer[8 : 8+domainLength]) address = v2net.DomainAddress(domain, port) buffer = buffer[8+domainLength:] default: log.Warning("Unexpected address type %d", addrType) return nil, errors.NewCorruptedPacketError() } vmess.address = address vmess.data = buffer return vmess, nil }
func (request *VMessRequest) ToBytes(idHash user.CounterHash, randomRangeInt64 user.RandomInt64InRange) ([]byte, error) { buffer := make([]byte, 0, 300) counter := randomRangeInt64(time.Now().UTC().Unix(), 30) hash := idHash.Hash(request.UserId.Bytes, counter) log.Debug("Writing userhash: %v", hash) buffer = append(buffer, hash...) encryptionBegin := len(buffer) randomLength := mrand.Intn(32) + 1 randomContent := make([]byte, randomLength) _, err := rand.Read(randomContent) if err != nil { return nil, err } buffer = append(buffer, byte(randomLength)) buffer = append(buffer, randomContent...) buffer = append(buffer, request.Version) buffer = append(buffer, request.RequestIV[:]...) buffer = append(buffer, request.RequestKey[:]...) buffer = append(buffer, request.ResponseHeader[:]...) buffer = append(buffer, request.Command) buffer = append(buffer, request.Address.PortBytes()...) switch { case request.Address.IsIPv4(): buffer = append(buffer, addrTypeIPv4) buffer = append(buffer, request.Address.IP()...) case request.Address.IsIPv6(): buffer = append(buffer, addrTypeIPv6) buffer = append(buffer, request.Address.IP()...) case request.Address.IsDomain(): buffer = append(buffer, addrTypeDomain) buffer = append(buffer, byte(len(request.Address.Domain()))) buffer = append(buffer, []byte(request.Address.Domain())...) } paddingLength := mrand.Intn(32) + 1 paddingBuffer := make([]byte, paddingLength) _, err = rand.Read(paddingBuffer) if err != nil { return nil, err } buffer = append(buffer, byte(paddingLength)) buffer = append(buffer, paddingBuffer...) encryptionEnd := len(buffer) aesCipher, err := aes.NewCipher(request.UserId.CmdKey()) if err != nil { return nil, err } aesStream := cipher.NewCFBEncrypter(aesCipher, user.Int64Hash(counter)) aesStream.XORKeyStream(buffer[encryptionBegin:encryptionEnd], buffer[encryptionBegin:encryptionEnd]) return buffer, nil }
func (vmess *VMessUDP) ToBytes(idHash user.CounterHash, randomRangeInt64 user.RandomInt64InRange, buffer []byte) []byte { if buffer == nil { buffer = make([]byte, 0, 2*1024) } counter := randomRangeInt64(time.Now().UTC().Unix(), 30) hash := idHash.Hash(vmess.user.Bytes[:], counter) buffer = append(buffer, hash...) encryptBegin := 16 // Placeholder for fnv1a hash buffer = append(buffer, byte(0), byte(0), byte(0), byte(0)) fnvHash := 16 fnvHashBegin := 20 buffer = append(buffer, vmess.version) buffer = append(buffer, byte(vmess.token>>8), byte(vmess.token)) buffer = append(buffer, byte(0x00)) buffer = append(buffer, vmess.address.PortBytes()...) switch { case vmess.address.IsIPv4(): buffer = append(buffer, addrTypeIPv4) buffer = append(buffer, vmess.address.IP()...) case vmess.address.IsIPv6(): buffer = append(buffer, addrTypeIPv6) buffer = append(buffer, vmess.address.IP()...) case vmess.address.IsDomain(): buffer = append(buffer, addrTypeDomain) buffer = append(buffer, byte(len(vmess.address.Domain()))) buffer = append(buffer, []byte(vmess.address.Domain())...) } buffer = append(buffer, vmess.data...) fnv1a := fnv.New32a() fnv1a.Write(buffer[fnvHashBegin:]) fnvHashValue := fnv1a.Sum32() buffer[fnvHash] = byte(fnvHashValue >> 24) buffer[fnvHash+1] = byte(fnvHashValue >> 16) buffer[fnvHash+2] = byte(fnvHashValue >> 8) buffer[fnvHash+3] = byte(fnvHashValue) aesCipher, err := aes.NewCipher(vmess.user.CmdKey()) if err != nil { log.Error("VMess failed to create AES cipher: %v", err) return nil } aesStream := cipher.NewCFBEncrypter(aesCipher, user.Int64Hash(counter)) aesStream.XORKeyStream(buffer[encryptBegin:], buffer[encryptBegin:]) return buffer }
// ToBytes returns a VMessRequest in the form of byte array. func (request *VMessRequest) ToBytes(idHash user.CounterHash, randomRangeInt64 user.RandomInt64InRange, buffer []byte) ([]byte, error) { if buffer == nil { buffer = make([]byte, 0, 300) } counter := randomRangeInt64(time.Now().UTC().Unix(), 30) hash := idHash.Hash(request.UserId.Bytes[:], counter) log.Debug("Writing userhash: %v", hash) buffer = append(buffer, hash...) encryptionBegin := len(buffer) buffer = append(buffer, request.Version) buffer = append(buffer, request.RequestIV[:]...) buffer = append(buffer, request.RequestKey[:]...) buffer = append(buffer, request.ResponseHeader[:]...) buffer = append(buffer, request.Command) buffer = append(buffer, request.Address.PortBytes()...) switch { case request.Address.IsIPv4(): buffer = append(buffer, addrTypeIPv4) buffer = append(buffer, request.Address.IP()...) case request.Address.IsIPv6(): buffer = append(buffer, addrTypeIPv6) buffer = append(buffer, request.Address.IP()...) case request.Address.IsDomain(): buffer = append(buffer, addrTypeDomain) buffer = append(buffer, byte(len(request.Address.Domain()))) buffer = append(buffer, []byte(request.Address.Domain())...) } encryptionEnd := len(buffer) fnv1a := fnv.New32a() fnv1a.Write(buffer[encryptionBegin:encryptionEnd]) fnvHash := fnv1a.Sum32() buffer = append(buffer, byte(fnvHash>>24)) buffer = append(buffer, byte(fnvHash>>16)) buffer = append(buffer, byte(fnvHash>>8)) buffer = append(buffer, byte(fnvHash)) encryptionEnd += 4 aesCipher, err := aes.NewCipher(request.UserId.CmdKey()) if err != nil { return nil, err } aesStream := cipher.NewCFBEncrypter(aesCipher, user.Int64Hash(counter)) aesStream.XORKeyStream(buffer[encryptionBegin:encryptionEnd], buffer[encryptionBegin:encryptionEnd]) return buffer, nil }
// ToBytes returns a VMessRequest in the form of byte array. func (request *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().UTC().Unix(), 30) hash := idHash.Hash(request.UserId.Bytes[:], counter) buffer.Append(hash) encryptionBegin := buffer.Len() buffer.AppendBytes(request.Version) buffer.Append(request.RequestIV) buffer.Append(request.RequestKey) buffer.Append(request.ResponseHeader) buffer.AppendBytes(request.Command) buffer.Append(request.Address.PortBytes()) switch { case request.Address.IsIPv4(): buffer.AppendBytes(addrTypeIPv4) buffer.Append(request.Address.IP()) case request.Address.IsIPv6(): buffer.AppendBytes(addrTypeIPv6) buffer.Append(request.Address.IP()) case request.Address.IsDomain(): buffer.AppendBytes(addrTypeDomain, byte(len(request.Address.Domain()))) buffer.Append([]byte(request.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 aesCipher, err := aes.NewCipher(request.UserId.CmdKey()) if err != nil { return nil, err } aesStream := cipher.NewCFBEncrypter(aesCipher, user.Int64Hash(counter)) aesStream.XORKeyStream(buffer.Value[encryptionBegin:encryptionEnd], buffer.Value[encryptionBegin:encryptionEnd]) return buffer, nil }
func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) { buffer := make([]byte, 256) nBytes, err := reader.Read(buffer[:user.IDBytesLen]) if err != nil { return nil, err } log.Debug("Read user hash: %v", buffer[:nBytes]) userId, timeSec, valid := r.vUserSet.GetUser(buffer[:nBytes]) if !valid { return nil, ErrorInvalidUser } aesCipher, err := aes.NewCipher(userId.CmdKey()) if err != nil { return nil, err } aesStream := cipher.NewCFBDecrypter(aesCipher, user.Int64Hash(timeSec)) decryptor := v2io.NewCryptionReader(aesStream, reader) if err != nil { return nil, err } nBytes, err = decryptor.Read(buffer[0:1]) if err != nil { return nil, err } randomLength := buffer[0] if randomLength <= 0 || randomLength > 32 { return nil, fmt.Errorf("Unexpected random length %d", randomLength) } _, err = decryptor.Read(buffer[:randomLength]) if err != nil { return nil, err } nBytes, err = decryptor.Read(buffer[0:1]) if err != nil { return nil, err } request := &VMessRequest{ UserId: *userId, Version: buffer[0], } if request.Version != Version { log.Error("Unknown VMess version %d", request.Version) return nil, ErrorInvalidVerion } // TODO: check number of bytes returned _, err = decryptor.Read(request.RequestIV[:]) if err != nil { return nil, err } _, err = decryptor.Read(request.RequestKey[:]) if err != nil { return nil, err } _, err = decryptor.Read(request.ResponseHeader[:]) if err != nil { return nil, err } _, err = decryptor.Read(buffer[0:1]) if err != nil { return nil, err } request.Command = buffer[0] _, err = decryptor.Read(buffer[0:2]) if err != nil { return nil, err } port := binary.BigEndian.Uint16(buffer[0:2]) _, err = decryptor.Read(buffer[0:1]) if err != nil { return nil, err } switch buffer[0] { case addrTypeIPv4: _, err = decryptor.Read(buffer[1:5]) if err != nil { return nil, err } request.Address = v2net.IPAddress(buffer[1:5], port) case addrTypeIPv6: _, err = decryptor.Read(buffer[1:17]) if err != nil { return nil, err } request.Address = v2net.IPAddress(buffer[1:17], port) case addrTypeDomain: _, err = decryptor.Read(buffer[1:2]) if err != nil { return nil, err } domainLength := buffer[1] _, err = decryptor.Read(buffer[2 : 2+domainLength]) if err != nil { return nil, err } request.Address = v2net.DomainAddress(string(buffer[2:2+domainLength]), port) } _, err = decryptor.Read(buffer[0:1]) if err != nil { return nil, err } randomLength = buffer[0] _, err = decryptor.Read(buffer[:randomLength]) if err != nil { return nil, err } return request, nil }
// Read reads a VMessRequest from a byte stream. func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) { buffer := alloc.NewSmallBuffer() nBytes, err := v2net.ReadAllBytes(reader, buffer.Value[:config.IDBytesLen]) if err != nil { return nil, err } userId, timeSec, valid := r.vUserSet.GetUser(buffer.Value[:nBytes]) if !valid { return nil, proxy.InvalidAuthentication } aesCipher, err := aes.NewCipher(userId.CmdKey()) if err != nil { return nil, err } aesStream := cipher.NewCFBDecrypter(aesCipher, user.Int64Hash(timeSec)) decryptor := v2io.NewCryptionReader(aesStream, reader) if err != nil { return nil, err } nBytes, err = v2net.ReadAllBytes(decryptor, buffer.Value[:41]) if err != nil { return nil, err } bufferLen := nBytes request := &VMessRequest{ UserId: *userId, Version: buffer.Value[0], } if request.Version != Version { log.Warning("Invalid protocol version %d", request.Version) return nil, proxy.InvalidProtocolVersion } request.RequestIV = buffer.Value[1:17] // 16 bytes request.RequestKey = buffer.Value[17:33] // 16 bytes request.ResponseHeader = buffer.Value[33:37] // 4 bytes request.Command = buffer.Value[37] port := binary.BigEndian.Uint16(buffer.Value[38:40]) switch buffer.Value[40] { case addrTypeIPv4: _, err = v2net.ReadAllBytes(decryptor, buffer.Value[41:45]) // 4 bytes bufferLen += 4 if err != nil { return nil, err } request.Address = v2net.IPAddress(buffer.Value[41:45], port) case addrTypeIPv6: _, err = v2net.ReadAllBytes(decryptor, buffer.Value[41:57]) // 16 bytes bufferLen += 16 if err != nil { return nil, err } request.Address = v2net.IPAddress(buffer.Value[41:57], port) case addrTypeDomain: _, err = v2net.ReadAllBytes(decryptor, buffer.Value[41:42]) if err != nil { return nil, err } domainLength := int(buffer.Value[41]) _, err = v2net.ReadAllBytes(decryptor, buffer.Value[42:42+domainLength]) if err != nil { return nil, err } bufferLen += 1 + domainLength request.Address = v2net.DomainAddress(string(buffer.Value[42:42+domainLength]), port) } _, err = v2net.ReadAllBytes(decryptor, buffer.Value[bufferLen:bufferLen+4]) if err != nil { return nil, err } fnv1a := fnv.New32a() fnv1a.Write(buffer.Value[:bufferLen]) actualHash := fnv1a.Sum32() expectedHash := binary.BigEndian.Uint32(buffer.Value[bufferLen : bufferLen+4]) if actualHash != expectedHash { return nil, transport.CorruptedPacket } return request, nil }
// Read reads a VMessRequest from a byte stream. func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) { buffer := make([]byte, 256) nBytes, err := reader.Read(buffer[:user.IDBytesLen]) if err != nil { return nil, err } log.Debug("Read user hash: %v", buffer[:nBytes]) userId, timeSec, valid := r.vUserSet.GetUser(buffer[:nBytes]) if !valid { return nil, errors.NewAuthenticationError(buffer[:nBytes]) } aesCipher, err := aes.NewCipher(userId.CmdKey()) if err != nil { return nil, err } aesStream := cipher.NewCFBDecrypter(aesCipher, user.Int64Hash(timeSec)) decryptor := v2io.NewCryptionReader(aesStream, reader) if err != nil { return nil, err } nBytes, err = decryptor.Read(buffer[:41]) if err != nil { return nil, err } bufferLen := nBytes request := &VMessRequest{ UserId: *userId, Version: buffer[0], } if request.Version != Version { return nil, errors.NewProtocolVersionError(int(request.Version)) } copy(request.RequestIV[:], buffer[1:17]) // 16 bytes copy(request.RequestKey[:], buffer[17:33]) // 16 bytes copy(request.ResponseHeader[:], buffer[33:37]) // 4 bytes request.Command = buffer[37] port := binary.BigEndian.Uint16(buffer[38:40]) switch buffer[40] { case addrTypeIPv4: _, err = decryptor.Read(buffer[41:45]) // 4 bytes bufferLen += 4 if err != nil { return nil, err } request.Address = v2net.IPAddress(buffer[41:45], port) case addrTypeIPv6: _, err = decryptor.Read(buffer[41:57]) // 16 bytes bufferLen += 16 if err != nil { return nil, err } request.Address = v2net.IPAddress(buffer[41:57], port) case addrTypeDomain: _, err = decryptor.Read(buffer[41:42]) if err != nil { return nil, err } domainLength := int(buffer[41]) _, err = decryptor.Read(buffer[42 : 42+domainLength]) if err != nil { return nil, err } bufferLen += 1 + domainLength request.Address = v2net.DomainAddress(string(buffer[42:42+domainLength]), port) } _, err = decryptor.Read(buffer[bufferLen : bufferLen+4]) if err != nil { return nil, err } fnv1a := fnv.New32a() fnv1a.Write(buffer[:bufferLen]) actualHash := fnv1a.Sum32() expectedHash := binary.BigEndian.Uint32(buffer[bufferLen : bufferLen+4]) if actualHash != expectedHash { return nil, errors.NewCorruptedPacketError() } return request, nil }
// Read reads a VMessRequest from a byte stream. func (this *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) { buffer := alloc.NewSmallBuffer() defer buffer.Release() nBytes, err := v2net.ReadAllBytes(reader, buffer.Value[:vmess.IDBytesLen]) if err != nil { log.Debug("VMess: Failed to read request ID (%d bytes): %v", nBytes, err) return nil, err } userObj, timeSec, valid := this.vUserSet.GetUser(buffer.Value[:nBytes]) if !valid { return nil, proxy.InvalidAuthentication } aesStream, err := v2crypto.NewAesDecryptionStream(userObj.ID().CmdKey(), user.Int64Hash(timeSec)) if err != nil { log.Debug("VMess: Failed to create AES stream: %v", err) return nil, err } decryptor := v2crypto.NewCryptionReader(aesStream, reader) nBytes, err = v2net.ReadAllBytes(decryptor, buffer.Value[:41]) if err != nil { log.Debug("VMess: Failed to read request header (%d bytes): %v", nBytes, err) return nil, err } bufferLen := nBytes request := &VMessRequest{ User: userObj, Version: buffer.Value[0], } if request.Version != Version { log.Warning("VMess: Invalid protocol version %d", request.Version) return nil, proxy.InvalidProtocolVersion } request.RequestIV = append([]byte(nil), buffer.Value[1:17]...) // 16 bytes request.RequestKey = append([]byte(nil), buffer.Value[17:33]...) // 16 bytes request.ResponseHeader = append([]byte(nil), buffer.Value[33:37]...) // 4 bytes request.Command = buffer.Value[37] request.Port = v2net.PortFromBytes(buffer.Value[38:40]) switch buffer.Value[40] { case addrTypeIPv4: nBytes, err = v2net.ReadAllBytes(decryptor, buffer.Value[41:45]) // 4 bytes bufferLen += 4 if err != nil { log.Debug("VMess: Failed to read target IPv4 (%d bytes): %v", nBytes, err) return nil, err } request.Address = v2net.IPAddress(buffer.Value[41:45]) case addrTypeIPv6: nBytes, err = v2net.ReadAllBytes(decryptor, buffer.Value[41:57]) // 16 bytes bufferLen += 16 if err != nil { log.Debug("VMess: Failed to read target IPv6 (%d bytes): %v", nBytes, err) return nil, err } request.Address = v2net.IPAddress(buffer.Value[41:57]) case addrTypeDomain: nBytes, err = v2net.ReadAllBytes(decryptor, buffer.Value[41:42]) if err != nil { log.Debug("VMess: Failed to read target domain (%d bytes): %v", nBytes, err) return nil, err } domainLength := int(buffer.Value[41]) if domainLength == 0 { return nil, transport.CorruptedPacket } nBytes, err = v2net.ReadAllBytes(decryptor, buffer.Value[42:42+domainLength]) if err != nil { log.Debug("VMess: Failed to read target domain (%d bytes): %v", nBytes, err) return nil, err } bufferLen += 1 + domainLength domainBytes := append([]byte(nil), buffer.Value[42:42+domainLength]...) request.Address = v2net.DomainAddress(string(domainBytes)) } nBytes, err = v2net.ReadAllBytes(decryptor, buffer.Value[bufferLen:bufferLen+4]) if err != nil { log.Debug("VMess: Failed to read checksum (%d bytes): %v", nBytes, err) return nil, err } fnv1a := fnv.New32a() fnv1a.Write(buffer.Value[:bufferLen]) actualHash := fnv1a.Sum32() expectedHash := binary.BigEndian.Uint32(buffer.Value[bufferLen : bufferLen+4]) if actualHash != expectedHash { return nil, transport.CorruptedPacket } return request, nil }