github.com/metacubex/mihomo@v1.18.5/transport/shadowsocks/shadowstream/stream.go (about) 1 package shadowstream 2 3 import ( 4 "crypto/cipher" 5 "crypto/rand" 6 "io" 7 "net" 8 ) 9 10 const bufSize = 2048 11 12 type Writer struct { 13 io.Writer 14 cipher.Stream 15 buf [bufSize]byte 16 } 17 18 // NewWriter wraps an io.Writer with stream cipher encryption. 19 func NewWriter(w io.Writer, s cipher.Stream) *Writer { return &Writer{Writer: w, Stream: s} } 20 21 func (w *Writer) Write(p []byte) (n int, err error) { 22 buf := w.buf[:] 23 for nw := 0; n < len(p) && err == nil; n += nw { 24 end := n + len(buf) 25 if end > len(p) { 26 end = len(p) 27 } 28 w.XORKeyStream(buf, p[n:end]) 29 nw, err = w.Writer.Write(buf[:end-n]) 30 } 31 return 32 } 33 34 func (w *Writer) ReadFrom(r io.Reader) (n int64, err error) { 35 buf := w.buf[:] 36 for { 37 nr, er := r.Read(buf) 38 n += int64(nr) 39 b := buf[:nr] 40 w.XORKeyStream(b, b) 41 if _, err = w.Writer.Write(b); err != nil { 42 return 43 } 44 if er != nil { 45 if er != io.EOF { // ignore EOF as per io.ReaderFrom contract 46 err = er 47 } 48 return 49 } 50 } 51 } 52 53 type Reader struct { 54 io.Reader 55 cipher.Stream 56 buf [bufSize]byte 57 } 58 59 // NewReader wraps an io.Reader with stream cipher decryption. 60 func NewReader(r io.Reader, s cipher.Stream) *Reader { return &Reader{Reader: r, Stream: s} } 61 62 func (r *Reader) Read(p []byte) (n int, err error) { 63 n, err = r.Reader.Read(p) 64 if err != nil { 65 return 0, err 66 } 67 r.XORKeyStream(p, p[:n]) 68 return 69 } 70 71 func (r *Reader) WriteTo(w io.Writer) (n int64, err error) { 72 buf := r.buf[:] 73 for { 74 nr, er := r.Reader.Read(buf) 75 if nr > 0 { 76 r.XORKeyStream(buf, buf[:nr]) 77 nw, ew := w.Write(buf[:nr]) 78 n += int64(nw) 79 if ew != nil { 80 err = ew 81 return 82 } 83 } 84 if er != nil { 85 if er != io.EOF { // ignore EOF as per io.Copy contract (using src.WriteTo shortcut) 86 err = er 87 } 88 return 89 } 90 } 91 } 92 93 // A Conn represents a Shadowsocks connection. It implements the net.Conn interface. 94 type Conn struct { 95 net.Conn 96 Cipher 97 r *Reader 98 w *Writer 99 readIV []byte 100 writeIV []byte 101 } 102 103 // NewConn wraps a stream-oriented net.Conn with stream cipher encryption/decryption. 104 func NewConn(c net.Conn, ciph Cipher) *Conn { return &Conn{Conn: c, Cipher: ciph} } 105 106 func (c *Conn) initReader() error { 107 if c.r == nil { 108 iv, err := c.ObtainReadIV() 109 if err != nil { 110 return err 111 } 112 c.r = NewReader(c.Conn, c.Decrypter(iv)) 113 } 114 return nil 115 } 116 117 func (c *Conn) Read(b []byte) (int, error) { 118 if c.r == nil { 119 if err := c.initReader(); err != nil { 120 return 0, err 121 } 122 } 123 return c.r.Read(b) 124 } 125 126 func (c *Conn) WriteTo(w io.Writer) (int64, error) { 127 if c.r == nil { 128 if err := c.initReader(); err != nil { 129 return 0, err 130 } 131 } 132 return c.r.WriteTo(w) 133 } 134 135 func (c *Conn) initWriter() error { 136 if c.w == nil { 137 iv, err := c.ObtainWriteIV() 138 if err != nil { 139 return err 140 } 141 if _, err := c.Conn.Write(iv); err != nil { 142 return err 143 } 144 c.w = NewWriter(c.Conn, c.Encrypter(iv)) 145 } 146 return nil 147 } 148 149 func (c *Conn) Write(b []byte) (int, error) { 150 if c.w == nil { 151 if err := c.initWriter(); err != nil { 152 return 0, err 153 } 154 } 155 return c.w.Write(b) 156 } 157 158 func (c *Conn) ReadFrom(r io.Reader) (int64, error) { 159 if c.w == nil { 160 if err := c.initWriter(); err != nil { 161 return 0, err 162 } 163 } 164 return c.w.ReadFrom(r) 165 } 166 167 func (c *Conn) ObtainWriteIV() ([]byte, error) { 168 if len(c.writeIV) == c.IVSize() { 169 return c.writeIV, nil 170 } 171 172 iv := make([]byte, c.IVSize()) 173 174 if _, err := rand.Read(iv); err != nil { 175 return nil, err 176 } 177 178 c.writeIV = iv 179 180 return iv, nil 181 } 182 183 func (c *Conn) ObtainReadIV() ([]byte, error) { 184 if len(c.readIV) == c.IVSize() { 185 return c.readIV, nil 186 } 187 188 iv := make([]byte, c.IVSize()) 189 190 if _, err := io.ReadFull(c.Conn, iv); err != nil { 191 return nil, err 192 } 193 194 c.readIV = iv 195 196 return iv, nil 197 }