From 06b92bddcf86530c8baa60e77e82fb54ca1e9b38 Mon Sep 17 00:00:00 2001 From: v2ray Date: Fri, 29 Jan 2016 10:57:52 +0100 Subject: [PATCH] authenticator --- common/alloc/buffer.go | 6 ++++++ common/crypto/authenticator.go | 6 ++++++ common/net/transport.go | 39 ++++++++++++++++++++++++++++++++++ common/serial/bytes.go | 8 +++++++ 4 files changed, 59 insertions(+) create mode 100644 common/crypto/authenticator.go diff --git a/common/alloc/buffer.go b/common/alloc/buffer.go index 2bc51641..18d2c8c6 100644 --- a/common/alloc/buffer.go +++ b/common/alloc/buffer.go @@ -5,6 +5,12 @@ import ( "sync" ) +func Release(buffer *Buffer) { + if buffer != nil { + buffer.Release() + } +} + // Buffer is a recyclable allocation of a byte array. Buffer.Release() recycles // the buffer into an internal buffer pool, in order to recreate a buffer more // quickly. diff --git a/common/crypto/authenticator.go b/common/crypto/authenticator.go new file mode 100644 index 00000000..51072e03 --- /dev/null +++ b/common/crypto/authenticator.go @@ -0,0 +1,6 @@ +package crypto + +type Authenticator interface { + AuthBytes() int + Authenticate(auth []byte, data []byte) []byte +} diff --git a/common/net/transport.go b/common/net/transport.go index daa0dd1d..a527fbb5 100644 --- a/common/net/transport.go +++ b/common/net/transport.go @@ -4,6 +4,9 @@ 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. @@ -17,6 +20,42 @@ func ReadFrom(reader io.Reader, buffer *alloc.Buffer) (*alloc.Buffer, error) { return buffer, err } +func ReadChunk(reader io.Reader, buffer *alloc.Buffer) (*alloc.Buffer, error) { + if buffer == nil { + buffer = alloc.NewBuffer() + } + if _, err := io.ReadFull(reader, buffer.Value[:2]); err != nil { + alloc.Release(buffer) + return nil, err + } + length := serial.BytesLiteral(buffer.Value[:2]).Uint16Value() + if _, err := io.ReadFull(reader, buffer.Value[:length]); err != nil { + alloc.Release(buffer) + return nil, err + } + buffer.Slice(0, int(length)) + return buffer, nil +} + +func ReadAuthenticatedChunk(reader io.Reader, auth crypto.Authenticator, buffer *alloc.Buffer) (*alloc.Buffer, error) { + buffer, err := ReadChunk(reader, buffer) + if err != nil { + alloc.Release(buffer) + return nil, err + } + authSize := auth.AuthBytes() + + authBytes := auth.Authenticate(nil, buffer.Value[authSize:]) + + if !serial.BytesLiteral(authBytes).Equals(serial.BytesLiteral(buffer.Value[:authSize])) { + alloc.Release(buffer) + return nil, transport.CorruptedPacket + } + buffer.SliceFrom(authSize) + + return buffer, nil +} + // ReaderToChan dumps all content from a given reader to a chan by constantly reading it until EOF. func ReaderToChan(stream chan<- *alloc.Buffer, reader io.Reader) error { allocate := alloc.NewBuffer diff --git a/common/serial/bytes.go b/common/serial/bytes.go index 0b315aa0..8305bfc2 100644 --- a/common/serial/bytes.go +++ b/common/serial/bytes.go @@ -1,5 +1,9 @@ package serial +import ( + "bytes" +) + type Bytes interface { Bytes() []byte } @@ -10,6 +14,10 @@ func (this BytesLiteral) Value() []byte { return []byte(this) } +func (this BytesLiteral) Equals(another BytesLiteral) bool { + return bytes.Equal(this.Value(), another.Value()) +} + func (this BytesLiteral) Uint8Value() uint8 { return this.Value()[0] }