Prechádzať zdrojové kódy

Refactor AES encryption/decryption

V2Ray 10 rokov pred
rodič
commit
a46db069fb

+ 62 - 0
common/crypto/aes.go

@@ -0,0 +1,62 @@
+package crypto
+
+import (
+	"crypto/aes"
+	"crypto/cipher"
+	"io"
+)
+
+func NewAesDecryptionStream(key []byte, iv []byte) (cipher.Stream, error) {
+	aesBlock, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+
+	return cipher.NewCFBDecrypter(aesBlock, iv), nil
+}
+
+func NewAesEncryptionStream(key []byte, iv []byte) (cipher.Stream, error) {
+	aesBlock, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+
+	return cipher.NewCFBEncrypter(aesBlock, iv), nil
+}
+
+type cryptionReader struct {
+	stream cipher.Stream
+	reader io.Reader
+}
+
+func NewCryptionReader(stream cipher.Stream, reader io.Reader) io.Reader {
+	return &cryptionReader{
+		stream: stream,
+		reader: reader,
+	}
+}
+
+func (this *cryptionReader) Read(data []byte) (int, error) {
+	nBytes, err := this.reader.Read(data)
+	if nBytes > 0 {
+		this.stream.XORKeyStream(data[:nBytes], data[:nBytes])
+	}
+	return nBytes, err
+}
+
+type cryptionWriter struct {
+	stream cipher.Stream
+	writer io.Writer
+}
+
+func NewCryptionWriter(stream cipher.Stream, writer io.Writer) io.Writer {
+	return &cryptionWriter{
+		stream: stream,
+		writer: writer,
+	}
+}
+
+func (this *cryptionWriter) Write(data []byte) (int, error) {
+	this.stream.XORKeyStream(data, data)
+	return this.writer.Write(data)
+}

+ 0 - 27
common/io/aes.go

@@ -1,27 +0,0 @@
-package io
-
-import (
-	"crypto/aes"
-	"crypto/cipher"
-	"io"
-)
-
-func NewAesDecryptReader(key []byte, iv []byte, reader io.Reader) (*CryptionReader, error) {
-	aesBlock, err := aes.NewCipher(key)
-	if err != nil {
-		return nil, err
-	}
-
-	aesStream := cipher.NewCFBDecrypter(aesBlock, iv)
-	return NewCryptionReader(aesStream, reader), nil
-}
-
-func NewAesEncryptWriter(key []byte, iv []byte, writer io.Writer) (*CryptionWriter, error) {
-	aesBlock, err := aes.NewCipher(key)
-	if err != nil {
-		return nil, err
-	}
-
-	aesStream := cipher.NewCFBEncrypter(aesBlock, iv)
-	return NewCryptionWriter(aesStream, writer), nil
-}

+ 0 - 54
common/io/encryption.go

@@ -1,54 +0,0 @@
-package io
-
-import (
-	"crypto/cipher"
-	"io"
-)
-
-// CryptionReader is a general purpose reader that applies a stream cipher on top of a regular reader.
-type CryptionReader struct {
-	stream cipher.Stream
-	reader io.Reader
-}
-
-// NewCryptionReader creates a new CryptionReader instance from given stream cipher and reader.
-func NewCryptionReader(stream cipher.Stream, reader io.Reader) *CryptionReader {
-	return &CryptionReader{
-		stream: stream,
-		reader: reader,
-	}
-}
-
-// Read reads blocks from underlying reader, and crypt it. The content of blocks is modified in place.
-func (reader CryptionReader) Read(blocks []byte) (int, error) {
-	nBytes, err := reader.reader.Read(blocks)
-	if nBytes > 0 {
-		reader.stream.XORKeyStream(blocks[:nBytes], blocks[:nBytes])
-	}
-	return nBytes, err
-}
-
-// Cryption writer is a general purpose of byte stream writer that applies a stream cipher on top of a regular writer.
-type CryptionWriter struct {
-	stream cipher.Stream
-	writer io.Writer
-}
-
-// NewCryptionWriter creates a new CryptionWriter from given stream cipher and writer.
-func NewCryptionWriter(stream cipher.Stream, writer io.Writer) *CryptionWriter {
-	return &CryptionWriter{
-		stream: stream,
-		writer: writer,
-	}
-}
-
-// Crypt crypts the content of blocks without writing them into the underlying writer.
-func (writer CryptionWriter) Crypt(blocks []byte) {
-	writer.stream.XORKeyStream(blocks, blocks)
-}
-
-// Write crypts the content of blocks in place, and then writes the give blocks to underlying writer.
-func (writer CryptionWriter) Write(blocks []byte) (int, error) {
-	writer.Crypt(blocks)
-	return writer.writer.Write(blocks)
-}

+ 4 - 11
proxy/vmess/protocol/vmess.go

@@ -2,15 +2,13 @@
 package protocol
 
 import (
-	"crypto/aes"
-	"crypto/cipher"
 	"encoding/binary"
 	"hash/fnv"
 	"io"
 	"time"
 
 	"github.com/v2ray/v2ray-core/common/alloc"
-	v2io "github.com/v2ray/v2ray-core/common/io"
+	v2crypto "github.com/v2ray/v2ray-core/common/crypto"
 	"github.com/v2ray/v2ray-core/common/log"
 	v2net "github.com/v2ray/v2ray-core/common/net"
 	proxyerrors "github.com/v2ray/v2ray-core/proxy/common/errors"
@@ -80,16 +78,12 @@ func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) {
 		return nil, proxyerrors.InvalidAuthentication
 	}
 
-	aesCipher, err := aes.NewCipher(userObj.ID().CmdKey())
+	aesStream, err := v2crypto.NewAesDecryptionStream(userObj.ID().CmdKey(), user.Int64Hash(timeSec))
 	if err != nil {
 		return nil, err
 	}
-	aesStream := cipher.NewCFBDecrypter(aesCipher, user.Int64Hash(timeSec))
-	decryptor := v2io.NewCryptionReader(aesStream, reader)
 
-	if err != nil {
-		return nil, err
-	}
+	decryptor := v2crypto.NewCryptionReader(aesStream, reader)
 
 	nBytes, err = v2net.ReadAllBytes(decryptor, buffer.Value[:41])
 	if err != nil {
@@ -201,11 +195,10 @@ func (request *VMessRequest) ToBytes(idHash user.CounterHash, randomRangeInt64 u
 	buffer.AppendBytes(byte(fnvHash>>24), byte(fnvHash>>16), byte(fnvHash>>8), byte(fnvHash))
 	encryptionEnd += 4
 
-	aesCipher, err := aes.NewCipher(request.User.ID().CmdKey())
+	aesStream, err := v2crypto.NewAesEncryptionStream(request.User.ID().CmdKey(), user.Int64Hash(counter))
 	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

+ 8 - 6
proxy/vmess/vmessin.go

@@ -8,7 +8,7 @@ import (
 
 	"github.com/v2ray/v2ray-core/app"
 	"github.com/v2ray/v2ray-core/common/alloc"
-	v2io "github.com/v2ray/v2ray-core/common/io"
+	v2crypto "github.com/v2ray/v2ray-core/common/crypto"
 	"github.com/v2ray/v2ray-core/common/log"
 	v2net "github.com/v2ray/v2ray-core/common/net"
 	"github.com/v2ray/v2ray-core/common/retry"
@@ -98,12 +98,14 @@ func (handler *VMessInboundHandler) HandleConnection(connection *net.TCPConn) er
 	responseKey := md5.Sum(request.RequestKey)
 	responseIV := md5.Sum(request.RequestIV)
 
-	responseWriter, err := v2io.NewAesEncryptWriter(responseKey[:], responseIV[:], connection)
+	aesStream, err := v2crypto.NewAesEncryptionStream(responseKey[:], responseIV[:])
 	if err != nil {
-		log.Error("VMessIn: Failed to create encrypt writer: %v", err)
+		log.Error("VMessIn: Failed to create AES decryption stream: %v", err)
 		return err
 	}
 
+	responseWriter := v2crypto.NewCryptionWriter(aesStream, connection)
+
 	// Optimize for small response packet
 	buffer := alloc.NewLargeBuffer().Clear()
 	buffer.Append(request.ResponseHeader)
@@ -127,12 +129,12 @@ func handleInput(request *protocol.VMessRequest, reader io.Reader, input chan<-
 	defer close(input)
 	defer finish.Unlock()
 
-	requestReader, err := v2io.NewAesDecryptReader(request.RequestKey, request.RequestIV, reader)
+	aesStream, err := v2crypto.NewAesDecryptionStream(request.RequestKey, request.RequestIV)
 	if err != nil {
-		log.Error("VMessIn: Failed to create decrypt reader: %v", err)
+		log.Error("VMessIn: Failed to create AES decryption stream: %v", err)
 		return
 	}
-
+	requestReader := v2crypto.NewCryptionReader(aesStream, reader)
 	v2net.ReaderToChan(input, requestReader)
 }
 

+ 8 - 5
proxy/vmess/vmessin_udp.go

@@ -6,7 +6,7 @@ import (
 	"net"
 
 	"github.com/v2ray/v2ray-core/common/alloc"
-	v2io "github.com/v2ray/v2ray-core/common/io"
+	v2crypto "github.com/v2ray/v2ray-core/common/crypto"
 	"github.com/v2ray/v2ray-core/common/log"
 	v2net "github.com/v2ray/v2ray-core/common/net"
 	"github.com/v2ray/v2ray-core/proxy/vmess/protocol"
@@ -54,12 +54,13 @@ func (handler *VMessInboundHandler) AcceptPackets(conn *net.UDPConn) {
 		}
 		log.Access(addr.String(), request.Address.String(), log.AccessAccepted, "")
 
-		cryptReader, err := v2io.NewAesDecryptReader(request.RequestKey, request.RequestIV, reader)
+		aesStream, err := v2crypto.NewAesDecryptionStream(request.RequestKey, request.RequestIV)
 		if err != nil {
-			log.Error("VMessIn: Failed to create decrypt reader: %v", err)
+			log.Error("VMessIn: Failed to AES decryption stream: %v", err)
 			buffer.Release()
 			continue
 		}
+		cryptReader := v2crypto.NewCryptionReader(aesStream, reader)
 
 		data := alloc.NewBuffer()
 		nBytes, err = cryptReader.Read(data.Value)
@@ -86,11 +87,13 @@ func (handler *VMessInboundHandler) handlePacket(conn *net.UDPConn, request *pro
 	buffer := alloc.NewBuffer().Clear()
 	defer buffer.Release()
 
-	responseWriter, err := v2io.NewAesEncryptWriter(responseKey[:], responseIV[:], buffer)
+	aesStream, err := v2crypto.NewAesEncryptionStream(responseKey[:], responseIV[:])
 	if err != nil {
-		log.Error("VMessIn: Failed to create encrypt writer: %v", err)
+		log.Error("VMessIn: Failed to create AES encryption stream: %v", err)
 		return
 	}
+	responseWriter := v2crypto.NewCryptionWriter(aesStream, buffer)
+
 	responseWriter.Write(request.ResponseHeader)
 
 	hasData := false

+ 8 - 6
proxy/vmess/vmessout.go

@@ -9,7 +9,7 @@ import (
 	"sync"
 
 	"github.com/v2ray/v2ray-core/common/alloc"
-	v2io "github.com/v2ray/v2ray-core/common/io"
+	v2crypto "github.com/v2ray/v2ray-core/common/crypto"
 	"github.com/v2ray/v2ray-core/common/log"
 	v2net "github.com/v2ray/v2ray-core/common/net"
 	"github.com/v2ray/v2ray-core/proxy/common/connhandler"
@@ -114,11 +114,12 @@ func startCommunicate(request *protocol.VMessRequest, dest v2net.Destination, ra
 
 func handleRequest(conn net.Conn, request *protocol.VMessRequest, firstPacket v2net.Packet, input <-chan *alloc.Buffer, finish *sync.Mutex) {
 	defer finish.Unlock()
-	encryptRequestWriter, err := v2io.NewAesEncryptWriter(request.RequestKey[:], request.RequestIV[:], conn)
+	aesStream, err := v2crypto.NewAesEncryptionStream(request.RequestKey[:], request.RequestIV[:])
 	if err != nil {
-		log.Error("VMessOut: Failed to create encrypt writer: %v", err)
+		log.Error("VMessOut: Failed to create AES encryption stream: %v", err)
 		return
 	}
+	encryptRequestWriter := v2crypto.NewCryptionWriter(aesStream, conn)
 
 	buffer := alloc.NewBuffer().Clear()
 	buffer, err = request.ToBytes(user.NewTimeHash(user.HMACHash{}), user.GenerateRandomInt64InRange, buffer)
@@ -136,7 +137,7 @@ func handleRequest(conn net.Conn, request *protocol.VMessRequest, firstPacket v2
 	}
 
 	if firstChunk != nil {
-		encryptRequestWriter.Crypt(firstChunk.Value)
+		aesStream.XORKeyStream(firstChunk.Value, firstChunk.Value)
 		buffer.Append(firstChunk.Value)
 		firstChunk.Release()
 
@@ -160,11 +161,12 @@ func handleResponse(conn net.Conn, request *protocol.VMessRequest, output chan<-
 	responseKey := md5.Sum(request.RequestKey[:])
 	responseIV := md5.Sum(request.RequestIV[:])
 
-	decryptResponseReader, err := v2io.NewAesDecryptReader(responseKey[:], responseIV[:], conn)
+	aesStream, err := v2crypto.NewAesDecryptionStream(responseKey[:], responseIV[:])
 	if err != nil {
-		log.Error("VMessOut: Failed to create decrypt reader: %v", err)
+		log.Error("VMessOut: Failed to create AES encryption stream: %v", err)
 		return
 	}
+	decryptResponseReader := v2crypto.NewCryptionReader(aesStream, conn)
 
 	buffer, err := v2net.ReadFrom(decryptResponseReader, nil)
 	if err != nil {