github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/common/crypto/auth.go (about)

     1  package crypto
     2  
     3  import (
     4  	"crypto/cipher"
     5  	"crypto/rand"
     6  	"io"
     7  
     8  	"github.com/v2fly/v2ray-core/v5/common"
     9  	"github.com/v2fly/v2ray-core/v5/common/buf"
    10  	"github.com/v2fly/v2ray-core/v5/common/bytespool"
    11  	"github.com/v2fly/v2ray-core/v5/common/errors"
    12  	"github.com/v2fly/v2ray-core/v5/common/protocol"
    13  )
    14  
    15  type BytesGenerator func() []byte
    16  
    17  func GenerateEmptyBytes() BytesGenerator {
    18  	var b [1]byte
    19  	return func() []byte {
    20  		return b[:0]
    21  	}
    22  }
    23  
    24  func GenerateStaticBytes(content []byte) BytesGenerator {
    25  	return func() []byte {
    26  		return content
    27  	}
    28  }
    29  
    30  func GenerateIncreasingNonce(nonce []byte) BytesGenerator {
    31  	c := append([]byte(nil), nonce...)
    32  	return func() []byte {
    33  		for i := range c {
    34  			c[i]++
    35  			if c[i] != 0 {
    36  				break
    37  			}
    38  		}
    39  		return c
    40  	}
    41  }
    42  
    43  func GenerateInitialAEADNonce() BytesGenerator {
    44  	return GenerateIncreasingNonce([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF})
    45  }
    46  
    47  type Authenticator interface {
    48  	NonceSize() int
    49  	Overhead() int
    50  	Open(dst, cipherText []byte) ([]byte, error)
    51  	Seal(dst, plainText []byte) ([]byte, error)
    52  }
    53  
    54  type AEADAuthenticator struct {
    55  	cipher.AEAD
    56  	NonceGenerator          BytesGenerator
    57  	AdditionalDataGenerator BytesGenerator
    58  }
    59  
    60  func (v *AEADAuthenticator) Open(dst, cipherText []byte) ([]byte, error) {
    61  	iv := v.NonceGenerator()
    62  	if len(iv) != v.AEAD.NonceSize() {
    63  		return nil, newError("invalid AEAD nonce size: ", len(iv))
    64  	}
    65  
    66  	var additionalData []byte
    67  	if v.AdditionalDataGenerator != nil {
    68  		additionalData = v.AdditionalDataGenerator()
    69  	}
    70  	return v.AEAD.Open(dst, iv, cipherText, additionalData)
    71  }
    72  
    73  func (v *AEADAuthenticator) Seal(dst, plainText []byte) ([]byte, error) {
    74  	iv := v.NonceGenerator()
    75  	if len(iv) != v.AEAD.NonceSize() {
    76  		return nil, newError("invalid AEAD nonce size: ", len(iv))
    77  	}
    78  
    79  	var additionalData []byte
    80  	if v.AdditionalDataGenerator != nil {
    81  		additionalData = v.AdditionalDataGenerator()
    82  	}
    83  	return v.AEAD.Seal(dst, iv, plainText, additionalData), nil
    84  }
    85  
    86  type AuthenticationReader struct {
    87  	auth         Authenticator
    88  	reader       *buf.BufferedReader
    89  	sizeParser   ChunkSizeDecoder
    90  	sizeBytes    []byte
    91  	transferType protocol.TransferType
    92  	padding      PaddingLengthGenerator
    93  	size         uint16
    94  	sizeOffset   uint16
    95  	paddingLen   uint16
    96  	hasSize      bool
    97  	done         bool
    98  }
    99  
   100  func NewAuthenticationReader(auth Authenticator, sizeParser ChunkSizeDecoder, reader io.Reader, transferType protocol.TransferType, paddingLen PaddingLengthGenerator) *AuthenticationReader {
   101  	r := &AuthenticationReader{
   102  		auth:         auth,
   103  		sizeParser:   sizeParser,
   104  		transferType: transferType,
   105  		padding:      paddingLen,
   106  		sizeBytes:    make([]byte, sizeParser.SizeBytes()),
   107  	}
   108  	if chunkSizeDecoderWithOffset, ok := sizeParser.(ChunkSizeDecoderWithOffset); ok {
   109  		r.sizeOffset = chunkSizeDecoderWithOffset.HasConstantOffset()
   110  	}
   111  	if breader, ok := reader.(*buf.BufferedReader); ok {
   112  		r.reader = breader
   113  	} else {
   114  		r.reader = &buf.BufferedReader{Reader: buf.NewReader(reader)}
   115  	}
   116  	return r
   117  }
   118  
   119  func (r *AuthenticationReader) readSize() (uint16, uint16, error) {
   120  	if r.hasSize {
   121  		r.hasSize = false
   122  		return r.size, r.paddingLen, nil
   123  	}
   124  	if _, err := io.ReadFull(r.reader, r.sizeBytes); err != nil {
   125  		return 0, 0, err
   126  	}
   127  	var padding uint16
   128  	if r.padding != nil {
   129  		padding = r.padding.NextPaddingLen()
   130  	}
   131  	size, err := r.sizeParser.Decode(r.sizeBytes)
   132  	return size, padding, err
   133  }
   134  
   135  var errSoft = newError("waiting for more data")
   136  
   137  func (r *AuthenticationReader) readBuffer(size int32, padding int32) (*buf.Buffer, error) {
   138  	b := buf.New()
   139  	if _, err := b.ReadFullFrom(r.reader, size); err != nil {
   140  		b.Release()
   141  		return nil, err
   142  	}
   143  	size -= padding
   144  	rb, err := r.auth.Open(b.BytesTo(0), b.BytesTo(size))
   145  	if err != nil {
   146  		b.Release()
   147  		return nil, err
   148  	}
   149  	b.Resize(0, int32(len(rb)))
   150  	return b, nil
   151  }
   152  
   153  func (r *AuthenticationReader) readInternal(soft bool, mb *buf.MultiBuffer) error {
   154  	if soft && r.reader.BufferedBytes() < r.sizeParser.SizeBytes() {
   155  		return errSoft
   156  	}
   157  
   158  	if r.done {
   159  		return io.EOF
   160  	}
   161  
   162  	size, padding, err := r.readSize()
   163  	if err != nil {
   164  		return err
   165  	}
   166  
   167  	if size+r.sizeOffset == uint16(r.auth.Overhead())+padding {
   168  		r.done = true
   169  		return io.EOF
   170  	}
   171  
   172  	effectiveSize := int32(size) + int32(r.sizeOffset)
   173  
   174  	if soft && effectiveSize > r.reader.BufferedBytes() {
   175  		r.size = size
   176  		r.paddingLen = padding
   177  		r.hasSize = true
   178  		return errSoft
   179  	}
   180  
   181  	if effectiveSize <= buf.Size {
   182  		b, err := r.readBuffer(effectiveSize, int32(padding))
   183  		if err != nil {
   184  			return err
   185  		}
   186  		*mb = append(*mb, b)
   187  		return nil
   188  	}
   189  
   190  	payload := bytespool.Alloc(effectiveSize)
   191  	defer bytespool.Free(payload)
   192  
   193  	if _, err := io.ReadFull(r.reader, payload[:effectiveSize]); err != nil {
   194  		return err
   195  	}
   196  
   197  	effectiveSize -= int32(padding)
   198  
   199  	rb, err := r.auth.Open(payload[:0], payload[:effectiveSize])
   200  	if err != nil {
   201  		return err
   202  	}
   203  
   204  	*mb = buf.MergeBytes(*mb, rb)
   205  	return nil
   206  }
   207  
   208  func (r *AuthenticationReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
   209  	const readSize = 16
   210  	mb := make(buf.MultiBuffer, 0, readSize)
   211  	if err := r.readInternal(false, &mb); err != nil {
   212  		buf.ReleaseMulti(mb)
   213  		return nil, err
   214  	}
   215  
   216  	for i := 1; i < readSize; i++ {
   217  		err := r.readInternal(true, &mb)
   218  		if err == errSoft || err == io.EOF {
   219  			break
   220  		}
   221  		if err != nil {
   222  			buf.ReleaseMulti(mb)
   223  			return nil, err
   224  		}
   225  	}
   226  
   227  	return mb, nil
   228  }
   229  
   230  type AuthenticationWriter struct {
   231  	auth         Authenticator
   232  	writer       buf.Writer
   233  	sizeParser   ChunkSizeEncoder
   234  	transferType protocol.TransferType
   235  	padding      PaddingLengthGenerator
   236  }
   237  
   238  func NewAuthenticationWriter(auth Authenticator, sizeParser ChunkSizeEncoder, writer io.Writer, transferType protocol.TransferType, padding PaddingLengthGenerator) *AuthenticationWriter {
   239  	w := &AuthenticationWriter{
   240  		auth:         auth,
   241  		writer:       buf.NewWriter(writer),
   242  		sizeParser:   sizeParser,
   243  		transferType: transferType,
   244  	}
   245  	if padding != nil {
   246  		w.padding = padding
   247  	}
   248  	return w
   249  }
   250  
   251  func (w *AuthenticationWriter) seal(b []byte) (*buf.Buffer, error) {
   252  	encryptedSize := int32(len(b) + w.auth.Overhead())
   253  	var paddingSize int32
   254  	if w.padding != nil {
   255  		paddingSize = int32(w.padding.NextPaddingLen())
   256  	}
   257  
   258  	sizeBytes := w.sizeParser.SizeBytes()
   259  	totalSize := sizeBytes + encryptedSize + paddingSize
   260  	if totalSize > buf.Size {
   261  		return nil, newError("size too large: ", totalSize)
   262  	}
   263  
   264  	eb := buf.New()
   265  	w.sizeParser.Encode(uint16(encryptedSize+paddingSize), eb.Extend(sizeBytes))
   266  	if _, err := w.auth.Seal(eb.Extend(encryptedSize)[:0], b); err != nil {
   267  		eb.Release()
   268  		return nil, err
   269  	}
   270  	if paddingSize > 0 {
   271  		// These paddings will send in clear text.
   272  		// To avoid leakage of PRNG internal state, a cryptographically secure PRNG should be used.
   273  		paddingBytes := eb.Extend(paddingSize)
   274  		common.Must2(rand.Read(paddingBytes))
   275  	}
   276  
   277  	return eb, nil
   278  }
   279  
   280  func (w *AuthenticationWriter) writeStream(mb buf.MultiBuffer) error {
   281  	defer buf.ReleaseMulti(mb)
   282  
   283  	var maxPadding int32
   284  	if w.padding != nil {
   285  		maxPadding = int32(w.padding.MaxPaddingLen())
   286  	}
   287  
   288  	payloadSize := buf.Size - int32(w.auth.Overhead()) - w.sizeParser.SizeBytes() - maxPadding
   289  	if len(mb)+10 > 64*1024*1024 {
   290  		return errors.New("value too large")
   291  	}
   292  	sliceSize := len(mb) + 10
   293  	mb2Write := make(buf.MultiBuffer, 0, sliceSize)
   294  
   295  	temp := buf.New()
   296  	defer temp.Release()
   297  
   298  	rawBytes := temp.Extend(payloadSize)
   299  
   300  	for {
   301  		nb, nBytes := buf.SplitBytes(mb, rawBytes)
   302  		mb = nb
   303  
   304  		eb, err := w.seal(rawBytes[:nBytes])
   305  		if err != nil {
   306  			buf.ReleaseMulti(mb2Write)
   307  			return err
   308  		}
   309  		mb2Write = append(mb2Write, eb)
   310  		if mb.IsEmpty() {
   311  			break
   312  		}
   313  	}
   314  
   315  	return w.writer.WriteMultiBuffer(mb2Write)
   316  }
   317  
   318  func (w *AuthenticationWriter) writePacket(mb buf.MultiBuffer) error {
   319  	defer buf.ReleaseMulti(mb)
   320  
   321  	if len(mb)+1 > 64*1024*1024 {
   322  		return errors.New("value too large")
   323  	}
   324  	sliceSize := len(mb) + 1
   325  	mb2Write := make(buf.MultiBuffer, 0, sliceSize)
   326  
   327  	for _, b := range mb {
   328  		if b.IsEmpty() {
   329  			continue
   330  		}
   331  
   332  		eb, err := w.seal(b.Bytes())
   333  		if err != nil {
   334  			continue
   335  		}
   336  
   337  		mb2Write = append(mb2Write, eb)
   338  	}
   339  
   340  	if mb2Write.IsEmpty() {
   341  		return nil
   342  	}
   343  
   344  	return w.writer.WriteMultiBuffer(mb2Write)
   345  }
   346  
   347  // WriteMultiBuffer implements buf.Writer.
   348  func (w *AuthenticationWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
   349  	if mb.IsEmpty() {
   350  		eb, err := w.seal([]byte{})
   351  		common.Must(err)
   352  		return w.writer.WriteMultiBuffer(buf.MultiBuffer{eb})
   353  	}
   354  
   355  	if w.transferType == protocol.TransferTypeStream {
   356  		return w.writeStream(mb)
   357  	}
   358  
   359  	return w.writePacket(mb)
   360  }