github.com/xraypb/xray-core@v1.6.6/proxy/vmess/encoding/auth.go (about)

     1  package encoding
     2  
     3  import (
     4  	"crypto/md5"
     5  	"encoding/binary"
     6  	"hash/fnv"
     7  
     8  	"github.com/xraypb/xray-core/common"
     9  	"github.com/xraypb/xray-core/common/crypto"
    10  	"golang.org/x/crypto/sha3"
    11  )
    12  
    13  // Authenticate authenticates a byte array using Fnv hash.
    14  func Authenticate(b []byte) uint32 {
    15  	fnv1hash := fnv.New32a()
    16  	common.Must2(fnv1hash.Write(b))
    17  	return fnv1hash.Sum32()
    18  }
    19  
    20  type NoOpAuthenticator struct{}
    21  
    22  func (NoOpAuthenticator) NonceSize() int {
    23  	return 0
    24  }
    25  
    26  func (NoOpAuthenticator) Overhead() int {
    27  	return 0
    28  }
    29  
    30  // Seal implements AEAD.Seal().
    31  func (NoOpAuthenticator) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
    32  	return append(dst[:0], plaintext...)
    33  }
    34  
    35  // Open implements AEAD.Open().
    36  func (NoOpAuthenticator) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
    37  	return append(dst[:0], ciphertext...), nil
    38  }
    39  
    40  // FnvAuthenticator is an AEAD based on Fnv hash.
    41  type FnvAuthenticator struct{}
    42  
    43  // NonceSize implements AEAD.NonceSize().
    44  func (*FnvAuthenticator) NonceSize() int {
    45  	return 0
    46  }
    47  
    48  // Overhead impelements AEAD.Overhead().
    49  func (*FnvAuthenticator) Overhead() int {
    50  	return 4
    51  }
    52  
    53  // Seal implements AEAD.Seal().
    54  func (*FnvAuthenticator) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
    55  	dst = append(dst, 0, 0, 0, 0)
    56  	binary.BigEndian.PutUint32(dst, Authenticate(plaintext))
    57  	return append(dst, plaintext...)
    58  }
    59  
    60  // Open implements AEAD.Open().
    61  func (*FnvAuthenticator) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
    62  	if binary.BigEndian.Uint32(ciphertext[:4]) != Authenticate(ciphertext[4:]) {
    63  		return dst, newError("invalid authentication")
    64  	}
    65  	return append(dst, ciphertext[4:]...), nil
    66  }
    67  
    68  // GenerateChacha20Poly1305Key generates a 32-byte key from a given 16-byte array.
    69  func GenerateChacha20Poly1305Key(b []byte) []byte {
    70  	key := make([]byte, 32)
    71  	t := md5.Sum(b)
    72  	copy(key, t[:])
    73  	t = md5.Sum(key[:16])
    74  	copy(key[16:], t[:])
    75  	return key
    76  }
    77  
    78  type ShakeSizeParser struct {
    79  	shake  sha3.ShakeHash
    80  	buffer [2]byte
    81  }
    82  
    83  func NewShakeSizeParser(nonce []byte) *ShakeSizeParser {
    84  	shake := sha3.NewShake128()
    85  	common.Must2(shake.Write(nonce))
    86  	return &ShakeSizeParser{
    87  		shake: shake,
    88  	}
    89  }
    90  
    91  func (*ShakeSizeParser) SizeBytes() int32 {
    92  	return 2
    93  }
    94  
    95  func (s *ShakeSizeParser) next() uint16 {
    96  	common.Must2(s.shake.Read(s.buffer[:]))
    97  	return binary.BigEndian.Uint16(s.buffer[:])
    98  }
    99  
   100  func (s *ShakeSizeParser) Decode(b []byte) (uint16, error) {
   101  	mask := s.next()
   102  	size := binary.BigEndian.Uint16(b)
   103  	return mask ^ size, nil
   104  }
   105  
   106  func (s *ShakeSizeParser) Encode(size uint16, b []byte) []byte {
   107  	mask := s.next()
   108  	binary.BigEndian.PutUint16(b, mask^size)
   109  	return b[:2]
   110  }
   111  
   112  func (s *ShakeSizeParser) NextPaddingLen() uint16 {
   113  	return s.next() % 64
   114  }
   115  
   116  func (s *ShakeSizeParser) MaxPaddingLen() uint16 {
   117  	return 64
   118  }
   119  
   120  type AEADSizeParser struct {
   121  	crypto.AEADChunkSizeParser
   122  }
   123  
   124  func NewAEADSizeParser(auth *crypto.AEADAuthenticator) *AEADSizeParser {
   125  	return &AEADSizeParser{crypto.AEADChunkSizeParser{Auth: auth}}
   126  }