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  }