|  | @@ -0,0 +1,99 @@
 | 
											
												
													
														|  | 
 |  | +package raw
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +import (
 | 
											
												
													
														|  | 
 |  | +	"crypto/md5"
 | 
											
												
													
														|  | 
 |  | +	"crypto/rand"
 | 
											
												
													
														|  | 
 |  | +	"hash/fnv"
 | 
											
												
													
														|  | 
 |  | +	"io"
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	"github.com/v2ray/v2ray-core/common/alloc"
 | 
											
												
													
														|  | 
 |  | +	"github.com/v2ray/v2ray-core/common/crypto"
 | 
											
												
													
														|  | 
 |  | +	"github.com/v2ray/v2ray-core/common/protocol"
 | 
											
												
													
														|  | 
 |  | +)
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +func hashTimestamp(t protocol.Timestamp) []byte {
 | 
											
												
													
														|  | 
 |  | +	once := t.Bytes()
 | 
											
												
													
														|  | 
 |  | +	bytes := make([]byte, 0, 32)
 | 
											
												
													
														|  | 
 |  | +	bytes = append(bytes, once...)
 | 
											
												
													
														|  | 
 |  | +	bytes = append(bytes, once...)
 | 
											
												
													
														|  | 
 |  | +	bytes = append(bytes, once...)
 | 
											
												
													
														|  | 
 |  | +	bytes = append(bytes, once...)
 | 
											
												
													
														|  | 
 |  | +	return bytes
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +type ClientSession struct {
 | 
											
												
													
														|  | 
 |  | +	requestBodyKey  []byte
 | 
											
												
													
														|  | 
 |  | +	requestBodyIV   []byte
 | 
											
												
													
														|  | 
 |  | +	responseHeader  byte
 | 
											
												
													
														|  | 
 |  | +	responseBodyKey []byte
 | 
											
												
													
														|  | 
 |  | +	responseBodyIV  []byte
 | 
											
												
													
														|  | 
 |  | +	idHash          protocol.IDHash
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +func NewClientSession(idHash protocol.IDHash) *ClientSession {
 | 
											
												
													
														|  | 
 |  | +	randomBytes := make([]byte, 33) // 16 + 16 + 1
 | 
											
												
													
														|  | 
 |  | +	rand.Read(randomBytes)
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	session := &ClientSession{}
 | 
											
												
													
														|  | 
 |  | +	session.requestBodyKey = randomBytes[:16]
 | 
											
												
													
														|  | 
 |  | +	session.requestBodyIV = randomBytes[16:32]
 | 
											
												
													
														|  | 
 |  | +	session.responseHeader = randomBytes[32]
 | 
											
												
													
														|  | 
 |  | +	session.idHash = idHash
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	return session
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +func (this *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, writer io.Writer) {
 | 
											
												
													
														|  | 
 |  | +	buffer := alloc.NewSmallBuffer().Clear()
 | 
											
												
													
														|  | 
 |  | +	defer buffer.Release()
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	timestamp := protocol.NewTimestampGenerator(protocol.NowTime(), 30)()
 | 
											
												
													
														|  | 
 |  | +	idHash := this.idHash(header.User.AnyValidID().Bytes())
 | 
											
												
													
														|  | 
 |  | +	idHash.Write(timestamp.Bytes())
 | 
											
												
													
														|  | 
 |  | +	idHash.Sum(buffer.Value)
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	encryptionBegin := buffer.Len()
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	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()))
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	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(hashTimestamp(timestamp))
 | 
											
												
													
														|  | 
 |  | +	iv := timestampHash.Sum(nil)
 | 
											
												
													
														|  | 
 |  | +	aesStream := crypto.NewAesEncryptionStream(header.User.ID.CmdKey(), iv)
 | 
											
												
													
														|  | 
 |  | +	aesStream.XORKeyStream(buffer.Value[encryptionBegin:encryptionEnd], buffer.Value[encryptionBegin:encryptionEnd])
 | 
											
												
													
														|  | 
 |  | +	writer.Write(buffer.Value)
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	return
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +func (this *ClientSession) EncodeRequestBody(writer io.Writer) io.Writer {
 | 
											
												
													
														|  | 
 |  | +	aesStream := crypto.NewAesEncryptionStream(this.requestBodyKey, this.requestBodyIV)
 | 
											
												
													
														|  | 
 |  | +	return crypto.NewCryptionWriter(aesStream, writer)
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 |