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