diff --git a/common/crypto/authenticator.go b/common/crypto/authenticator.go deleted file mode 100644 index 4cb7f8952..000000000 --- a/common/crypto/authenticator.go +++ /dev/null @@ -1,6 +0,0 @@ -package crypto - -type Authenticator interface { - AuthSize() int - Authenticate(auth []byte, data []byte) []byte -} diff --git a/common/io/reader.go b/common/io/reader.go index fd7c073c2..98e0f4c29 100644 --- a/common/io/reader.go +++ b/common/io/reader.go @@ -4,9 +4,6 @@ import ( "io" "github.com/v2ray/v2ray-core/common/alloc" - "github.com/v2ray/v2ray-core/common/crypto" - "github.com/v2ray/v2ray-core/common/serial" - "github.com/v2ray/v2ray-core/transport" ) // ReadFrom reads from a reader and put all content to a buffer. @@ -55,68 +52,3 @@ func (this *AdaptiveReader) Read() (*alloc.Buffer, error) { } return buffer, nil } - -type ChunkReader struct { - reader io.Reader -} - -func NewChunkReader(reader io.Reader) *ChunkReader { - return &ChunkReader{ - reader: reader, - } -} - -func (this *ChunkReader) Read() (*alloc.Buffer, error) { - buffer := alloc.NewLargeBuffer() - if _, err := io.ReadFull(this.reader, buffer.Value[:2]); err != nil { - alloc.Release(buffer) - return nil, err - } - length := serial.BytesLiteral(buffer.Value[:2]).Uint16Value() - if _, err := io.ReadFull(this.reader, buffer.Value[:length]); err != nil { - alloc.Release(buffer) - return nil, err - } - buffer.Slice(0, int(length)) - return buffer, nil -} - -type AuthenticationReader struct { - reader Reader - authenticator crypto.Authenticator - authBeforePayload bool -} - -func NewAuthenticationReader(reader Reader, auth crypto.Authenticator, authBeforePayload bool) *AuthenticationReader { - return &AuthenticationReader{ - reader: reader, - authenticator: auth, - authBeforePayload: authBeforePayload, - } -} - -func (this *AuthenticationReader) Read() (*alloc.Buffer, error) { - buffer, err := this.reader.Read() - if err != nil { - alloc.Release(buffer) - return nil, err - } - - authSize := this.authenticator.AuthSize() - var authBytes, payloadBytes []byte - if this.authBeforePayload { - authBytes = buffer.Value[:authSize] - payloadBytes = buffer.Value[authSize:] - } else { - payloadBytes = buffer.Value[:authSize] - authBytes = buffer.Value[authSize:] - } - - actualAuthBytes := this.authenticator.Authenticate(nil, payloadBytes) - if !serial.BytesLiteral(authBytes).Equals(serial.BytesLiteral(actualAuthBytes)) { - alloc.Release(buffer) - return nil, transport.CorruptedPacket - } - buffer.Value = payloadBytes - return buffer, nil -} diff --git a/proxy/shadowsocks/ota.go b/proxy/shadowsocks/ota.go index a30dd3d01..6b0fa2e9a 100644 --- a/proxy/shadowsocks/ota.go +++ b/proxy/shadowsocks/ota.go @@ -3,8 +3,12 @@ package shadowsocks import ( "crypto/hmac" "crypto/sha1" + "io" + "github.com/v2ray/v2ray-core/common/alloc" + "github.com/v2ray/v2ray-core/common/log" "github.com/v2ray/v2ray-core/common/serial" + "github.com/v2ray/v2ray-core/transport" ) const ( @@ -23,10 +27,6 @@ func NewAuthenticator(keygen KeyGenerator) *Authenticator { } } -func (this *Authenticator) AuthSize() int { - return AuthSize -} - func (this *Authenticator) Authenticate(auth []byte, data []byte) []byte { hasher := hmac.New(sha1.New, this.key()) hasher.Write(data) @@ -53,3 +53,44 @@ func ChunkKeyGenerator(iv []byte) func() []byte { return newKey } } + +type ChunkReader struct { + reader io.Reader + auth *Authenticator +} + +func NewChunkReader(reader io.Reader, auth *Authenticator) *ChunkReader { + return &ChunkReader{ + reader: reader, + auth: auth, + } +} + +func (this *ChunkReader) Read() (*alloc.Buffer, error) { + buffer := alloc.NewLargeBuffer() + if _, err := io.ReadFull(this.reader, buffer.Value[:2]); err != nil { + alloc.Release(buffer) + return nil, err + } + // There is a potential buffer overflow here. Large buffer is 64K bytes, + // while uin16 + 10 will be more than that + length := serial.BytesLiteral(buffer.Value[:2]).Uint16Value() + AuthSize + if _, err := io.ReadFull(this.reader, buffer.Value[:length]); err != nil { + alloc.Release(buffer) + return nil, err + } + buffer.Slice(0, int(length)) + + authBytes := buffer.Value[:AuthSize] + payload := buffer.Value[AuthSize:] + + actualAuthBytes := this.auth.Authenticate(nil, payload) + if !serial.BytesLiteral(authBytes).Equals(serial.BytesLiteral(actualAuthBytes)) { + alloc.Release(buffer) + log.Debug("AuthenticationReader: Unexpected auth: ", authBytes) + return nil, transport.CorruptedPacket + } + buffer.Value = payload + + return buffer, nil +} diff --git a/proxy/shadowsocks/protocol.go b/proxy/shadowsocks/protocol.go index bc3af8df5..626075806 100644 --- a/proxy/shadowsocks/protocol.go +++ b/proxy/shadowsocks/protocol.go @@ -86,7 +86,7 @@ func ReadRequest(reader io.Reader, auth *Authenticator) (*Request, error) { lenBuffer += 2 if request.OTA { - authBytes := buffer.Value[lenBuffer : lenBuffer+auth.AuthSize()] + authBytes := buffer.Value[lenBuffer : lenBuffer+AuthSize] _, err = io.ReadFull(reader, authBytes) if err != nil { log.Error("Shadowsocks: Failed to read OTA: ", err) diff --git a/proxy/shadowsocks/shadowsocks.go b/proxy/shadowsocks/shadowsocks.go index bd6832e85..19d074182 100644 --- a/proxy/shadowsocks/shadowsocks.go +++ b/proxy/shadowsocks/shadowsocks.go @@ -155,7 +155,7 @@ func (this *Shadowsocks) handleConnection(conn *hub.TCPConn) { return } - request, err := ReadRequest(reader, NewAuthenticator(HeaderKeyGenerator(key, iv))) + request, err := ReadRequest(reader, NewAuthenticator(HeaderKeyGenerator(iv, key))) if err != nil { return } @@ -188,7 +188,7 @@ func (this *Shadowsocks) handleConnection(conn *hub.TCPConn) { var payloadReader v2io.Reader if request.OTA { payloadAuth := NewAuthenticator(ChunkKeyGenerator(iv)) - payloadReader = v2io.NewAuthenticationReader(v2io.NewChunkReader(reader), payloadAuth, true) + payloadReader = NewChunkReader(reader, payloadAuth) } else { payloadReader = v2io.NewAdaptiveReader(reader) }