github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/pkg/net/proxy/shadowsocksr/cipher/cipher.go (about)

     1  package cipher
     2  
     3  import (
     4  	"crypto/aes"
     5  	"crypto/cipher"
     6  	"crypto/des"
     7  	"crypto/md5"
     8  	"crypto/rc4"
     9  	"encoding/binary"
    10  
    11  	"github.com/Asutorufa/yuhaiin/pkg/net/proxy/shadowsocksr/cipher/camellia"
    12  	"github.com/Asutorufa/yuhaiin/pkg/net/proxy/shadowsocksr/cipher/idea"
    13  	"github.com/Asutorufa/yuhaiin/pkg/net/proxy/shadowsocksr/cipher/rc2"
    14  	"github.com/Asutorufa/yuhaiin/pkg/utils/pool"
    15  	"golang.org/x/crypto/blowfish"
    16  	"golang.org/x/crypto/cast5"
    17  	"golang.org/x/crypto/chacha20"
    18  	"golang.org/x/crypto/salsa20/salsa"
    19  )
    20  
    21  func newAESCTRStream(key, iv []byte, _ bool) (cipher.Stream, error) {
    22  	block, err := aes.NewCipher(key)
    23  	if err != nil {
    24  		return nil, err
    25  	}
    26  	return cipher.NewCTR(block, iv), nil
    27  }
    28  
    29  func newAESOFBStream(key, iv []byte, _ bool) (cipher.Stream, error) {
    30  	block, err := aes.NewCipher(key)
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  	return cipher.NewOFB(block, iv), nil
    35  }
    36  
    37  func newRC4MD5Stream(key, iv []byte, _ bool) (cipher.Stream, error) {
    38  	rc4key := md5.Sum(append(key, iv...))
    39  	return rc4.NewCipher(rc4key[:])
    40  }
    41  
    42  func newChaCha20Stream(key, iv []byte, _ bool) (cipher.Stream, error) {
    43  	return chacha20.NewUnauthenticatedCipher(key, iv)
    44  }
    45  
    46  type salsaStreamCipher struct {
    47  	nonce   [8]byte
    48  	key     [32]byte
    49  	counter int
    50  }
    51  
    52  func (c *salsaStreamCipher) XORKeyStream(dst, src []byte) {
    53  	var buf []byte
    54  	padLen := c.counter % 64
    55  	dataSize := len(src) + padLen
    56  	if cap(dst) >= dataSize {
    57  		buf = dst[:dataSize]
    58  	} else if pool.DefaultSize >= dataSize {
    59  		buf = pool.GetBytes(pool.DefaultSize)
    60  		defer pool.PutBytes(buf)
    61  		buf = buf[:dataSize]
    62  	} else {
    63  		buf = make([]byte, dataSize)
    64  	}
    65  
    66  	var subNonce [16]byte
    67  	copy(subNonce[:], c.nonce[:])
    68  	binary.LittleEndian.PutUint64(subNonce[len(c.nonce):], uint64(c.counter/64))
    69  
    70  	// It's difficult to avoid data copy here. src or dst maybe slice from
    71  	// Conn.Read/Write, which can't have padding.
    72  	copy(buf[padLen:], src[:])
    73  	salsa.XORKeyStream(buf, buf, &subNonce, &c.key)
    74  	copy(dst, buf[padLen:])
    75  
    76  	c.counter += len(src)
    77  }
    78  
    79  func newSalsa20Stream(key, iv []byte, _ bool) (cipher.Stream, error) {
    80  	var c salsaStreamCipher
    81  	copy(c.nonce[:], iv[:8])
    82  	copy(c.key[:], key[:32])
    83  
    84  	return &c, nil
    85  }
    86  
    87  func newRC4Stream(key, iv []byte, doe bool) (cipher.Stream, error) {
    88  	return rc4.NewCipher(key)
    89  }
    90  
    91  func newCFBStream(block cipher.Block, err error, iv []byte, decrypt bool) (cipher.Stream, error) {
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  	if !decrypt {
    96  		return cipher.NewCFBEncrypter(block, iv), nil
    97  	} else {
    98  		return cipher.NewCFBDecrypter(block, iv), nil
    99  	}
   100  }
   101  
   102  func newAESCFBStream(key, iv []byte, doe bool) (cipher.Stream, error) {
   103  	block, err := aes.NewCipher(key)
   104  	return newCFBStream(block, err, iv, doe)
   105  }
   106  
   107  func newDESStream(key, iv []byte, doe bool) (cipher.Stream, error) {
   108  	block, err := des.NewCipher(key)
   109  	return newCFBStream(block, err, iv, doe)
   110  }
   111  
   112  func newBlowFishStream(key, iv []byte, doe bool) (cipher.Stream, error) {
   113  	aes.NewCipher(key)
   114  	block, err := blowfish.NewCipher(key)
   115  	return newCFBStream(block, err, iv, doe)
   116  }
   117  
   118  func newCast5Stream(key, iv []byte, doe bool) (cipher.Stream, error) {
   119  	block, err := cast5.NewCipher(key)
   120  	return newCFBStream(block, err, iv, doe)
   121  }
   122  
   123  func newCamelliaStream(key, iv []byte, doe bool) (cipher.Stream, error) {
   124  	block, err := camellia.NewCipher(key)
   125  	return newCFBStream(block, err, iv, doe)
   126  }
   127  
   128  func newIdeaStream(key, iv []byte, doe bool) (cipher.Stream, error) {
   129  	block, err := idea.NewCipher(key)
   130  	return newCFBStream(block, err, iv, doe)
   131  }
   132  
   133  func newRC2Stream(key, iv []byte, doe bool) (cipher.Stream, error) {
   134  	block, err := rc2.New(key, 16)
   135  	return newCFBStream(block, err, iv, doe)
   136  }
   137  
   138  func newSeedStream(key, iv []byte, doe bool) (cipher.Stream, error) {
   139  	// TODO: SEED block cipher implementation is required
   140  	block, err := rc2.New(key, 16)
   141  	return newCFBStream(block, err, iv, doe)
   142  }
   143  
   144  type NoneStream struct{}
   145  
   146  func (NoneStream) XORKeyStream(dst, src []byte)                     { copy(dst, src) }
   147  func newNoneStream(key, iv []byte, doe bool) (cipher.Stream, error) { return new(NoneStream), nil }
   148  
   149  type CipherFactory interface {
   150  	IVSize() int
   151  	EncryptStream(iv []byte) (cipher.Stream, error)
   152  	DecryptStream(iv []byte) (cipher.Stream, error)
   153  }
   154  type cipherFactory struct {
   155  	key    []byte
   156  	ivSize int
   157  	stream func(key, iv []byte, decrypt bool) (cipher.Stream, error)
   158  }
   159  
   160  func (c cipherFactory) IVSize() int { return c.ivSize }
   161  func (c cipherFactory) EncryptStream(iv []byte) (cipher.Stream, error) {
   162  	return c.stream(c.key, iv, false)
   163  }
   164  func (c cipherFactory) DecryptStream(iv []byte) (cipher.Stream, error) {
   165  	return c.stream(c.key, iv, true)
   166  }
   167  
   168  func newCipherObserver(keySize, ivSize int, stream func(key, iv []byte, decrypt bool) (cipher.Stream, error)) struct {
   169  	KeySize int
   170  	Creator func(key []byte) CipherFactory
   171  } {
   172  	return struct {
   173  		KeySize int
   174  		Creator func(key []byte) CipherFactory
   175  	}{
   176  		KeySize: keySize,
   177  		Creator: func(key []byte) CipherFactory {
   178  			return cipherFactory{key, ivSize, stream}
   179  		},
   180  	}
   181  }
   182  
   183  var StreamCipherMethod = map[string]struct {
   184  	KeySize int
   185  	Creator func(key []byte) CipherFactory
   186  }{
   187  	"aes-128-cfb":      newCipherObserver(16, 16, newAESCFBStream),
   188  	"aes-192-cfb":      newCipherObserver(24, 16, newAESCFBStream),
   189  	"aes-256-cfb":      newCipherObserver(32, 16, newAESCFBStream),
   190  	"aes-128-ctr":      newCipherObserver(16, 16, newAESCTRStream),
   191  	"aes-192-ctr":      newCipherObserver(24, 16, newAESCTRStream),
   192  	"aes-256-ctr":      newCipherObserver(32, 16, newAESCTRStream),
   193  	"aes-128-ofb":      newCipherObserver(16, 16, newAESOFBStream),
   194  	"aes-192-ofb":      newCipherObserver(24, 16, newAESOFBStream),
   195  	"aes-256-ofb":      newCipherObserver(32, 16, newAESOFBStream),
   196  	"des-cfb":          newCipherObserver(8, 8, newDESStream),
   197  	"bf-cfb":           newCipherObserver(16, 8, newBlowFishStream),
   198  	"cast5-cfb":        newCipherObserver(16, 8, newCast5Stream),
   199  	"rc4-md5":          newCipherObserver(16, 16, newRC4MD5Stream),
   200  	"rc4-md5-6":        newCipherObserver(16, 6, newRC4MD5Stream),
   201  	"chacha20":         newCipherObserver(chacha20.KeySize, 8, newChaCha20Stream),
   202  	"chacha20-ietf":    newCipherObserver(chacha20.KeySize, chacha20.NonceSize, newChaCha20Stream),
   203  	"salsa20":          newCipherObserver(32, 8, newSalsa20Stream),
   204  	"camellia-128-cfb": newCipherObserver(16, 16, newCamelliaStream),
   205  	"camellia-192-cfb": newCipherObserver(24, 16, newCamelliaStream),
   206  	"camellia-256-cfb": newCipherObserver(32, 16, newCamelliaStream),
   207  	"idea-cfb":         newCipherObserver(16, 8, newIdeaStream),
   208  	"rc2-cfb":          newCipherObserver(16, 8, newRC2Stream),
   209  	"seed-cfb":         newCipherObserver(16, 8, newSeedStream),
   210  	"rc4":              newCipherObserver(16, 0, newRC4Stream),
   211  	"none":             newCipherObserver(16, 0, newNoneStream),
   212  }