1use std::cmp;
2use std::io;
3use std::pin::Pin;
4use std::task::{Context, Poll};
5
6use bytes::{Buf as _, BytesMut};
7use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
8use zeroize::Zeroizing;
9
10use crate::aead::AeadCipher;
11use crate::method::CipherMethod;
12use crate::nonce::NonceCounter;
13
14pub const MAX_CHUNK_PAYLOAD: usize = 16 * 1024 - 1;
16
17#[derive(Clone, Copy, Debug)]
19enum ReadState {
20 PeerSalt,
22 LengthBlock,
24 Payload { len: usize },
26 Closed,
28}
29
30pub struct ShadowsocksAeadStream<S> {
47 inner: S,
48 method: CipherMethod,
49 write_subkey: Zeroizing<Vec<u8>>,
51 write_cipher: Option<AeadCipher>,
52 read_subkey: Option<Zeroizing<Vec<u8>>>,
55 read_cipher: Option<AeadCipher>,
56 password_ikm: Option<Zeroizing<Vec<u8>>>,
58 send_write_salt: bool,
60 write_nonce: NonceCounter,
61 read_nonce: NonceCounter,
62 read_plain: BytesMut,
63 read_buf: BytesMut,
64 read_state: ReadState,
65 write_buf: BytesMut,
66}
67
68impl<S: AsyncRead + AsyncWrite + Unpin> ShadowsocksAeadStream<S> {
69 pub fn new(
71 inner: S,
72 method: CipherMethod,
73 subkey: Vec<u8>,
74 ) -> Result<Self, crate::error::ShadowsocksError> {
75 let nonce_size = method.nonce_size();
76 let write_cipher = AeadCipher::new(method, &subkey)?;
77 let read_cipher = AeadCipher::new(method, &subkey)?;
78 let subkey = Zeroizing::new(subkey);
79 Ok(Self {
80 inner,
81 method,
82 write_subkey: subkey.clone(),
83 write_cipher: Some(write_cipher),
84 read_subkey: Some(subkey),
85 read_cipher: Some(read_cipher),
86 password_ikm: None,
87 send_write_salt: false,
88 write_nonce: NonceCounter::starting_at(nonce_size, 0),
89 read_nonce: NonceCounter::starting_at(nonce_size, 0),
90 read_plain: BytesMut::new(),
91 read_buf: BytesMut::new(),
92 read_state: ReadState::LengthBlock,
93 write_buf: BytesMut::new(),
94 })
95 }
96
97 pub fn new_client(
102 inner: S,
103 method: CipherMethod,
104 write_subkey: Vec<u8>,
105 password: &str,
106 ) -> Result<Self, crate::error::ShadowsocksError> {
107 let nonce_size = method.nonce_size();
108 let write_cipher = AeadCipher::new(method, &write_subkey)?;
109 Ok(Self {
110 inner,
111 method,
112 write_subkey: Zeroizing::new(write_subkey),
113 write_cipher: Some(write_cipher),
114 read_subkey: None,
115 read_cipher: None,
116 password_ikm: Some(Zeroizing::new(CipherMethod::password_key_material(
117 password.as_bytes(),
118 ))),
119 send_write_salt: false,
120 write_nonce: NonceCounter::starting_at(nonce_size, 2),
122 read_nonce: NonceCounter::starting_at(nonce_size, 0),
124 read_plain: BytesMut::new(),
125 read_buf: BytesMut::new(),
126 read_state: ReadState::PeerSalt,
127 write_buf: BytesMut::new(),
128 })
129 }
130
131 pub fn new_server(
137 inner: S,
138 method: CipherMethod,
139 read_subkey: Vec<u8>,
140 send_write_salt: bool,
141 password: &str,
142 ) -> Result<Self, crate::error::ShadowsocksError> {
143 if !send_write_salt {
144 return Err(crate::error::ShadowsocksError::Other(
145 "server streams must send a write salt".to_string(),
146 ));
147 }
148 let nonce_size = method.nonce_size();
149 let read_cipher = AeadCipher::new(method, &read_subkey)?;
150 Ok(Self {
151 inner,
152 method,
153 write_subkey: Zeroizing::new(Vec::new()), write_cipher: None,
155 read_subkey: Some(Zeroizing::new(read_subkey)),
156 read_cipher: Some(read_cipher),
157 password_ikm: Some(Zeroizing::new(CipherMethod::password_key_material(
158 password.as_bytes(),
159 ))),
160 send_write_salt,
161 read_nonce: NonceCounter::starting_at(nonce_size, 2),
163 write_nonce: NonceCounter::starting_at(nonce_size, 0),
165 read_plain: BytesMut::new(),
166 read_buf: BytesMut::new(),
167 read_state: ReadState::LengthBlock,
168 write_buf: BytesMut::new(),
169 })
170 }
171
172 pub fn new_with_nonces(
174 inner: S,
175 method: CipherMethod,
176 subkey: Vec<u8>,
177 write_start: u64,
178 read_start: u64,
179 ) -> Result<Self, crate::error::ShadowsocksError> {
180 let nonce_size = method.nonce_size();
181 let write_cipher = AeadCipher::new(method, &subkey)?;
182 let read_cipher = AeadCipher::new(method, &subkey)?;
183 let subkey = Zeroizing::new(subkey);
184 Ok(Self {
185 inner,
186 method,
187 write_subkey: subkey.clone(),
188 write_cipher: Some(write_cipher),
189 read_subkey: Some(subkey),
190 read_cipher: Some(read_cipher),
191 password_ikm: None,
192 send_write_salt: false,
193 write_nonce: NonceCounter::starting_at(nonce_size, write_start),
194 read_nonce: NonceCounter::starting_at(nonce_size, read_start),
195 read_plain: BytesMut::new(),
196 read_buf: BytesMut::new(),
197 read_state: ReadState::LengthBlock,
198 write_buf: BytesMut::new(),
199 })
200 }
201
202 pub fn into_inner(self) -> S {
203 self.inner
204 }
205
206 pub(crate) fn prepend_read_plaintext(&mut self, plaintext: &[u8]) {
210 if !plaintext.is_empty() {
211 self.read_plain.extend_from_slice(plaintext);
212 }
213 }
214}
215
216fn read_until<S: AsyncRead + Unpin>(
225 inner: &mut S,
226 cx: &mut Context<'_>,
227 buf: &mut BytesMut,
228 target: usize,
229) -> Poll<io::Result<bool>> {
230 while buf.len() < target {
231 let start = buf.len();
232 buf.resize(target, 0);
233 let mut rbuf = ReadBuf::new(&mut buf[start..target]);
234 match Pin::new(&mut *inner).poll_read(cx, &mut rbuf) {
235 Poll::Ready(Ok(())) => {
236 let n = rbuf.filled().len();
237 if n == 0 {
238 buf.truncate(start);
240 return Poll::Ready(Ok(false));
241 }
242 buf.truncate(start + n);
243 }
244 Poll::Ready(Err(e)) => {
245 buf.truncate(start);
246 return Poll::Ready(Err(e));
247 }
248 Poll::Pending => {
249 buf.truncate(start);
250 return Poll::Pending;
251 }
252 }
253 }
254 Poll::Ready(Ok(true))
255}
256
257impl<S: AsyncRead + AsyncWrite + Unpin> AsyncRead for ShadowsocksAeadStream<S> {
258 fn poll_read(
259 self: Pin<&mut Self>,
260 cx: &mut Context<'_>,
261 buf: &mut ReadBuf<'_>,
262 ) -> Poll<io::Result<()>> {
263 let this = self.get_mut();
264
265 if !this.read_plain.is_empty() {
267 let n = cmp::min(this.read_plain.len(), buf.remaining());
268 buf.put_slice(&this.read_plain.split_to(n));
269 return Poll::Ready(Ok(()));
270 }
271
272 loop {
274 let state = this.read_state;
275 match state {
276 ReadState::Closed => return Poll::Ready(Ok(())),
277 ReadState::PeerSalt => {
278 let salt_size = this.method.salt_size();
280 match read_until(&mut this.inner, cx, &mut this.read_buf, salt_size) {
281 Poll::Ready(Ok(true)) => {}
282 Poll::Ready(Ok(false)) => {
283 this.read_buf.clear();
284 return Poll::Ready(Ok(()));
285 }
286 Poll::Ready(Err(e)) => {
287 this.read_buf.clear();
288 return Poll::Ready(Err(e));
289 }
290 Poll::Pending => return Poll::Pending,
291 }
292
293 let salt = this.read_buf.split_to(salt_size);
294 let password_ikm = this
295 .password_ikm
296 .as_deref()
297 .ok_or_else(|| io::Error::other("no password for subkey derivation"))?;
298 let read_subkey = this
299 .method
300 .derive_key_from_ikm(password_ikm, &salt)
301 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
302 let read_cipher = AeadCipher::new(this.method, &read_subkey)
303 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
304 this.read_subkey = Some(Zeroizing::new(read_subkey));
305 this.read_cipher = Some(read_cipher);
306 this.read_buf.clear();
307 this.read_state = ReadState::LengthBlock;
308 }
309 ReadState::LengthBlock => {
310 let len_block_size = 2 + this.method.tag_size();
312 match read_until(&mut this.inner, cx, &mut this.read_buf, len_block_size) {
313 Poll::Ready(Ok(true)) => {}
314 Poll::Ready(Ok(false)) => {
315 this.read_buf.clear();
317 return Poll::Ready(Ok(()));
318 }
319 Poll::Ready(Err(e)) => {
320 this.read_buf.clear();
321 return Poll::Ready(Err(e));
322 }
323 Poll::Pending => return Poll::Pending,
324 }
325
326 let cipher = this
327 .read_cipher
328 .as_ref()
329 .ok_or_else(|| io::Error::other("read cipher not yet derived"))?;
330
331 let mut nonce = [0u8; 12];
333 this.read_nonce
334 .current(&mut nonce)
335 .map_err(io::Error::other)?;
336 let len_plaintext = cipher
337 .decrypt(&nonce, &this.read_buf[..len_block_size])
338 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
339
340 this.read_nonce.advance().map_err(io::Error::other)?;
342
343 if len_plaintext.len() != 2 {
344 this.read_buf.clear();
345 return Poll::Ready(Err(io::Error::new(
346 io::ErrorKind::InvalidData,
347 "invalid length block plaintext",
348 )));
349 }
350
351 let payload_len =
352 u16::from_be_bytes([len_plaintext[0], len_plaintext[1]]) as usize;
353 this.read_buf.clear();
354
355 if payload_len > MAX_CHUNK_PAYLOAD {
356 return Poll::Ready(Err(io::Error::new(
357 io::ErrorKind::InvalidData,
358 format!(
359 "payload length {} exceeds maximum {}",
360 payload_len, MAX_CHUNK_PAYLOAD
361 ),
362 )));
363 }
364
365 if payload_len == 0 {
367 this.read_state = ReadState::Closed;
368 return Poll::Ready(Ok(()));
369 }
370
371 this.read_state = ReadState::Payload { len: payload_len };
372 }
373 ReadState::Payload { len } => {
374 let wire_len = len + this.method.tag_size();
376 match read_until(&mut this.inner, cx, &mut this.read_buf, wire_len) {
377 Poll::Ready(Ok(true)) => {}
378 Poll::Ready(Ok(false)) | Poll::Ready(Err(_)) => {
379 this.read_buf.clear();
380 this.read_state = ReadState::LengthBlock;
381 return Poll::Ready(Err(io::Error::new(
382 io::ErrorKind::UnexpectedEof,
383 "unexpected EOF in payload",
384 )));
385 }
386 Poll::Pending => return Poll::Pending,
387 }
388
389 let cipher = this
390 .read_cipher
391 .as_ref()
392 .ok_or_else(|| io::Error::other("read cipher not yet derived"))?;
393
394 let mut nonce = [0u8; 12];
396 this.read_nonce
397 .current(&mut nonce)
398 .map_err(io::Error::other)?;
399 let plaintext = cipher
400 .decrypt(&nonce, &this.read_buf)
401 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
402
403 this.read_nonce.advance().map_err(io::Error::other)?;
405
406 this.read_buf.clear();
407 this.read_state = ReadState::LengthBlock;
408 if plaintext.len() <= buf.remaining() {
411 buf.put_slice(&plaintext);
412 } else {
413 this.read_plain.extend_from_slice(&plaintext);
414 let n = cmp::min(this.read_plain.len(), buf.remaining());
415 buf.put_slice(&this.read_plain.split_to(n));
416 }
417 return Poll::Ready(Ok(()));
418 }
419 }
420 }
421 }
422}
423
424impl<S: AsyncRead + AsyncWrite + Unpin> AsyncWrite for ShadowsocksAeadStream<S> {
425 fn poll_write(
426 self: Pin<&mut Self>,
427 cx: &mut Context<'_>,
428 buf: &[u8],
429 ) -> Poll<io::Result<usize>> {
430 let this = self.get_mut();
431
432 if this.send_write_salt {
434 use rand::RngCore;
436 let mut salt_buf = [0u8; 32];
437 rand::thread_rng().fill_bytes(&mut salt_buf[..this.method.salt_size()]);
438 let salt = &salt_buf[..this.method.salt_size()];
439 let password_ikm = this
440 .password_ikm
441 .as_deref()
442 .ok_or_else(|| io::Error::other("no password for subkey derivation"))?;
443 let write_subkey = this
444 .method
445 .derive_key_from_ikm(password_ikm, salt)
446 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
447 let write_cipher = AeadCipher::new(this.method, &write_subkey)
448 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
449 this.write_subkey = Zeroizing::new(write_subkey);
450 this.write_cipher = Some(write_cipher);
451 this.write_buf.extend_from_slice(salt);
452 this.send_write_salt = false;
453 }
454
455 while !this.write_buf.is_empty() {
457 match Pin::new(&mut this.inner).poll_write(cx, &this.write_buf) {
458 Poll::Ready(Ok(0)) => {
459 return Poll::Ready(Err(io::Error::new(
460 io::ErrorKind::WriteZero,
461 "zero-byte write",
462 )));
463 }
464 Poll::Ready(Ok(n)) => this.write_buf.advance(n),
465 Poll::Ready(Err(e)) => return Poll::Ready(Err(e)),
466 Poll::Pending => return Poll::Pending,
467 }
468 }
469
470 let chunk_size = cmp::min(buf.len(), MAX_CHUNK_PAYLOAD);
472 if chunk_size == 0 {
473 return Poll::Ready(Ok(0));
474 }
475
476 let len_bytes = (chunk_size as u16).to_be_bytes();
478 let cipher = this
479 .write_cipher
480 .as_ref()
481 .ok_or_else(|| io::Error::other("write cipher not yet derived"))?;
482 let mut len_nonce = [0u8; 12];
483 this.write_nonce
484 .current(&mut len_nonce)
485 .map_err(io::Error::other)?;
486 let len_ct = cipher
487 .encrypt(&len_nonce, &len_bytes)
488 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
489 this.write_nonce.advance().map_err(io::Error::other)?;
490
491 let mut payload_nonce = [0u8; 12];
493 this.write_nonce
494 .current(&mut payload_nonce)
495 .map_err(io::Error::other)?;
496 let payload_ct = cipher
497 .encrypt(&payload_nonce, &buf[..chunk_size])
498 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
499 this.write_nonce.advance().map_err(io::Error::other)?;
500
501 this.write_buf.extend_from_slice(&len_ct);
503 this.write_buf.extend_from_slice(&payload_ct);
504
505 while !this.write_buf.is_empty() {
507 match Pin::new(&mut this.inner).poll_write(cx, &this.write_buf) {
508 Poll::Ready(Ok(0)) => {
509 return Poll::Ready(Err(io::Error::new(
510 io::ErrorKind::WriteZero,
511 "zero-byte write",
512 )));
513 }
514 Poll::Ready(Ok(n)) => this.write_buf.advance(n),
515 Poll::Ready(Err(e)) => return Poll::Ready(Err(e)),
516 Poll::Pending => break,
517 }
518 }
519
520 Poll::Ready(Ok(chunk_size))
521 }
522
523 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
524 let this = self.get_mut();
525
526 while !this.write_buf.is_empty() {
527 match Pin::new(&mut this.inner).poll_write(cx, &this.write_buf) {
528 Poll::Ready(Ok(0)) => {
529 return Poll::Ready(Err(io::Error::new(
530 io::ErrorKind::WriteZero,
531 "zero-byte write",
532 )));
533 }
534 Poll::Ready(Ok(n)) => this.write_buf.advance(n),
535 Poll::Ready(Err(e)) => return Poll::Ready(Err(e)),
536 Poll::Pending => return Poll::Pending,
537 }
538 }
539
540 Pin::new(&mut this.inner).poll_flush(cx)
541 }
542
543 fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
544 let this = self.get_mut();
545
546 while !this.write_buf.is_empty() {
548 match Pin::new(&mut this.inner).poll_write(cx, &this.write_buf) {
549 Poll::Ready(Ok(0)) => {
550 return Poll::Ready(Err(io::Error::new(
551 io::ErrorKind::WriteZero,
552 "zero-byte write",
553 )));
554 }
555 Poll::Ready(Ok(n)) => this.write_buf.advance(n),
556 Poll::Ready(Err(e)) => return Poll::Ready(Err(e)),
557 Poll::Pending => return Poll::Pending,
558 }
559 }
560
561 Pin::new(&mut this.inner).poll_shutdown(cx)
562 }
563}
564
565#[cfg(test)]
566mod tests {
567 use super::*;
568 use tokio::io::{AsyncReadExt, AsyncWriteExt};
569
570 use crate::aead::encrypt_chunk_standard;
571
572 #[test]
573 fn invalid_subkey_returns_error_instead_of_panicking() {
574 let (stream, _) = tokio::io::duplex(64);
575 let result = ShadowsocksAeadStream::new(stream, CipherMethod::Aes256Gcm, vec![0; 16]);
576 assert!(result.is_err());
577 }
578
579 #[tokio::test]
580 async fn roundtrip_small_data() {
581 let (client, server) = tokio::io::duplex(4096);
582 let method = CipherMethod::Aes256Gcm;
583 let subkey = vec![0x42u8; 32];
584
585 let mut client_stream = ShadowsocksAeadStream::new(client, method, subkey.clone()).unwrap();
586 let mut server_stream = ShadowsocksAeadStream::new(server, method, subkey).unwrap();
587
588 client_stream.write_all(b"hello").await.unwrap();
590 client_stream.flush().await.unwrap();
591
592 let mut buf = vec![0u8; 64];
594 let n = server_stream.read(&mut buf).await.unwrap();
595 assert_eq!(&buf[..n], b"hello");
596 }
597
598 #[tokio::test]
599 async fn roundtrip_large_data() {
600 let (client, server) = tokio::io::duplex(1 << 16);
601 let method = CipherMethod::ChaCha20IetfPoly1305;
602 let subkey = vec![0xABu8; 32];
603
604 let payload = vec![0xCDu8; 100_000];
605 let expected = payload.clone();
606 let write_subkey = subkey.clone();
607
608 let write_handle = tokio::spawn(async move {
609 let mut client_stream =
610 ShadowsocksAeadStream::new(client, method, write_subkey).unwrap();
611 client_stream.write_all(&payload).await.unwrap();
612 client_stream.flush().await.unwrap();
613 });
614
615 let mut server_stream = ShadowsocksAeadStream::new(server, method, subkey).unwrap();
616
617 let mut received = Vec::new();
618 server_stream.read_to_end(&mut received).await.unwrap();
619 write_handle.await.unwrap();
620 assert_eq!(received, expected);
621 }
622
623 #[tokio::test]
624 async fn bidirectional_communication() {
625 let (c1, s1) = tokio::io::duplex(4096);
626 let (c2, s2) = tokio::io::duplex(4096);
627 let method = CipherMethod::Aes128Gcm;
628 let subkey = vec![0x11u8; 16];
629
630 let mut client_a = ShadowsocksAeadStream::new(c1, method, subkey.clone()).unwrap();
631 let mut server_a = ShadowsocksAeadStream::new(s1, method, subkey.clone()).unwrap();
632 let mut client_b = ShadowsocksAeadStream::new(c2, method, subkey.clone()).unwrap();
633 let mut server_b = ShadowsocksAeadStream::new(s2, method, subkey).unwrap();
634
635 client_a.write_all(b"ping").await.unwrap();
637 client_a.flush().await.unwrap();
638
639 let mut buf = vec![0u8; 64];
640 let n = server_a.read(&mut buf).await.unwrap();
641 assert_eq!(&buf[..n], b"ping");
642
643 client_b.write_all(b"pong").await.unwrap();
644 client_b.flush().await.unwrap();
645
646 let n = server_b.read(&mut buf).await.unwrap();
647 assert_eq!(&buf[..n], b"pong");
648 }
649
650 #[tokio::test]
651 async fn empty_read_on_eof() {
652 let (client, server) = tokio::io::duplex(256);
653 let method = CipherMethod::Aes256Gcm;
654 let subkey = vec![0x55u8; 32];
655
656 let client_stream = ShadowsocksAeadStream::new(client, method, subkey.clone()).unwrap();
657 let mut server_stream = ShadowsocksAeadStream::new(server, method, subkey).unwrap();
658
659 drop(client_stream);
661
662 let mut buf = vec![0u8; 64];
663 let result = server_stream.read(&mut buf).await;
664 assert!(result.is_ok());
665 assert_eq!(result.unwrap(), 0); }
667
668 #[tokio::test]
669 async fn write_buffer_flushed_on_flush() {
670 let (client, server) = tokio::io::duplex(4096);
671 let method = CipherMethod::Aes256Gcm;
672 let subkey = vec![0x99u8; 32];
673
674 let mut client_stream = ShadowsocksAeadStream::new(client, method, subkey.clone()).unwrap();
675 let mut server_stream = ShadowsocksAeadStream::new(server, method, subkey).unwrap();
676
677 client_stream.write_all(b"data").await.unwrap();
678 client_stream.flush().await.unwrap();
679
680 let mut buf = vec![0u8; 64];
681 let n = server_stream.read(&mut buf).await.unwrap();
682 assert_eq!(&buf[..n], b"data");
683 }
684
685 #[tokio::test]
686 async fn multiple_chunks() {
687 let (client, server) = tokio::io::duplex(8192);
688 let method = CipherMethod::Aes256Gcm;
689 let subkey = vec![0x77u8; 32];
690
691 let mut client_stream = ShadowsocksAeadStream::new(client, method, subkey.clone()).unwrap();
692 let mut server_stream = ShadowsocksAeadStream::new(server, method, subkey).unwrap();
693
694 for i in 0..10 {
696 let msg = format!("msg-{i}");
697 client_stream.write_all(msg.as_bytes()).await.unwrap();
698 }
699 client_stream.flush().await.unwrap();
700 drop(client_stream);
701
702 let mut received = Vec::new();
703 server_stream.read_to_end(&mut received).await.unwrap();
704
705 let mut expected = Vec::new();
706 for i in 0..10 {
707 expected.extend_from_slice(format!("msg-{i}").as_bytes());
708 }
709 assert_eq!(received, expected);
710 }
711
712 #[tokio::test]
713 async fn into_inner_returns_original_stream() {
714 let (client, _server) = tokio::io::duplex(256);
715 let method = CipherMethod::Aes256Gcm;
716 let subkey = vec![0x01u8; 32];
717
718 let stream = ShadowsocksAeadStream::new(client, method, subkey).unwrap();
719 let _ = stream.into_inner();
720 }
721
722 #[tokio::test]
723 async fn zero_length_payload_signals_eof() {
724 let (client, server) = tokio::io::duplex(256);
725 let method = CipherMethod::Aes256Gcm;
726 let subkey = vec![0x33u8; 32];
727
728 let mut server_stream =
730 ShadowsocksAeadStream::new_with_nonces(server, method, subkey.clone(), 0, 0).unwrap();
731
732 let mut nonce = vec![0u8; method.nonce_size()];
735 nonce[0] = 0;
736 let wire = encrypt_chunk_standard(method, &subkey, &nonce, b"").unwrap();
737 let mut raw_stream = client;
738 raw_stream.write_all(&wire).await.unwrap();
739
740 let mut buf = vec![0u8; 64];
742 let result = server_stream.read(&mut buf).await;
743 assert!(result.is_ok());
744 assert_eq!(result.unwrap(), 0); raw_stream.write_all(b"ignored").await.unwrap();
749 let result = server_stream.read(&mut buf).await;
750 assert!(result.is_ok());
751 assert_eq!(result.unwrap(), 0);
752 }
753
754 #[tokio::test]
755 async fn tampered_length_block_fails() {
756 let (client, server) = tokio::io::duplex(256);
757 let method = CipherMethod::Aes256Gcm;
758 let subkey = vec![0x42u8; 32];
759
760 let mut server_stream = ShadowsocksAeadStream::new(server, method, subkey.clone()).unwrap();
761
762 let mut raw_stream = client;
764 let nonce1 = {
765 let mut n = vec![0u8; method.nonce_size()];
766 n[0] = 2; n
768 };
769 let len_bytes = (5u16).to_be_bytes();
770 let len_ct = crate::aead::aead_encrypt_raw(method, &subkey, &nonce1, &len_bytes).unwrap();
771 let mut tampered_len_ct = len_ct;
772 tampered_len_ct[0] ^= 0xFF;
773
774 raw_stream.write_all(&tampered_len_ct).await.unwrap();
776 let nonce2 = {
778 let mut n = vec![0u8; method.nonce_size()];
779 n[0] = 3; n
781 };
782 let payload_ct = crate::aead::aead_encrypt_raw(method, &subkey, &nonce2, b"hello").unwrap();
783 raw_stream.write_all(&payload_ct).await.unwrap();
784 drop(raw_stream);
785
786 let mut buf = vec![0u8; 64];
787 let result = tokio::time::timeout(
788 std::time::Duration::from_secs(2),
789 server_stream.read(&mut buf),
790 )
791 .await;
792
793 let result = result.expect("tampered length block must fail promptly");
794 let error = result.expect_err("tampered length block must not produce plaintext or EOF");
795 assert_eq!(error.kind(), std::io::ErrorKind::InvalidData);
796 }
797
798 #[test]
799 fn server_without_write_salt_is_rejected() {
800 let (_, server) = tokio::io::duplex(64);
801 let result = ShadowsocksAeadStream::new_server(
802 server,
803 CipherMethod::Aes256Gcm,
804 vec![0x42; 32],
805 false,
806 "password",
807 );
808 assert!(result.is_err());
809 }
810
811 #[tokio::test]
812 async fn tampered_payload_block_fails() {
813 let (client, server) = tokio::io::duplex(1024);
814 let method = CipherMethod::Aes256Gcm;
815 let subkey = vec![0x42u8; 32];
816
817 let mut server_stream = ShadowsocksAeadStream::new(server, method, subkey.clone()).unwrap();
818
819 let mut raw_stream = client;
821 let nonce1 = {
822 let mut n = vec![0u8; method.nonce_size()];
823 n[0] = 2; n
825 };
826 let len_bytes = (5u16).to_be_bytes();
827 let len_ct = crate::aead::aead_encrypt_raw(method, &subkey, &nonce1, &len_bytes).unwrap();
828 raw_stream.write_all(&len_ct).await.unwrap();
829
830 let nonce2 = {
832 let mut n = vec![0u8; method.nonce_size()];
833 n[0] = 3; n
835 };
836 let payload_ct = crate::aead::aead_encrypt_raw(method, &subkey, &nonce2, b"hello").unwrap();
837 let mut tampered_payload_ct = payload_ct;
838 tampered_payload_ct[0] ^= 0xFF;
839 raw_stream.write_all(&tampered_payload_ct).await.unwrap();
840 drop(raw_stream);
841
842 let mut buf = vec![0u8; 64];
843 let result = tokio::time::timeout(
844 std::time::Duration::from_secs(2),
845 server_stream.read(&mut buf),
846 )
847 .await;
848
849 let result = result.expect("tampered payload block must fail promptly");
850 let error = result.expect_err("tampered payload block must not produce plaintext or EOF");
851 assert_eq!(error.kind(), std::io::ErrorKind::InvalidData);
852 }
853
854 #[tokio::test]
855 async fn tampered_payload_fails() {
856 use crate::aead::aead_encrypt_raw;
857
858 let method = CipherMethod::Aes256Gcm;
859 let subkey = vec![0x42u8; 32];
860 let plaintext = b"hello world";
861
862 let nonce = vec![0u8; method.nonce_size()];
863 let ciphertext = aead_encrypt_raw(method, &subkey, &nonce, plaintext).unwrap();
864
865 let mut tampered = ciphertext.clone();
866 tampered[0] ^= 0x01;
867
868 let result = crate::aead::aead_decrypt_raw(method, &subkey, &nonce, &tampered);
869 assert!(
870 result.is_err(),
871 "decryption of tampered ciphertext should fail"
872 );
873 }
874
875 #[tokio::test]
876 async fn wrong_key_fails() {
877 use crate::aead::aead_encrypt_raw;
878
879 let method = CipherMethod::Aes256Gcm;
880 let correct_key = vec![0x42u8; 32];
881 let wrong_key = vec![0x99u8; 32];
882 let plaintext = b"secret data";
883
884 let nonce = vec![0u8; method.nonce_size()];
885 let ciphertext = aead_encrypt_raw(method, &correct_key, &nonce, plaintext).unwrap();
886
887 let result = crate::aead::aead_decrypt_raw(method, &wrong_key, &nonce, &ciphertext);
888 assert!(result.is_err(), "decryption with wrong key should fail");
889
890 let result = crate::aead::aead_decrypt_raw(method, &correct_key, &nonce, &ciphertext);
891 assert!(result.is_ok(), "decryption with correct key should succeed");
892 assert_eq!(result.unwrap(), plaintext);
893 }
894
895 #[tokio::test]
896 async fn standard_chunk_format_roundtrip() {
897 let (client, server) = tokio::io::duplex(4096);
898 let method = CipherMethod::Aes256Gcm;
899 let subkey = vec![0x55u8; 32];
900
901 let mut client_stream = ShadowsocksAeadStream::new(client, method, subkey.clone()).unwrap();
902 let mut server_stream = ShadowsocksAeadStream::new(server, method, subkey).unwrap();
903
904 let data = b"standard SIP003 framing test";
905 client_stream.write_all(data).await.unwrap();
906 client_stream.flush().await.unwrap();
907
908 let mut buf = vec![0u8; 64];
909 let n = server_stream.read(&mut buf).await.unwrap();
910 assert_eq!(&buf[..n], data.as_slice());
911 }
912
913 #[tokio::test]
914 async fn empty_plaintext_roundtrip() {
915 let (client, server) = tokio::io::duplex(256);
916 let method = CipherMethod::Aes128Gcm;
917 let subkey = vec![0x88u8; 16];
918
919 let mut client_stream = ShadowsocksAeadStream::new(client, method, subkey.clone()).unwrap();
920 let mut server_stream = ShadowsocksAeadStream::new(server, method, subkey).unwrap();
921
922 client_stream.write_all(b"").await.unwrap();
924 client_stream.flush().await.unwrap();
925 drop(client_stream);
926
927 let mut buf = vec![0u8; 64];
928 let result = server_stream.read(&mut buf).await;
929 assert!(result.is_ok());
930 assert_eq!(result.unwrap(), 0); }
932
933 #[tokio::test]
934 async fn large_chunk_split_across_reads() {
935 let (client, server) = tokio::io::duplex(1 << 18);
936 let method = CipherMethod::Aes256Gcm;
937 let subkey = vec![0xBBu8; 32];
938
939 let payload = vec![0x44u8; 50_000];
940 let expected = payload.clone();
941 let write_subkey = subkey.clone();
942
943 let write_handle = tokio::spawn(async move {
944 let mut client_stream =
945 ShadowsocksAeadStream::new(client, method, write_subkey).unwrap();
946 client_stream.write_all(&payload).await.unwrap();
947 client_stream.flush().await.unwrap();
948 drop(client_stream);
949 });
950
951 let mut server_stream = ShadowsocksAeadStream::new(server, method, subkey).unwrap();
952
953 let mut received = Vec::new();
955 let mut tmp = [0u8; 1024];
956 loop {
957 let n = server_stream.read(&mut tmp).await.unwrap();
958 if n == 0 {
959 break;
960 }
961 received.extend_from_slice(&tmp[..n]);
962 }
963 write_handle.await.unwrap();
964 assert_eq!(received, expected);
965 }
966}