2017-04-23 07:30:08 -04:00
|
|
|
package crypto
|
|
|
|
|
|
|
|
import (
|
|
|
|
"io"
|
|
|
|
|
2017-11-07 08:40:51 -05:00
|
|
|
"v2ray.com/core/common"
|
2017-04-23 07:30:08 -04:00
|
|
|
"v2ray.com/core/common/buf"
|
|
|
|
"v2ray.com/core/common/serial"
|
|
|
|
)
|
|
|
|
|
2018-04-02 03:52:16 -04:00
|
|
|
// ChunkSizeDecoder is a utility class to decode size value from bytes.
|
2017-04-23 07:30:08 -04:00
|
|
|
type ChunkSizeDecoder interface {
|
2018-04-03 05:32:03 -04:00
|
|
|
SizeBytes() int32
|
2017-04-23 07:30:08 -04:00
|
|
|
Decode([]byte) (uint16, error)
|
|
|
|
}
|
|
|
|
|
2018-04-02 03:52:16 -04:00
|
|
|
// ChunkSizeEncoder is a utility class to encode size value into bytes.
|
2017-04-23 07:30:08 -04:00
|
|
|
type ChunkSizeEncoder interface {
|
2018-04-03 05:32:03 -04:00
|
|
|
SizeBytes() int32
|
2017-04-23 07:30:08 -04:00
|
|
|
Encode(uint16, []byte) []byte
|
|
|
|
}
|
|
|
|
|
|
|
|
type PlainChunkSizeParser struct{}
|
|
|
|
|
2018-04-03 05:32:03 -04:00
|
|
|
func (PlainChunkSizeParser) SizeBytes() int32 {
|
2017-04-23 07:30:08 -04:00
|
|
|
return 2
|
|
|
|
}
|
|
|
|
|
|
|
|
func (PlainChunkSizeParser) Encode(size uint16, b []byte) []byte {
|
|
|
|
return serial.Uint16ToBytes(size, b)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (PlainChunkSizeParser) Decode(b []byte) (uint16, error) {
|
|
|
|
return serial.BytesToUint16(b), nil
|
|
|
|
}
|
|
|
|
|
2017-11-25 18:51:54 -05:00
|
|
|
type AEADChunkSizeParser struct {
|
|
|
|
Auth *AEADAuthenticator
|
|
|
|
}
|
|
|
|
|
2018-04-03 05:32:03 -04:00
|
|
|
func (p *AEADChunkSizeParser) SizeBytes() int32 {
|
|
|
|
return 2 + int32(p.Auth.Overhead())
|
2017-11-25 18:51:54 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *AEADChunkSizeParser) Encode(size uint16, b []byte) []byte {
|
2017-11-26 10:55:46 -05:00
|
|
|
b = serial.Uint16ToBytes(size-uint16(p.Auth.Overhead()), b)
|
2017-11-25 18:51:54 -05:00
|
|
|
b, err := p.Auth.Seal(b[:0], b)
|
|
|
|
common.Must(err)
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *AEADChunkSizeParser) Decode(b []byte) (uint16, error) {
|
|
|
|
b, err := p.Auth.Open(b[:0], b)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
2017-11-26 10:55:46 -05:00
|
|
|
return serial.BytesToUint16(b) + uint16(p.Auth.Overhead()), nil
|
2017-11-25 18:51:54 -05:00
|
|
|
}
|
|
|
|
|
2017-04-23 07:30:08 -04:00
|
|
|
type ChunkStreamReader struct {
|
|
|
|
sizeDecoder ChunkSizeDecoder
|
2017-12-01 19:19:27 -05:00
|
|
|
reader *buf.BufferedReader
|
2017-04-23 07:30:08 -04:00
|
|
|
|
|
|
|
buffer []byte
|
2018-04-02 14:00:50 -04:00
|
|
|
leftOverSize int32
|
2017-04-23 07:30:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewChunkStreamReader(sizeDecoder ChunkSizeDecoder, reader io.Reader) *ChunkStreamReader {
|
|
|
|
return &ChunkStreamReader{
|
|
|
|
sizeDecoder: sizeDecoder,
|
2017-12-01 19:19:27 -05:00
|
|
|
reader: buf.NewBufferedReader(buf.NewReader(reader)),
|
2017-04-23 07:30:08 -04:00
|
|
|
buffer: make([]byte, sizeDecoder.SizeBytes()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *ChunkStreamReader) readSize() (uint16, error) {
|
2017-12-01 19:19:27 -05:00
|
|
|
if _, err := io.ReadFull(r.reader, r.buffer); err != nil {
|
|
|
|
return 0, err
|
2017-04-23 07:30:08 -04:00
|
|
|
}
|
|
|
|
return r.sizeDecoder.Decode(r.buffer)
|
|
|
|
}
|
|
|
|
|
2017-11-09 16:33:15 -05:00
|
|
|
func (r *ChunkStreamReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
2017-05-02 16:50:27 -04:00
|
|
|
size := r.leftOverSize
|
2017-04-23 07:30:08 -04:00
|
|
|
if size == 0 {
|
|
|
|
nextSize, err := r.readSize()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if nextSize == 0 {
|
|
|
|
return nil, io.EOF
|
|
|
|
}
|
2018-04-02 14:00:50 -04:00
|
|
|
size = int32(nextSize)
|
2017-04-23 07:30:08 -04:00
|
|
|
}
|
2017-12-01 19:19:27 -05:00
|
|
|
r.leftOverSize = size
|
2017-04-23 07:30:08 -04:00
|
|
|
|
2017-12-01 19:19:27 -05:00
|
|
|
mb, err := r.reader.ReadAtMost(size)
|
|
|
|
if !mb.IsEmpty() {
|
|
|
|
r.leftOverSize -= mb.Len()
|
2017-04-28 14:11:44 -04:00
|
|
|
return mb, nil
|
2017-04-23 07:30:08 -04:00
|
|
|
}
|
2017-12-01 19:19:27 -05:00
|
|
|
return nil, err
|
2017-04-23 07:30:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
type ChunkStreamWriter struct {
|
|
|
|
sizeEncoder ChunkSizeEncoder
|
|
|
|
writer buf.Writer
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewChunkStreamWriter(sizeEncoder ChunkSizeEncoder, writer io.Writer) *ChunkStreamWriter {
|
|
|
|
return &ChunkStreamWriter{
|
|
|
|
sizeEncoder: sizeEncoder,
|
|
|
|
writer: buf.NewWriter(writer),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-09 16:33:15 -05:00
|
|
|
func (w *ChunkStreamWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
2017-04-23 07:30:08 -04:00
|
|
|
const sliceSize = 8192
|
2017-11-08 18:55:28 -05:00
|
|
|
mbLen := mb.Len()
|
2017-11-09 16:33:15 -05:00
|
|
|
mb2Write := buf.NewMultiBufferCap(mbLen/buf.Size + mbLen/sliceSize + 2)
|
2017-04-23 07:30:08 -04:00
|
|
|
|
|
|
|
for {
|
|
|
|
slice := mb.SliceBySize(sliceSize)
|
|
|
|
|
|
|
|
b := buf.New()
|
2017-11-08 05:11:13 -05:00
|
|
|
common.Must(b.Reset(func(buffer []byte) (int, error) {
|
2017-04-23 07:30:08 -04:00
|
|
|
w.sizeEncoder.Encode(uint16(slice.Len()), buffer[:0])
|
2018-04-03 05:32:03 -04:00
|
|
|
return int(w.sizeEncoder.SizeBytes()), nil
|
2017-11-07 08:40:51 -05:00
|
|
|
}))
|
2017-04-23 07:30:08 -04:00
|
|
|
mb2Write.Append(b)
|
|
|
|
mb2Write.AppendMulti(slice)
|
|
|
|
|
|
|
|
if mb.IsEmpty() {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-09 16:33:15 -05:00
|
|
|
return w.writer.WriteMultiBuffer(mb2Write)
|
2017-04-23 07:30:08 -04:00
|
|
|
}
|