1use std::{convert::TryInto, time::Duration};
2
3use async_dup::Arc;
4
5use c2_chacha::{stream_cipher::NewStreamCipher, stream_cipher::SyncStreamCipher, ChaCha8};
6
7use parking_lot::Mutex;
8
9use smol::io::BufReader;
10use smol::prelude::*;
11
12mod client;
13mod tls_helpers;
14pub use client::*;
15mod server;
16pub use server::*;
17
18use crate::{buffer::Buff, crypt::NgAead};
19
20const CONN_LIFETIME: Duration = Duration::from_secs(600);
21
22const TCP_UP_KEY: &[u8; 32] = b"uploadtcp-----------------------";
23const TCP_DN_KEY: &[u8; 32] = b"downloadtcp---------------------";
24
25type DynAsyncWrite = Box<dyn AsyncWrite + Unpin + Send + Sync + 'static>;
26type DynAsyncRead = Box<dyn AsyncRead + Unpin + Send + Sync + 'static>;
27
28#[derive(Clone)]
30struct ObfsTcp {
31 write: async_dup::Arc<async_dup::Mutex<DynAsyncWrite>>,
32 read: async_dup::Arc<async_dup::Mutex<BufReader<DynAsyncRead>>>,
33 send_chacha: Arc<Mutex<ChaCha8>>,
34 recv_chacha: Arc<Mutex<ChaCha8>>,
35}
36
37impl ObfsTcp {
38 fn new(ss: blake3::Hash, is_server: bool, write: DynAsyncWrite, read: DynAsyncRead) -> Self {
40 let up_chacha = Arc::new(Mutex::new(
41 ChaCha8::new_var(
42 blake3::keyed_hash(TCP_UP_KEY, ss.as_bytes()).as_bytes(),
43 &[0; 8],
44 )
45 .unwrap(),
46 ));
47 let dn_chacha = Arc::new(Mutex::new(
48 ChaCha8::new_var(
49 blake3::keyed_hash(TCP_DN_KEY, ss.as_bytes()).as_bytes(),
50 &[0; 8],
51 )
52 .unwrap(),
53 ));
54 let buf_read =
55 async_dup::Arc::new(async_dup::Mutex::new(BufReader::with_capacity(4096, read)));
56 if is_server {
57 Self {
58 write: async_dup::Arc::new(async_dup::Mutex::new(write)),
59 read: buf_read,
60 send_chacha: dn_chacha,
61 recv_chacha: up_chacha,
62 }
63 } else {
64 Self {
65 write: async_dup::Arc::new(async_dup::Mutex::new(write)),
66 read: buf_read,
67 send_chacha: up_chacha,
68 recv_chacha: dn_chacha,
69 }
70 }
71 }
72
73 async fn write(&self, msg: &[u8]) -> std::io::Result<()> {
74 assert!(msg.len() <= 2048);
75 let mut buf = [0u8; 2048];
76 let buf = &mut buf[..msg.len()];
77 buf.copy_from_slice(msg);
78 self.send_chacha.lock().apply_keystream(buf);
79 let mut inner = self.write.clone();
80 inner.write_all(buf).await?;
81 inner.flush().await?;
82 Ok(())
83 }
84
85 async fn read_exact(&self, buf: &mut [u8]) -> std::io::Result<()> {
86 self.read.lock().read_exact(buf).await?;
87 self.recv_chacha.lock().apply_keystream(buf);
88 Ok(())
89 }
90}
91
92async fn read_encrypted<R: AsyncRead + Unpin>(
93 decrypt: NgAead,
94 rdr: &mut R,
95) -> anyhow::Result<Buff> {
96 let mut length_buf = vec![0u8; NgAead::overhead() + 2];
98 rdr.read_exact(&mut length_buf).await?;
99 let length_buf = decrypt.decrypt(&length_buf)?;
101 if length_buf.len() != 2 {
102 anyhow::bail!("length must be 16 bits");
103 }
104 let length_buf = &length_buf[..];
105 let mut actual_buf = vec![0u8; u16::from_be_bytes(length_buf.try_into().unwrap()) as usize];
107 rdr.read_exact(&mut actual_buf).await?;
108 Ok(decrypt.decrypt(&actual_buf)?)
109}
110
111async fn write_encrypted<W: AsyncWrite + Unpin>(
112 encrypt: NgAead,
113 to_send: &[u8],
114 writer: &mut W,
115) -> anyhow::Result<()> {
116 let to_send = encrypt.encrypt(to_send);
117 let raw_length = (to_send.len() as u16).to_be_bytes();
118 writer.write_all(&encrypt.encrypt(&raw_length)).await?;
119 writer.write_all(&to_send).await?;
120 Ok(())
121}