github.com/database64128/shadowsocks-go@v1.7.0/ss2022/stream.go (about) 1 package ss2022 2 3 import ( 4 "bytes" 5 "crypto/cipher" 6 "crypto/rand" 7 "encoding/binary" 8 "errors" 9 "io" 10 11 "github.com/database64128/shadowsocks-go/zerocopy" 12 ) 13 14 const MaxPayloadSize = 0xFFFF 15 16 // ShadowStreamHeadroom is the headroom required by an encrypted Shadowsocks stream. 17 // 18 // Front is the size of an encrypted length chunk. 19 // Rear is the size of an AEAD tag. 20 var ShadowStreamHeadroom = zerocopy.Headroom{ 21 Front: 2 + 16, 22 Rear: 16, 23 } 24 25 // ShadowStreamReaderInfo contains information about a [ShadowStreamReader]. 26 var ShadowStreamReaderInfo = zerocopy.ReaderInfo{ 27 Headroom: ShadowStreamHeadroom, 28 MinPayloadBufferSizePerRead: MaxPayloadSize, 29 } 30 31 // ShadowStreamWriterInfo contains information about a [ShadowStreamWriter]. 32 var ShadowStreamWriterInfo = zerocopy.WriterInfo{ 33 Headroom: ShadowStreamHeadroom, 34 MaxPayloadSizePerWrite: MaxPayloadSize, 35 } 36 37 var ( 38 ErrZeroLengthChunk = errors.New("length in length chunk is zero") 39 ErrFirstRead = errors.New("failed to read fixed-length header in one read call") 40 ErrRepeatedSalt = errors.New("detected replay: repeated salt") 41 ) 42 43 var ErrUnsafeStreamPrefixMismatch = errors.New("unsafe stream prefix mismatch") 44 45 // ShadowStreamServerReadWriter implements Shadowsocks stream server. 46 type ShadowStreamServerReadWriter struct { 47 *ShadowStreamReader 48 *ShadowStreamWriter 49 rawRW zerocopy.DirectReadWriteCloser 50 cipherConfig UserCipherConfig 51 requestSalt []byte 52 unsafeResponseStreamPrefix []byte 53 } 54 55 // WriteZeroCopy implements the Writer WriteZeroCopy method. 56 func (rw *ShadowStreamServerReadWriter) WriteZeroCopy(b []byte, payloadStart, payloadLen int) (int, error) { 57 if rw.ShadowStreamWriter == nil { // first write 58 urspLen := len(rw.unsafeResponseStreamPrefix) 59 saltLen := len(rw.cipherConfig.PSK) 60 responseHeaderStart := urspLen + saltLen 61 responseHeaderEnd := responseHeaderStart + TCPRequestFixedLengthHeaderLength + saltLen 62 payloadBufStart := responseHeaderEnd + 16 63 bufferLen := payloadBufStart + payloadLen + 16 64 hb := make([]byte, bufferLen) 65 ursp := hb[:urspLen] 66 salt := hb[urspLen:responseHeaderStart] 67 responseHeader := hb[responseHeaderStart:responseHeaderEnd] 68 69 // Write unsafe response stream prefix. 70 copy(ursp, rw.unsafeResponseStreamPrefix) 71 72 // Random salt. 73 _, err := rand.Read(salt) 74 if err != nil { 75 return 0, err 76 } 77 78 // Write response header. 79 WriteTCPResponseHeader(responseHeader, rw.requestSalt, uint16(payloadLen)) 80 81 // Create AEAD cipher. 82 shadowStreamCipher, err := rw.cipherConfig.ShadowStreamCipher(salt) 83 if err != nil { 84 return 0, err 85 } 86 87 // Create writer. 88 rw.ShadowStreamWriter = &ShadowStreamWriter{ 89 writer: rw.rawRW, 90 ssc: shadowStreamCipher, 91 } 92 93 // Seal response header. 94 shadowStreamCipher.EncryptInPlace(responseHeader) 95 96 // Seal payload. 97 dst := hb[payloadBufStart:] 98 plaintext := b[payloadStart : payloadStart+payloadLen] 99 shadowStreamCipher.EncryptTo(dst, plaintext) 100 101 // Write out. 102 _, err = rw.rawRW.Write(hb) 103 if err != nil { 104 return 0, err 105 } 106 107 return payloadLen, nil 108 } 109 110 return rw.ShadowStreamWriter.WriteZeroCopy(b, payloadStart, payloadLen) 111 } 112 113 // CloseRead implements the ReadWriter CloseRead method. 114 func (rw *ShadowStreamServerReadWriter) CloseRead() error { 115 return rw.rawRW.CloseRead() 116 } 117 118 // CloseWrite implements the ReadWriter CloseWrite method. 119 func (rw *ShadowStreamServerReadWriter) CloseWrite() error { 120 return rw.rawRW.CloseWrite() 121 } 122 123 // Close implements the ReadWriter Close method. 124 func (rw *ShadowStreamServerReadWriter) Close() error { 125 return rw.rawRW.Close() 126 } 127 128 // ShadowStreamClientReadWriter implements Shadowsocks stream client. 129 type ShadowStreamClientReadWriter struct { 130 *ShadowStreamReader 131 *ShadowStreamWriter 132 rawRW zerocopy.DirectReadWriteCloser 133 cipherConfig *ClientCipherConfig 134 requestSalt []byte 135 unsafeResponseStreamPrefix []byte 136 } 137 138 // ReadZeroCopy implements the Reader ReadZeroCopy method. 139 func (rw *ShadowStreamClientReadWriter) ReadZeroCopy(b []byte, payloadBufStart, payloadBufLen int) (int, error) { 140 if rw.ShadowStreamReader == nil { // first read 141 urspLen := len(rw.unsafeResponseStreamPrefix) 142 saltLen := len(rw.cipherConfig.PSK) 143 fixedLengthHeaderStart := urspLen + saltLen 144 bufferLen := fixedLengthHeaderStart + TCPRequestFixedLengthHeaderLength + saltLen + 16 145 hb := make([]byte, bufferLen) 146 147 // Read response header. 148 n, err := rw.rawRW.Read(hb) 149 if err != nil { 150 return 0, err 151 } 152 if n < bufferLen { 153 return 0, &HeaderError[int]{ErrFirstRead, bufferLen, n} 154 } 155 156 // Check unsafe response stream prefix. 157 ursp := hb[:urspLen] 158 if !bytes.Equal(ursp, rw.unsafeResponseStreamPrefix) { 159 return 0, &HeaderError[[]byte]{ErrUnsafeStreamPrefixMismatch, rw.unsafeResponseStreamPrefix, ursp} 160 } 161 162 // Derive key and create cipher. 163 salt := hb[urspLen:fixedLengthHeaderStart] 164 ciphertext := hb[fixedLengthHeaderStart:] 165 shadowStreamCipher, err := rw.cipherConfig.ShadowStreamCipher(salt) 166 if err != nil { 167 return 0, err 168 } 169 170 // Create reader. 171 rw.ShadowStreamReader = &ShadowStreamReader{ 172 reader: rw.rawRW, 173 ssc: shadowStreamCipher, 174 } 175 176 // AEAD open. 177 plaintext, err := shadowStreamCipher.DecryptInPlace(ciphertext) 178 if err != nil { 179 return 0, err 180 } 181 182 // Parse response header. 183 n, err = ParseTCPResponseHeader(plaintext, rw.requestSalt) 184 if err != nil { 185 return 0, err 186 } 187 188 payloadBuf := b[payloadBufStart : payloadBufStart+n+16] 189 190 // Read payload chunk. 191 _, err = io.ReadFull(rw.rawRW, payloadBuf) 192 if err != nil { 193 return 0, err 194 } 195 196 // AEAD open. 197 _, err = shadowStreamCipher.DecryptInPlace(payloadBuf) 198 if err != nil { 199 return 0, err 200 } 201 202 return n, nil 203 } 204 205 return rw.ShadowStreamReader.ReadZeroCopy(b, payloadBufStart, payloadBufLen) 206 } 207 208 // CloseRead implements the ReadWriter CloseRead method. 209 func (rw *ShadowStreamClientReadWriter) CloseRead() error { 210 return rw.rawRW.CloseRead() 211 } 212 213 // CloseWrite implements the ReadWriter CloseWrite method. 214 func (rw *ShadowStreamClientReadWriter) CloseWrite() error { 215 return rw.rawRW.CloseWrite() 216 } 217 218 // Close implements the ReadWriter Close method. 219 func (rw *ShadowStreamClientReadWriter) Close() error { 220 return rw.rawRW.Close() 221 } 222 223 // ShadowStreamWriter wraps an io.WriteCloser and feeds an encrypted Shadowsocks stream to it. 224 // 225 // Wire format: 226 // 227 // +------------------------+---------------------------+ 228 // | encrypted length chunk | encrypted payload chunk | 229 // +------------------------+---------------------------+ 230 // | 2B length + 16B tag | variable length + 16B tag | 231 // +------------------------+---------------------------+ 232 type ShadowStreamWriter struct { 233 writer io.WriteCloser 234 ssc *ShadowStreamCipher 235 } 236 237 // WriterInfo implements the Writer WriterInfo method. 238 func (w *ShadowStreamWriter) WriterInfo() zerocopy.WriterInfo { 239 return ShadowStreamWriterInfo 240 } 241 242 // WriteZeroCopy implements the Writer WriteZeroCopy method. 243 func (w *ShadowStreamWriter) WriteZeroCopy(b []byte, payloadStart, payloadLen int) (payloadWritten int, err error) { 244 overhead := w.ssc.Overhead() 245 lengthStart := payloadStart - overhead - 2 246 lengthBuf := b[lengthStart : lengthStart+2] 247 payloadBuf := b[payloadStart : payloadStart+payloadLen] 248 payloadTagEnd := payloadStart + payloadLen + overhead 249 chunksBuf := b[lengthStart:payloadTagEnd] 250 251 // Write length. 252 binary.BigEndian.PutUint16(lengthBuf, uint16(payloadLen)) 253 254 // Seal length chunk. 255 w.ssc.EncryptInPlace(lengthBuf) 256 257 // Seal payload chunk. 258 w.ssc.EncryptInPlace(payloadBuf) 259 260 // Write to wrapped writer. 261 _, err = w.writer.Write(chunksBuf) 262 if err != nil { 263 return 264 } 265 payloadWritten = payloadLen 266 return 267 } 268 269 // ShadowStreamReader wraps an io.ReadCloser and reads from it as an encrypted Shadowsocks stream. 270 type ShadowStreamReader struct { 271 reader io.ReadCloser 272 ssc *ShadowStreamCipher 273 } 274 275 // ReaderInfo implements the Reader ReaderInfo method. 276 func (r *ShadowStreamReader) ReaderInfo() zerocopy.ReaderInfo { 277 return ShadowStreamReaderInfo 278 } 279 280 // ReadZeroCopy implements the Reader ReadZeroCopy method. 281 func (r *ShadowStreamReader) ReadZeroCopy(b []byte, payloadBufStart, payloadBufLen int) (payloadLen int, err error) { 282 overhead := r.ssc.Overhead() 283 sealedLengthChunkStart := payloadBufStart - overhead - 2 284 sealedLengthChunkBuf := b[sealedLengthChunkStart:payloadBufStart] 285 286 // Read sealed length chunk. 287 _, err = io.ReadFull(r.reader, sealedLengthChunkBuf) 288 if err != nil { 289 return 290 } 291 292 // Open sealed length chunk. 293 _, err = r.ssc.DecryptInPlace(sealedLengthChunkBuf) 294 if err != nil { 295 return 296 } 297 298 // Validate length. 299 payloadLen = int(binary.BigEndian.Uint16(sealedLengthChunkBuf)) 300 if payloadLen == 0 { 301 err = ErrZeroLengthChunk 302 return 303 } 304 305 // Read sealed payload chunk. 306 sealedPayloadChunkBuf := b[payloadBufStart : payloadBufStart+payloadLen+overhead] 307 _, err = io.ReadFull(r.reader, sealedPayloadChunkBuf) 308 if err != nil { 309 payloadLen = 0 310 return 311 } 312 313 // Open sealed payload chunk. 314 _, err = r.ssc.DecryptInPlace(sealedPayloadChunkBuf) 315 if err != nil { 316 payloadLen = 0 317 } 318 319 return 320 } 321 322 // ShadowStreamCipher wraps an AEAD cipher and provides methods that transparently increments 323 // the nonce after each AEAD operation. 324 type ShadowStreamCipher struct { 325 aead cipher.AEAD 326 nonce []byte 327 } 328 329 // NewShadowStreamCipher wraps the given AEAD cipher into a new ShadowStreamCipher. 330 func NewShadowStreamCipher(aead cipher.AEAD) *ShadowStreamCipher { 331 return &ShadowStreamCipher{ 332 aead: aead, 333 nonce: make([]byte, aead.NonceSize()), 334 } 335 } 336 337 // Overhead returns the tag size of the AEAD cipher. 338 func (c *ShadowStreamCipher) Overhead() int { 339 return c.aead.Overhead() 340 } 341 342 // EncryptInPlace encrypts and authenticates plaintext in-place. 343 func (c *ShadowStreamCipher) EncryptInPlace(plaintext []byte) (ciphertext []byte) { 344 ciphertext = c.aead.Seal(plaintext[:0], c.nonce, plaintext, nil) 345 increment(c.nonce) 346 return 347 } 348 349 // EncryptTo encrypts and authenticates the plaintext and saves the ciphertext to dst. 350 func (c *ShadowStreamCipher) EncryptTo(dst, plaintext []byte) (ciphertext []byte) { 351 ciphertext = c.aead.Seal(dst[:0], c.nonce, plaintext, nil) 352 increment(c.nonce) 353 return 354 } 355 356 // DecryptInplace decrypts and authenticates ciphertext in-place. 357 func (c *ShadowStreamCipher) DecryptInPlace(ciphertext []byte) (plaintext []byte, err error) { 358 plaintext, err = c.aead.Open(ciphertext[:0], c.nonce, ciphertext, nil) 359 if err == nil { 360 increment(c.nonce) 361 } 362 return 363 } 364 365 // DecryptTo decrypts and authenticates the ciphertext and saves the plaintext to dst. 366 func (c *ShadowStreamCipher) DecryptTo(dst, ciphertext []byte) (plaintext []byte, err error) { 367 plaintext, err = c.aead.Open(dst[:0], c.nonce, ciphertext, nil) 368 if err == nil { 369 increment(c.nonce) 370 } 371 return 372 } 373 374 // increment increments a little-endian unsigned integer b. 375 func increment(b []byte) { 376 for i := range b { 377 b[i]++ 378 if b[i] != 0 { 379 return 380 } 381 } 382 }