1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2025-12-29 13:35:20 -05:00

VMess AEAD Experiment

This commit is contained in:
Shelikhoo
2020-06-06 17:11:30 +08:00
parent b610fc0a70
commit 9bf07b1f26
11 changed files with 621 additions and 45 deletions

View File

@@ -1,12 +1,19 @@
package encoding
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/md5"
"crypto/rand"
"crypto/sha256"
"encoding/binary"
"fmt"
"hash"
"hash/fnv"
"io"
"os"
vmessaead "v2ray.com/core/proxy/vmess/aead"
"golang.org/x/crypto/chacha20poly1305"
@@ -37,6 +44,8 @@ type ClientSession struct {
responseBodyIV [16]byte
responseReader io.Reader
responseHeader byte
isAEADRequest bool
}
// NewClientSession creates a new ClientSession.
@@ -45,11 +54,29 @@ func NewClientSession(idHash protocol.IDHash) *ClientSession {
common.Must2(rand.Read(randomBytes))
session := &ClientSession{}
session.isAEADRequest = false
if vmessexp, vmessexp_found := os.LookupEnv("VMESSAEADEXPERIMENT"); vmessexp_found {
if vmessexp == "y" {
session.isAEADRequest = true
fmt.Println("=======VMESSAEADEXPERIMENT ENABLED========")
}
}
copy(session.requestBodyKey[:], randomBytes[:16])
copy(session.requestBodyIV[:], randomBytes[16:32])
session.responseHeader = randomBytes[32]
session.responseBodyKey = md5.Sum(session.requestBodyKey[:])
session.responseBodyIV = md5.Sum(session.requestBodyIV[:])
if !session.isAEADRequest {
session.responseBodyKey = md5.Sum(session.requestBodyKey[:])
session.responseBodyIV = md5.Sum(session.requestBodyIV[:])
} else {
BodyKey := sha256.Sum256(session.requestBodyKey[:])
copy(session.responseBodyKey[:], BodyKey[:16])
BodyIV := sha256.Sum256(session.requestBodyKey[:])
copy(session.responseBodyIV[:], BodyIV[:16])
}
session.idHash = idHash
return session
@@ -58,9 +85,11 @@ func NewClientSession(idHash protocol.IDHash) *ClientSession {
func (c *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, writer io.Writer) error {
timestamp := protocol.NewTimestampGenerator(protocol.NowTime(), 30)()
account := header.User.Account.(*vmess.MemoryAccount)
idHash := c.idHash(account.AnyValidID().Bytes())
common.Must2(serial.WriteUint64(idHash, uint64(timestamp)))
common.Must2(writer.Write(idHash.Sum(nil)))
if !c.isAEADRequest {
idHash := c.idHash(account.AnyValidID().Bytes())
common.Must2(serial.WriteUint64(idHash, uint64(timestamp)))
common.Must2(writer.Write(idHash.Sum(nil)))
}
buffer := buf.New()
defer buffer.Release()
@@ -92,10 +121,18 @@ func (c *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, writ
fnv1a.Sum(hashBytes[:0])
}
iv := hashTimestamp(md5.New(), timestamp)
aesStream := crypto.NewAesEncryptionStream(account.ID.CmdKey(), iv[:])
aesStream.XORKeyStream(buffer.Bytes(), buffer.Bytes())
common.Must2(writer.Write(buffer.Bytes()))
if !c.isAEADRequest {
iv := hashTimestamp(md5.New(), timestamp)
aesStream := crypto.NewAesEncryptionStream(account.ID.CmdKey(), iv[:])
aesStream.XORKeyStream(buffer.Bytes(), buffer.Bytes())
common.Must2(writer.Write(buffer.Bytes()))
} else {
var fixedLengthCmdKey [16]byte
copy(fixedLengthCmdKey[:], account.ID.CmdKey())
vmessout := vmessaead.SealVMessAEADHeader(fixedLengthCmdKey, buffer.Bytes())
common.Must2(io.Copy(writer, bytes.NewReader(vmessout)))
}
return nil
}
@@ -161,8 +198,49 @@ func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
}
func (c *ClientSession) DecodeResponseHeader(reader io.Reader) (*protocol.ResponseHeader, error) {
aesStream := crypto.NewAesDecryptionStream(c.responseBodyKey[:], c.responseBodyIV[:])
c.responseReader = crypto.NewCryptionReader(aesStream, reader)
if !c.isAEADRequest {
aesStream := crypto.NewAesDecryptionStream(c.responseBodyKey[:], c.responseBodyIV[:])
c.responseReader = crypto.NewCryptionReader(aesStream, reader)
} else {
resph := vmessaead.KDF16(c.responseBodyKey[:], "AEAD Resp Header Len Key")
respi := vmessaead.KDF(c.responseBodyIV[:], "AEAD Resp Header Len IV")[:12]
aesblock := common.Must2(aes.NewCipher(resph)).(cipher.Block)
aeadHeader := common.Must2(cipher.NewGCM(aesblock)).(cipher.AEAD)
var AEADLen [18]byte
var lenresp int
var lenrespr uint16
if _, err := io.ReadFull(reader, AEADLen[:]); err != nil {
return nil, newError("Unable to Read Header Len").Base(err)
}
if AEADLend, err := aeadHeader.Open(nil, respi, AEADLen[:], nil); err != nil {
return nil, newError("Failed To Decrypt Length").Base(err)
} else {
common.Must(binary.Read(bytes.NewReader(AEADLend), binary.BigEndian, &lenrespr))
lenresp = int(lenrespr)
}
resphc := vmessaead.KDF16(c.responseBodyKey[:], "AEAD Resp Header Key")
respic := vmessaead.KDF(c.responseBodyIV[:], "AEAD Resp Header IV")[:12]
aesblockc := common.Must2(aes.NewCipher(resphc)).(cipher.Block)
aeadHeaderc := common.Must2(cipher.NewGCM(aesblockc)).(cipher.AEAD)
respPayload := make([]byte, lenresp+16)
if _, err := io.ReadFull(reader, respPayload); err != nil {
return nil, newError("Unable to Read Header Data").Base(err)
}
if AEADData, err := aeadHeaderc.Open(nil, respic, respPayload, nil); err != nil {
return nil, newError("Failed To Decrypt Payload").Base(err)
} else {
c.responseReader = bytes.NewReader(AEADData)
}
}
buffer := buf.StackNew()
defer buffer.Release()
@@ -192,7 +270,10 @@ func (c *ClientSession) DecodeResponseHeader(reader io.Reader) (*protocol.Respon
header.Command = command
}
}
if c.isAEADRequest {
aesStream := crypto.NewAesDecryptionStream(c.responseBodyKey[:], c.responseBodyIV[:])
c.responseReader = crypto.NewCryptionReader(aesStream, reader)
}
return header, nil
}