github.com/imannamdari/v2ray-core/v5@v5.0.5/proxy/vmess/encoding/auth.go (about)

     1  package encoding
     2  
     3  import (
     4  	"crypto/md5"
     5  	"encoding/binary"
     6  	"hash/fnv"
     7  
     8  	"golang.org/x/crypto/sha3"
     9  
    10  	"github.com/imannamdari/v2ray-core/v5/common"
    11  	"github.com/imannamdari/v2ray-core/v5/common/crypto"
    12  )
    13  
    14  // Authenticate authenticates a byte array using Fnv hash.
    15  func Authenticate(b []byte) uint32 {
    16  	fnv1hash := fnv.New32a()
    17  	common.Must2(fnv1hash.Write(b))
    18  	return fnv1hash.Sum32()
    19  }
    20  
    21  type NoOpAuthenticator struct{}
    22  
    23  func (NoOpAuthenticator) NonceSize() int {
    24  	return 0
    25  }
    26  
    27  func (NoOpAuthenticator) Overhead() int {
    28  	return 0
    29  }
    30  
    31  // Seal implements AEAD.Seal().
    32  func (NoOpAuthenticator) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
    33  	return append(dst[:0], plaintext...)
    34  }
    35  
    36  // Open implements AEAD.Open().
    37  func (NoOpAuthenticator) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
    38  	return append(dst[:0], ciphertext...), nil
    39  }
    40  
    41  // FnvAuthenticator is an AEAD based on Fnv hash.
    42  type FnvAuthenticator struct{}
    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  }
   120  
   121  type AEADSizeParser struct {
   122  	crypto.AEADChunkSizeParser
   123  }
   124  
   125  func NewAEADSizeParser(auth *crypto.AEADAuthenticator) *AEADSizeParser {
   126  	return &AEADSizeParser{crypto.AEADChunkSizeParser{Auth: auth}}
   127  }