github.com/metacubex/mihomo@v1.18.5/transport/shadowsocks/shadowstream/cipher.go (about)

     1  package shadowstream
     2  
     3  import (
     4  	"crypto/aes"
     5  	"crypto/cipher"
     6  	"crypto/md5"
     7  	"crypto/rc4"
     8  	"strconv"
     9  
    10  	"golang.org/x/crypto/chacha20"
    11  )
    12  
    13  // Cipher generates a pair of stream ciphers for encryption and decryption.
    14  type Cipher interface {
    15  	IVSize() int
    16  	Encrypter(iv []byte) cipher.Stream
    17  	Decrypter(iv []byte) cipher.Stream
    18  }
    19  
    20  type KeySizeError int
    21  
    22  func (e KeySizeError) Error() string {
    23  	return "key size error: need " + strconv.Itoa(int(e)) + " bytes"
    24  }
    25  
    26  // CTR mode
    27  type ctrStream struct{ cipher.Block }
    28  
    29  func (b *ctrStream) IVSize() int                       { return b.BlockSize() }
    30  func (b *ctrStream) Decrypter(iv []byte) cipher.Stream { return b.Encrypter(iv) }
    31  func (b *ctrStream) Encrypter(iv []byte) cipher.Stream { return cipher.NewCTR(b, iv) }
    32  
    33  func AESCTR(key []byte) (Cipher, error) {
    34  	blk, err := aes.NewCipher(key)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	return &ctrStream{blk}, nil
    39  }
    40  
    41  // CFB mode
    42  type cfbStream struct{ cipher.Block }
    43  
    44  func (b *cfbStream) IVSize() int                       { return b.BlockSize() }
    45  func (b *cfbStream) Decrypter(iv []byte) cipher.Stream { return cipher.NewCFBDecrypter(b, iv) }
    46  func (b *cfbStream) Encrypter(iv []byte) cipher.Stream { return cipher.NewCFBEncrypter(b, iv) }
    47  
    48  func AESCFB(key []byte) (Cipher, error) {
    49  	blk, err := aes.NewCipher(key)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	return &cfbStream{blk}, nil
    54  }
    55  
    56  // IETF-variant of chacha20
    57  type chacha20ietfkey []byte
    58  
    59  func (k chacha20ietfkey) IVSize() int                       { return chacha20.NonceSize }
    60  func (k chacha20ietfkey) Decrypter(iv []byte) cipher.Stream { return k.Encrypter(iv) }
    61  func (k chacha20ietfkey) Encrypter(iv []byte) cipher.Stream {
    62  	ciph, err := chacha20.NewUnauthenticatedCipher(k, iv)
    63  	if err != nil {
    64  		panic(err) // should never happen
    65  	}
    66  	return ciph
    67  }
    68  
    69  func Chacha20IETF(key []byte) (Cipher, error) {
    70  	if len(key) != chacha20.KeySize {
    71  		return nil, KeySizeError(chacha20.KeySize)
    72  	}
    73  	return chacha20ietfkey(key), nil
    74  }
    75  
    76  type xchacha20key []byte
    77  
    78  func (k xchacha20key) IVSize() int                       { return chacha20.NonceSizeX }
    79  func (k xchacha20key) Decrypter(iv []byte) cipher.Stream { return k.Encrypter(iv) }
    80  func (k xchacha20key) Encrypter(iv []byte) cipher.Stream {
    81  	ciph, err := chacha20.NewUnauthenticatedCipher(k, iv)
    82  	if err != nil {
    83  		panic(err) // should never happen
    84  	}
    85  	return ciph
    86  }
    87  
    88  func Xchacha20(key []byte) (Cipher, error) {
    89  	if len(key) != chacha20.KeySize {
    90  		return nil, KeySizeError(chacha20.KeySize)
    91  	}
    92  	return xchacha20key(key), nil
    93  }
    94  
    95  type rc4Md5Key []byte
    96  
    97  func (k rc4Md5Key) IVSize() int {
    98  	return 16
    99  }
   100  
   101  func (k rc4Md5Key) Encrypter(iv []byte) cipher.Stream {
   102  	h := md5.New()
   103  	h.Write([]byte(k))
   104  	h.Write(iv)
   105  	rc4key := h.Sum(nil)
   106  	c, _ := rc4.NewCipher(rc4key)
   107  	return c
   108  }
   109  
   110  func (k rc4Md5Key) Decrypter(iv []byte) cipher.Stream {
   111  	return k.Encrypter(iv)
   112  }
   113  
   114  func RC4MD5(key []byte) (Cipher, error) {
   115  	return rc4Md5Key(key), nil
   116  }