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 }