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 }