1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-06-29 10:45:22 +00:00
v2fly/common/crypto/chunk.go

161 lines
3.6 KiB
Go
Raw Normal View History

2017-04-23 11:30:08 +00:00
package crypto
import (
2018-11-02 14:47:58 +00:00
"encoding/binary"
2017-04-23 11:30:08 +00:00
"io"
2017-11-07 13:40:51 +00:00
"v2ray.com/core/common"
2017-04-23 11:30:08 +00:00
"v2ray.com/core/common/buf"
)
2018-04-02 07:52:16 +00:00
// ChunkSizeDecoder is a utility class to decode size value from bytes.
2017-04-23 11:30:08 +00:00
type ChunkSizeDecoder interface {
2018-04-03 09:32:03 +00:00
SizeBytes() int32
2017-04-23 11:30:08 +00:00
Decode([]byte) (uint16, error)
}
2018-04-02 07:52:16 +00:00
// ChunkSizeEncoder is a utility class to encode size value into bytes.
2017-04-23 11:30:08 +00:00
type ChunkSizeEncoder interface {
2018-04-03 09:32:03 +00:00
SizeBytes() int32
2017-04-23 11:30:08 +00:00
Encode(uint16, []byte) []byte
}
2018-07-07 13:42:24 +00:00
type PaddingLengthGenerator interface {
2018-07-08 19:46:13 +00:00
MaxPaddingLen() uint16
2018-07-07 13:42:24 +00:00
NextPaddingLen() uint16
}
2017-04-23 11:30:08 +00:00
type PlainChunkSizeParser struct{}
2018-04-03 09:32:03 +00:00
func (PlainChunkSizeParser) SizeBytes() int32 {
2017-04-23 11:30:08 +00:00
return 2
}
func (PlainChunkSizeParser) Encode(size uint16, b []byte) []byte {
2018-11-02 17:20:02 +00:00
binary.BigEndian.PutUint16(b, size)
return b[:2]
2017-04-23 11:30:08 +00:00
}
func (PlainChunkSizeParser) Decode(b []byte) (uint16, error) {
2018-11-02 14:47:58 +00:00
return binary.BigEndian.Uint16(b), nil
2017-04-23 11:30:08 +00:00
}
2017-11-25 23:51:54 +00:00
type AEADChunkSizeParser struct {
Auth *AEADAuthenticator
}
2018-04-03 09:32:03 +00:00
func (p *AEADChunkSizeParser) SizeBytes() int32 {
return 2 + int32(p.Auth.Overhead())
2017-11-25 23:51:54 +00:00
}
func (p *AEADChunkSizeParser) Encode(size uint16, b []byte) []byte {
2018-11-02 17:20:02 +00:00
binary.BigEndian.PutUint16(b, size-uint16(p.Auth.Overhead()))
b, err := p.Auth.Seal(b[:0], b[:2])
2017-11-25 23:51:54 +00:00
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
}
2018-11-02 14:47:58 +00:00
return binary.BigEndian.Uint16(b) + uint16(p.Auth.Overhead()), nil
2017-11-25 23:51:54 +00:00
}
2017-04-23 11:30:08 +00:00
type ChunkStreamReader struct {
sizeDecoder ChunkSizeDecoder
2017-12-02 00:19:27 +00:00
reader *buf.BufferedReader
2017-04-23 11:30:08 +00:00
buffer []byte
2018-04-02 18:00:50 +00:00
leftOverSize int32
2018-08-23 08:39:53 +00:00
maxNumChunk uint32
numChunk uint32
2017-04-23 11:30:08 +00:00
}
func NewChunkStreamReader(sizeDecoder ChunkSizeDecoder, reader io.Reader) *ChunkStreamReader {
2018-08-23 08:39:53 +00:00
return NewChunkStreamReaderWithChunkCount(sizeDecoder, reader, 0)
}
func NewChunkStreamReaderWithChunkCount(sizeDecoder ChunkSizeDecoder, reader io.Reader, maxNumChunk uint32) *ChunkStreamReader {
r := &ChunkStreamReader{
2017-04-23 11:30:08 +00:00
sizeDecoder: sizeDecoder,
buffer: make([]byte, sizeDecoder.SizeBytes()),
2018-08-23 08:39:53 +00:00
maxNumChunk: maxNumChunk,
2017-04-23 11:30:08 +00:00
}
if breader, ok := reader.(*buf.BufferedReader); ok {
r.reader = breader
} else {
r.reader = &buf.BufferedReader{Reader: buf.NewReader(reader)}
}
return r
2017-04-23 11:30:08 +00:00
}
func (r *ChunkStreamReader) readSize() (uint16, error) {
2017-12-02 00:19:27 +00:00
if _, err := io.ReadFull(r.reader, r.buffer); err != nil {
return 0, err
2017-04-23 11:30:08 +00:00
}
return r.sizeDecoder.Decode(r.buffer)
}
2017-11-09 21:33:15 +00:00
func (r *ChunkStreamReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
2017-05-02 20:50:27 +00:00
size := r.leftOverSize
2017-04-23 11:30:08 +00:00
if size == 0 {
2018-08-23 08:39:53 +00:00
r.numChunk++
if r.maxNumChunk > 0 && r.numChunk > r.maxNumChunk {
return nil, io.EOF
}
2017-04-23 11:30:08 +00:00
nextSize, err := r.readSize()
if err != nil {
return nil, err
}
if nextSize == 0 {
return nil, io.EOF
}
2018-04-02 18:00:50 +00:00
size = int32(nextSize)
2017-04-23 11:30:08 +00:00
}
2017-12-02 00:19:27 +00:00
r.leftOverSize = size
2017-04-23 11:30:08 +00:00
2017-12-02 00:19:27 +00:00
mb, err := r.reader.ReadAtMost(size)
if !mb.IsEmpty() {
r.leftOverSize -= mb.Len()
2017-04-28 18:11:44 +00:00
return mb, nil
2017-04-23 11:30:08 +00:00
}
2017-12-02 00:19:27 +00:00
return nil, err
2017-04-23 11:30:08 +00: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 21:33:15 +00:00
func (w *ChunkStreamWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
2017-04-23 11:30:08 +00:00
const sliceSize = 8192
2017-11-08 23:55:28 +00:00
mbLen := mb.Len()
2018-11-16 10:29:16 +00:00
mb2Write := make(buf.MultiBuffer, 0, mbLen/buf.Size+mbLen/sliceSize+2)
2017-04-23 11:30:08 +00:00
for {
2018-11-18 19:16:14 +00:00
mb2, slice := buf.SplitSize(mb, sliceSize)
mb = mb2
2017-04-23 11:30:08 +00:00
b := buf.New()
2018-11-02 20:34:04 +00:00
w.sizeEncoder.Encode(uint16(slice.Len()), b.Extend(w.sizeEncoder.SizeBytes()))
2018-11-17 08:12:20 +00:00
mb2Write = append(mb2Write, b)
mb2Write = append(mb2Write, slice...)
2017-04-23 11:30:08 +00:00
if mb.IsEmpty() {
break
}
}
2017-11-09 21:33:15 +00:00
return w.writer.WriteMultiBuffer(mb2Write)
2017-04-23 11:30:08 +00:00
}