1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-12-21 09:36:34 -05:00

global padding in vmess protocol

This commit is contained in:
Darien Raymond 2018-07-07 15:42:24 +02:00
parent 5db7a47694
commit f54a8735ab
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169
8 changed files with 90 additions and 33 deletions

View File

@ -2,6 +2,7 @@ package crypto
import (
"crypto/cipher"
"crypto/rand"
"io"
"v2ray.com/core/common"
@ -85,31 +86,39 @@ type AuthenticationReader struct {
reader *buf.BufferedReader
sizeParser ChunkSizeDecoder
transferType protocol.TransferType
padding PaddingLengthGenerator
size int32
paddingLen int32
}
func NewAuthenticationReader(auth Authenticator, sizeParser ChunkSizeDecoder, reader io.Reader, transferType protocol.TransferType) *AuthenticationReader {
func NewAuthenticationReader(auth Authenticator, sizeParser ChunkSizeDecoder, reader io.Reader, transferType protocol.TransferType, paddingLen PaddingLengthGenerator) *AuthenticationReader {
return &AuthenticationReader{
auth: auth,
reader: &buf.BufferedReader{Reader: buf.NewReader(reader)},
sizeParser: sizeParser,
transferType: transferType,
padding: paddingLen,
size: -1,
paddingLen: -1,
}
}
func (r *AuthenticationReader) readSize() (int32, error) {
func (r *AuthenticationReader) readSize() (int32, int32, error) {
if r.size != -1 {
s := r.size
r.size = -1
return s, nil
return s, r.paddingLen, nil
}
sizeBytes := make([]byte, r.sizeParser.SizeBytes())
if _, err := io.ReadFull(r.reader, sizeBytes); err != nil {
return 0, err
return 0, 0, err
}
var padding int32
if r.padding != nil {
padding = int32(r.padding.NextPaddingLen())
}
size, err := r.sizeParser.Decode(sizeBytes)
return int32(size), err
return int32(size), padding, err
}
var errSoft = newError("waiting for more data")
@ -119,18 +128,19 @@ func (r *AuthenticationReader) readInternal(soft bool) (*buf.Buffer, error) {
return nil, errSoft
}
size, err := r.readSize()
size, padding, err := r.readSize()
if err != nil {
return nil, err
}
if size == -2 || size == int32(r.auth.Overhead()) {
if size == -2 || size == int32(r.auth.Overhead())+padding {
r.size = -2
return nil, io.EOF
}
if soft && size > r.reader.BufferedBytes() {
r.size = size
r.paddingLen = padding
return nil, errSoft
}
@ -140,6 +150,8 @@ func (r *AuthenticationReader) readInternal(soft bool) (*buf.Buffer, error) {
return nil, err
}
size -= padding
rb, err := r.auth.Open(b.BytesTo(0), b.BytesTo(size))
if err != nil {
b.Release()
@ -179,23 +191,29 @@ type AuthenticationWriter struct {
writer buf.Writer
sizeParser ChunkSizeEncoder
transferType protocol.TransferType
padding PaddingLengthGenerator
}
func NewAuthenticationWriter(auth Authenticator, sizeParser ChunkSizeEncoder, writer io.Writer, transferType protocol.TransferType) *AuthenticationWriter {
func NewAuthenticationWriter(auth Authenticator, sizeParser ChunkSizeEncoder, writer io.Writer, transferType protocol.TransferType, padding PaddingLengthGenerator) *AuthenticationWriter {
return &AuthenticationWriter{
auth: auth,
writer: buf.NewWriter(writer),
sizeParser: sizeParser,
transferType: transferType,
padding: padding,
}
}
func (w *AuthenticationWriter) seal(b *buf.Buffer) (*buf.Buffer, error) {
encryptedSize := int(b.Len()) + w.auth.Overhead()
paddingSize := 0
if w.padding != nil {
paddingSize = int(w.padding.NextPaddingLen())
}
eb := buf.New()
common.Must(eb.Reset(func(bb []byte) (int, error) {
w.sizeParser.Encode(uint16(encryptedSize), bb[:0])
w.sizeParser.Encode(uint16(encryptedSize+paddingSize), bb[:0])
return int(w.sizeParser.SizeBytes()), nil
}))
if err := eb.AppendSupplier(func(bb []byte) (int, error) {
@ -205,6 +223,15 @@ func (w *AuthenticationWriter) seal(b *buf.Buffer) (*buf.Buffer, error) {
eb.Release()
return nil, err
}
if paddingSize > 0 {
if err := eb.AppendSupplier(func(bb []byte) (int, error) {
common.Must2(rand.Read(bb[:paddingSize]))
return paddingSize, nil
}); err != nil {
eb.Release()
return nil, err
}
}
return eb, nil
}
@ -212,7 +239,7 @@ func (w *AuthenticationWriter) seal(b *buf.Buffer) (*buf.Buffer, error) {
func (w *AuthenticationWriter) writeStream(mb buf.MultiBuffer) error {
defer mb.Release()
payloadSize := buf.Size - int32(w.auth.Overhead()) - w.sizeParser.SizeBytes()
payloadSize := buf.Size - int32(w.auth.Overhead()) - w.sizeParser.SizeBytes() - 64 /* padding buffer */
mb2Write := buf.NewMultiBufferCap(int32(len(mb) + 10))
for {

View File

@ -40,17 +40,17 @@ func TestAuthenticationReaderWriter(t *testing.T) {
AEAD: aead,
NonceGenerator: GenerateStaticBytes(iv),
AdditionalDataGenerator: GenerateEmptyBytes(),
}, PlainChunkSizeParser{}, cache, protocol.TransferTypeStream)
}, PlainChunkSizeParser{}, cache, protocol.TransferTypeStream, nil)
assert(writer.WriteMultiBuffer(buf.NewMultiBufferValue(payload)), IsNil)
assert(cache.Len(), Equals, int32(82658))
assert(cache.Len(), Equals, int32(82676))
assert(writer.WriteMultiBuffer(buf.MultiBuffer{}), IsNil)
reader := NewAuthenticationReader(&AEADAuthenticator{
AEAD: aead,
NonceGenerator: GenerateStaticBytes(iv),
AdditionalDataGenerator: GenerateEmptyBytes(),
}, PlainChunkSizeParser{}, cache, protocol.TransferTypeStream)
}, PlainChunkSizeParser{}, cache, protocol.TransferTypeStream, nil)
var mb buf.MultiBuffer
@ -90,7 +90,7 @@ func TestAuthenticationReaderWriterPacket(t *testing.T) {
AEAD: aead,
NonceGenerator: GenerateStaticBytes(iv),
AdditionalDataGenerator: GenerateEmptyBytes(),
}, PlainChunkSizeParser{}, cache, protocol.TransferTypePacket)
}, PlainChunkSizeParser{}, cache, protocol.TransferTypePacket, nil)
var payload buf.MultiBuffer
pb1 := buf.New()
@ -110,7 +110,7 @@ func TestAuthenticationReaderWriterPacket(t *testing.T) {
AEAD: aead,
NonceGenerator: GenerateStaticBytes(iv),
AdditionalDataGenerator: GenerateEmptyBytes(),
}, PlainChunkSizeParser{}, cache, protocol.TransferTypePacket)
}, PlainChunkSizeParser{}, cache, protocol.TransferTypePacket, nil)
mb, err := reader.ReadMultiBuffer()
assert(err, IsNil)

View File

@ -20,6 +20,10 @@ type ChunkSizeEncoder interface {
Encode(uint16, []byte) []byte
}
type PaddingLengthGenerator interface {
NextPaddingLen() uint16
}
type PlainChunkSizeParser struct{}
func (PlainChunkSizeParser) SizeBytes() int32 {

View File

@ -36,6 +36,8 @@ const (
RequestOptionConnectionReuse bitmask.Byte = 0x02
RequestOptionChunkMasking bitmask.Byte = 0x04
RequestOptionGlobalPadding bitmask.Byte = 0x08
)
type RequestHeader struct {

View File

@ -182,14 +182,14 @@ func (c *AEADCipher) NewEncryptionWriter(key []byte, iv []byte, writer io.Writer
auth := c.createAuthenticator(key, iv)
return crypto.NewAuthenticationWriter(auth, &crypto.AEADChunkSizeParser{
Auth: auth,
}, writer, protocol.TransferTypeStream), nil
}, writer, protocol.TransferTypeStream, nil), nil
}
func (c *AEADCipher) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {
auth := c.createAuthenticator(key, iv)
return crypto.NewAuthenticationReader(auth, &crypto.AEADChunkSizeParser{
Auth: auth,
}, reader, protocol.TransferTypeStream), nil
}, reader, protocol.TransferTypeStream, nil), nil
}
func (c *AEADCipher) EncodePacket(key []byte, b *buf.Buffer) error {

View File

@ -107,3 +107,7 @@ func (s *ShakeSizeParser) Encode(size uint16, b []byte) []byte {
mask := s.next()
return serial.Uint16ToBytes(mask^size, b[:0])
}
func (s *ShakeSizeParser) NextPaddingLen() uint16 {
return s.next() % 64
}

View File

@ -110,6 +110,11 @@ func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
if request.Option.Has(protocol.RequestOptionChunkMasking) {
sizeParser = NewShakeSizeParser(c.requestBodyIV[:])
}
var padding crypto.PaddingLengthGenerator = nil
if request.Option.Has(protocol.RequestOptionGlobalPadding) {
padding = sizeParser.(crypto.PaddingLengthGenerator)
}
switch request.Security {
case protocol.SecurityType_NONE:
if request.Option.Has(protocol.RequestOptionChunkStream) {
@ -121,7 +126,7 @@ func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
NonceGenerator: crypto.GenerateEmptyBytes(),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, protocol.TransferTypePacket)
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, protocol.TransferTypePacket, padding)
}
return buf.NewWriter(writer)
@ -134,7 +139,7 @@ func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
NonceGenerator: crypto.GenerateEmptyBytes(),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationWriter(auth, sizeParser, cryptionWriter, request.Command.TransferType())
return crypto.NewAuthenticationWriter(auth, sizeParser, cryptionWriter, request.Command.TransferType(), padding)
}
return buf.NewWriter(cryptionWriter)
@ -147,7 +152,7 @@ func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
NonceGenerator: GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType())
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)
case protocol.SecurityType_CHACHA20_POLY1305:
aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(c.requestBodyKey[:]))
@ -156,7 +161,7 @@ func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
NonceGenerator: GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType())
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)
default:
panic("Unknown security type.")
}
@ -202,6 +207,11 @@ func (c *ClientSession) DecodeResponseBody(request *protocol.RequestHeader, read
if request.Option.Has(protocol.RequestOptionChunkMasking) {
sizeParser = NewShakeSizeParser(c.responseBodyIV[:])
}
var padding crypto.PaddingLengthGenerator = nil
if request.Option.Has(protocol.RequestOptionGlobalPadding) {
padding = sizeParser.(crypto.PaddingLengthGenerator)
}
switch request.Security {
case protocol.SecurityType_NONE:
if request.Option.Has(protocol.RequestOptionChunkStream) {
@ -215,7 +225,7 @@ func (c *ClientSession) DecodeResponseBody(request *protocol.RequestHeader, read
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationReader(auth, sizeParser, reader, protocol.TransferTypePacket)
return crypto.NewAuthenticationReader(auth, sizeParser, reader, protocol.TransferTypePacket, padding)
}
return buf.NewReader(reader)
@ -226,7 +236,7 @@ func (c *ClientSession) DecodeResponseBody(request *protocol.RequestHeader, read
NonceGenerator: crypto.GenerateEmptyBytes(),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationReader(auth, sizeParser, c.responseReader, request.Command.TransferType())
return crypto.NewAuthenticationReader(auth, sizeParser, c.responseReader, request.Command.TransferType(), padding)
}
return buf.NewReader(c.responseReader)
@ -239,7 +249,7 @@ func (c *ClientSession) DecodeResponseBody(request *protocol.RequestHeader, read
NonceGenerator: GenerateChunkNonce(c.responseBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType())
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)
case protocol.SecurityType_CHACHA20_POLY1305:
aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(c.responseBodyKey[:]))
@ -248,7 +258,7 @@ func (c *ClientSession) DecodeResponseBody(request *protocol.RequestHeader, read
NonceGenerator: GenerateChunkNonce(c.responseBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType())
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)
default:
panic("Unknown security type.")
}

View File

@ -238,6 +238,11 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade
if request.Option.Has(protocol.RequestOptionChunkMasking) {
sizeParser = NewShakeSizeParser(s.requestBodyIV[:])
}
var padding crypto.PaddingLengthGenerator = nil
if request.Option.Has(protocol.RequestOptionGlobalPadding) {
padding = sizeParser.(crypto.PaddingLengthGenerator)
}
switch request.Security {
case protocol.SecurityType_NONE:
if request.Option.Has(protocol.RequestOptionChunkStream) {
@ -250,7 +255,7 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade
NonceGenerator: crypto.GenerateEmptyBytes(),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationReader(auth, sizeParser, reader, protocol.TransferTypePacket)
return crypto.NewAuthenticationReader(auth, sizeParser, reader, protocol.TransferTypePacket, padding)
}
return buf.NewReader(reader)
@ -263,7 +268,7 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade
NonceGenerator: crypto.GenerateEmptyBytes(),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationReader(auth, sizeParser, cryptionReader, request.Command.TransferType())
return crypto.NewAuthenticationReader(auth, sizeParser, cryptionReader, request.Command.TransferType(), padding)
}
return buf.NewReader(cryptionReader)
@ -276,7 +281,7 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade
NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType())
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)
case protocol.SecurityType_CHACHA20_POLY1305:
aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(s.requestBodyKey[:]))
@ -285,7 +290,7 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade
NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType())
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)
default:
panic("Unknown security type.")
}
@ -313,6 +318,11 @@ func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writ
if request.Option.Has(protocol.RequestOptionChunkMasking) {
sizeParser = NewShakeSizeParser(s.responseBodyIV[:])
}
var padding crypto.PaddingLengthGenerator = nil
if request.Option.Has(protocol.RequestOptionGlobalPadding) {
padding = sizeParser.(crypto.PaddingLengthGenerator)
}
switch request.Security {
case protocol.SecurityType_NONE:
if request.Option.Has(protocol.RequestOptionChunkStream) {
@ -325,7 +335,7 @@ func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writ
NonceGenerator: crypto.GenerateEmptyBytes(),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, protocol.TransferTypePacket)
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, protocol.TransferTypePacket, padding)
}
return buf.NewWriter(writer)
@ -336,7 +346,7 @@ func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writ
NonceGenerator: crypto.GenerateEmptyBytes(),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationWriter(auth, sizeParser, s.responseWriter, request.Command.TransferType())
return crypto.NewAuthenticationWriter(auth, sizeParser, s.responseWriter, request.Command.TransferType(), padding)
}
return buf.NewWriter(s.responseWriter)
@ -349,7 +359,7 @@ func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writ
NonceGenerator: GenerateChunkNonce(s.responseBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType())
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)
case protocol.SecurityType_CHACHA20_POLY1305:
aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(s.responseBodyKey[:]))
@ -358,7 +368,7 @@ func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writ
NonceGenerator: GenerateChunkNonce(s.responseBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType())
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)
default:
panic("Unknown security type.")
}