func decryptBufferV20(dst, src []byte, config *Config) ([]byte, error) {
	ad, err := newAuthDecV20(config)
	if err != nil {
		return nil, err
	}
	for len(src) > 0 {
		buffer := packageV20(src)
		if len(buffer) > maxPackageSize {
			buffer = buffer[:maxPackageSize]
		}
		payloadLen := buffer.Header().Length()
		if cap(dst) >= len(dst)+payloadLen {
			dst = dst[:len(dst)+payloadLen]
		} else {
			dst = append(dst, make([]byte, payloadLen)...)
		}
		if err = ad.Open(dst[len(dst)-payloadLen:], buffer); err != nil {
			return nil, err  
		}
		src = src[buffer.Length():]
	}
	if !ad.finalized {
		return nil, errUnexpectedEOF
	}
	return dst, nil
}
decryptBufferV20 will append plaintext to dst and return the result.
package sio
import (
	"errors"
	"io"
	"io/ioutil"
	"sync"
)
type encReaderV20 struct {
	authEncV20
	src io.Reader
	buffer   packageV20
	offset   int
	lastByte byte
	stateErr error
	firstRead bool
}
var packageBufferPool = sync.Pool{New: func() interface{} { return make([]byte, maxPackageSize) }}
func recyclePackageBufferPool(b []byte) {
	if cap(b) < maxPackageSize {
		return
	}
	for i := range b {
		b[i] = 0
	}
	packageBufferPool.Put(b)
}
func encryptReaderV20(src io.Reader, config *Config) (*encReaderV20, error) {
	ae, err := newAuthEncV20(config)
	if err != nil {
		return nil, err
	}
	return &encReaderV20{
		authEncV20: ae,
		src:        src,
		buffer:     packageBufferPool.Get().([]byte)[:maxPackageSize],
		firstRead:  true,
	}, nil
}
func (r *encReaderV20) recycle() {
	recyclePackageBufferPool(r.buffer)
	r.buffer = nil
}
func (r *encReaderV20) Read(p []byte) (n int, err error) {
	if r.stateErr != nil {
		return 0, r.stateErr
	}
	if r.firstRead {
		r.firstRead = false
		_, err = io.ReadFull(r.src, r.buffer[headerSize:headerSize+1])
		if err != nil && err != io.EOF {  
			return 0, err
		}
		if err == io.EOF {
			r.finalized = true
			r.stateErr = io.EOF
			r.recycle()
			return 0, io.EOF
		}
		r.lastByte = r.buffer[headerSize]
	}
	if r.offset > 0 {  
		remaining := r.buffer.Length() - r.offset
		if len(p) < remaining {
			r.offset += copy(p, r.buffer[r.offset:r.offset+len(p)])
			return len(p), nil
		}
		n = copy(p, r.buffer[r.offset:r.offset+remaining])
		p = p[remaining:]
		r.offset = 0
	}
	if r.finalized {
		r.stateErr = io.EOF
		r.recycle()
		return n, io.EOF
	}
	for len(p) >= maxPackageSize {
		r.buffer[headerSize] = r.lastByte
		nn, err := io.ReadFull(r.src, r.buffer[headerSize+1:headerSize+1+maxPayloadSize])  
		if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
			return n, err  
		}
		if err == io.EOF || err == io.ErrUnexpectedEOF {  
			r.SealFinal(p, r.buffer[headerSize:headerSize+1+nn])
			return n + headerSize + tagSize + 1 + nn, io.EOF
		}
		r.lastByte = r.buffer[headerSize+maxPayloadSize]  
		r.Seal(p, r.buffer[headerSize:headerSize+maxPayloadSize])
		p = p[maxPackageSize:]
		n += maxPackageSize
	}
	if len(p) > 0 {
		r.buffer[headerSize] = r.lastByte
		nn, err := io.ReadFull(r.src, r.buffer[headerSize+1:headerSize+1+maxPayloadSize])  
		if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
			r.stateErr = err
			r.recycle()
			return n, err  
		}
		if err == io.EOF || err == io.ErrUnexpectedEOF {  
			r.SealFinal(r.buffer, r.buffer[headerSize:headerSize+1+nn])
			if len(p) > r.buffer.Length() {
				n += copy(p, r.buffer[:r.buffer.Length()])
				r.stateErr = io.EOF
				r.recycle()
				return n, io.EOF
			}
		} else {
			r.lastByte = r.buffer[headerSize+maxPayloadSize]  
			r.Seal(r.buffer, r.buffer[headerSize:headerSize+maxPayloadSize])
		}
		r.offset = copy(p, r.buffer[:len(p)])  
		n += r.offset
	}
	return n, nil
}
type decReaderV20 struct {
	authDecV20
	src io.Reader
	stateErr error
	buffer   packageV20
	offset   int
}
func decryptReaderV20(src io.Reader, config *Config) (*decReaderV20, error) {
	ad, err := newAuthDecV20(config)
	if err != nil {
		return nil, err
	}
	return &decReaderV20{
		authDecV20: ad,
		src:        src,
		buffer:     packageBufferPool.Get().([]byte)[:maxPackageSize],
	}, nil
}
func (r *decReaderV20) recycle() {
	recyclePackageBufferPool(r.buffer)
	r.buffer = nil
}
func (r *decReaderV20) Read(p []byte) (n int, err error) {
	if r.stateErr != nil {
		return 0, r.stateErr
	}
	if r.offset > 0 {  
		remaining := len(r.buffer.Payload()) - r.offset
		if len(p) < remaining {
			n = copy(p, r.buffer.Payload()[r.offset:r.offset+len(p)])
			r.offset += n
			return n, nil
		}
		n = copy(p, r.buffer.Payload()[r.offset:])
		p = p[remaining:]
		r.offset = 0
	}
	for len(p) >= maxPayloadSize {
		nn, err := io.ReadFull(r.src, r.buffer)
		if err == io.EOF && !r.finalized {
			return n, errUnexpectedEOF  
		}
		if err != nil && err != io.ErrUnexpectedEOF {
			r.recycle()
			r.stateErr = err
			return n, err  
		}
		if err = r.Open(p, r.buffer[:nn]); err != nil {
			r.recycle()
			r.stateErr = err
			return n, err  
		}
		p = p[len(r.buffer.Payload()):]
		n += len(r.buffer.Payload())
	}
	if len(p) > 0 {
		nn, err := io.ReadFull(r.src, r.buffer)
		if err == io.EOF && !r.finalized {
			r.recycle()
			r.stateErr = errUnexpectedEOF
			return n, errUnexpectedEOF  
		}
		if err != nil && err != io.ErrUnexpectedEOF {
			r.recycle()
			r.stateErr = err
			return n, err  
		}
		if err = r.Open(r.buffer[headerSize:], r.buffer[:nn]); err != nil {
			return n, err  
		}
		if payload := r.buffer.Payload(); len(p) < len(payload) {
			r.offset = copy(p, payload[:len(p)])
			n += r.offset
		} else {
			n += copy(p, payload)
		}
	}
	return n, nil
}