github.com/v2fly/v2ray-core/v4@v4.45.2/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/v2fly/v2ray-core/v4/common" 11 "github.com/v2fly/v2ray-core/v4/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 }