github.com/yaling888/clash@v1.53.0/transport/crypto/aead.go (about) 1 package crypto 2 3 import ( 4 "crypto/aes" 5 "crypto/cipher" 6 "crypto/rand" 7 "crypto/sha256" 8 "errors" 9 "fmt" 10 "strings" 11 12 "golang.org/x/crypto/chacha20poly1305" 13 14 "github.com/yaling888/clash/common/pool" 15 ) 16 17 var ErrInvalidCiphertext = errors.New("invalid ciphertext") 18 19 type AEAD struct { 20 cipher.AEAD 21 } 22 23 func (a *AEAD) Encrypt(dst *pool.BufferWriter, plaintext []byte) ([]byte, error) { 24 offset := dst.Len() 25 26 dst.Grow(a.NonceSize() + a.Overhead() + len(plaintext)) 27 28 nonce := (*dst)[offset : offset+a.NonceSize()] 29 if _, err := rand.Read(nonce); err != nil { 30 return nil, err 31 } 32 33 b := a.Seal((*dst)[offset:offset+a.NonceSize()], nonce, plaintext, nil) 34 *dst = (*dst)[:offset+len(b)] 35 return b, nil 36 } 37 38 func (a *AEAD) Decrypt(ciphertext []byte) ([]byte, error) { 39 if len(ciphertext) <= a.NonceSize() { 40 return nil, ErrInvalidCiphertext 41 } 42 43 nonce := ciphertext[:a.NonceSize()] 44 payload := ciphertext[a.NonceSize():] 45 46 b, err := a.Open(ciphertext[a.NonceSize():a.NonceSize()], nonce, payload, nil) 47 if err != nil { 48 return nil, ErrInvalidCiphertext 49 } 50 51 return ciphertext[a.NonceSize() : a.NonceSize()+len(b)], nil 52 } 53 54 func (a *AEAD) Clone() *AEAD { 55 o := *a 56 v := new(AEAD) 57 *v = o 58 return v 59 } 60 61 // NewAEAD supports security "none" | "aes-128-gcm" | "chacha20-poly1305", 62 // returns "nil, nil" if security is "none" 63 func NewAEAD(security, key, salt string) (*AEAD, error) { 64 security = strings.ToLower(security) 65 if security == "" || security == "none" { 66 return nil, nil 67 } 68 69 salted := []byte(key + salt) 70 keySum := sha256.Sum256(salted) 71 72 var ( 73 aead cipher.AEAD 74 err error 75 ) 76 switch security { 77 case "aes-128-gcm": 78 var block cipher.Block 79 block, err = aes.NewCipher(keySum[:16]) 80 if err != nil { 81 return nil, err 82 } 83 aead, err = cipher.NewGCM(block) 84 case "chacha20-poly1305": 85 aead, err = chacha20poly1305.New(keySum[:]) 86 default: 87 err = fmt.Errorf("unsupported cipher: %s", security) 88 } 89 90 if err != nil { 91 return nil, err 92 } 93 94 return &AEAD{AEAD: aead}, nil 95 }