github.com/eagleql/xray-core@v1.4.4/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/eagleql/xray-core/common"
     9  
    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  
    44  // NonceSize implements AEAD.NonceSize().
    45  func (*FnvAuthenticator) NonceSize() int {
    46  	return 0
    47  }
    48  
    49  // Overhead impelements AEAD.Overhead().
    50  func (*FnvAuthenticator) Overhead() int {
    51  	return 4
    52  }
    53  
    54  // Seal implements AEAD.Seal().
    55  func (*FnvAuthenticator) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
    56  	dst = append(dst, 0, 0, 0, 0)
    57  	binary.BigEndian.PutUint32(dst, Authenticate(plaintext))
    58  	return append(dst, plaintext...)
    59  }
    60  
    61  // Open implements AEAD.Open().
    62  func (*FnvAuthenticator) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
    63  	if binary.BigEndian.Uint32(ciphertext[:4]) != Authenticate(ciphertext[4:]) {
    64  		return dst, newError("invalid authentication")
    65  	}
    66  	return append(dst, ciphertext[4:]...), nil
    67  }
    68  
    69  // GenerateChacha20Poly1305Key generates a 32-byte key from a given 16-byte array.
    70  func GenerateChacha20Poly1305Key(b []byte) []byte {
    71  	key := make([]byte, 32)
    72  	t := md5.Sum(b)
    73  	copy(key, t[:])
    74  	t = md5.Sum(key[:16])
    75  	copy(key[16:], t[:])
    76  	return key
    77  }
    78  
    79  type ShakeSizeParser struct {
    80  	shake  sha3.ShakeHash
    81  	buffer [2]byte
    82  }
    83  
    84  func NewShakeSizeParser(nonce []byte) *ShakeSizeParser {
    85  	shake := sha3.NewShake128()
    86  	common.Must2(shake.Write(nonce))
    87  	return &ShakeSizeParser{
    88  		shake: shake,
    89  	}
    90  }
    91  
    92  func (*ShakeSizeParser) SizeBytes() int32 {
    93  	return 2
    94  }
    95  
    96  func (s *ShakeSizeParser) next() uint16 {
    97  	common.Must2(s.shake.Read(s.buffer[:]))
    98  	return binary.BigEndian.Uint16(s.buffer[:])
    99  }
   100  
   101  func (s *ShakeSizeParser) Decode(b []byte) (uint16, error) {
   102  	mask := s.next()
   103  	size := binary.BigEndian.Uint16(b)
   104  	return mask ^ size, nil
   105  }
   106  
   107  func (s *ShakeSizeParser) Encode(size uint16, b []byte) []byte {
   108  	mask := s.next()
   109  	binary.BigEndian.PutUint16(b, mask^size)
   110  	return b[:2]
   111  }
   112  
   113  func (s *ShakeSizeParser) NextPaddingLen() uint16 {
   114  	return s.next() % 64
   115  }
   116  
   117  func (s *ShakeSizeParser) MaxPaddingLen() uint16 {
   118  	return 64
   119  }