diff --git a/crates/obfs4/Cargo.toml b/crates/obfs4/Cargo.toml index e6e98e8..853e3eb 100644 --- a/crates/obfs4/Cargo.toml +++ b/crates/obfs4/Cargo.toml @@ -42,6 +42,8 @@ hex = "0.4.3" tracing = "0.1.40" colored = "2.0.4" base64 = "0.22.0" +serde_json = "1.0.114" +serde = "1.0.197" ## Networking tools pin-project = "1.1.3" diff --git a/crates/obfs4/src/bin/fwd/main.rs b/crates/obfs4/src/bin/fwd/main.rs index 6a8e033..3251575 100644 --- a/crates/obfs4/src/bin/fwd/main.rs +++ b/crates/obfs4/src/bin/fwd/main.rs @@ -306,7 +306,7 @@ where // connection and handshake when the `wrap(..)` is await-ed. let args = ptrs::args::Args::parse_client_parameters(obfs4::dev::CLIENT_ARGS)?; - debug!("client building {:?}", args); + debug!("client building with {:?}", args); let mut b = builder .options(&args) .context("failed setting builder opts")?; @@ -446,7 +446,6 @@ where } Ok(c) => c, }; - println!("HEREHRERHARWFANREWLAKNR"); debug!("accepted new connection -> {}:{}", sensitive(client_addr.ip()), client_addr.port()); if echo { tokio::spawn(warn_fut(client_addr, server_echo_connection( diff --git a/crates/obfs4/src/lib.rs b/crates/obfs4/src/lib.rs index 83f73fc..665e49c 100644 --- a/crates/obfs4/src/lib.rs +++ b/crates/obfs4/src/lib.rs @@ -23,7 +23,7 @@ pub(crate) mod test_utils; #[cfg(debug_assertions)] pub mod dev { - use super::common::curve25519::{PublicKey, StaticSecret}; + use super::common::curve25519::StaticSecret; use super::obfs4::constants::*; use super::obfs4::handshake::Obfs4NtorSecretKey; use ptrs::args::Args; @@ -33,13 +33,11 @@ pub mod dev { const DEV_PRIV_KEY: &[u8; 32] = b"0123456789abcdeffedcba9876543210"; pub const CLIENT_ARGS: &str = - "cert=AAAAAAAAAAAAAAAAAAAAAAAAAADTSFvsGKxNFPBcGdOCBSgpEtJInG9zCYZezBPVBuBWag,iat-mode=0"; + "cert=AAAAAAAAAAAAAAAAAAAAAAAAAADTSFvsGKxNFPBcGdOCBSgpEtJInG9zCYZezBPVBuBWag;iat-mode=0"; pub const SERVER_ARGS: &str = ""; pub fn print_dev_args() { let static_secret = StaticSecret::from(*DEV_PRIV_KEY); - let pk = PublicKey::from(&static_secret); - let sk = - Obfs4NtorSecretKey::new(static_secret, pk, RsaIdentity::from([0u8; NODE_ID_LENGTH])); + let sk = Obfs4NtorSecretKey::new(static_secret, RsaIdentity::from([0u8; NODE_ID_LENGTH])); let mut client_args = Args::new(); client_args.insert(CERT_ARG.into(), vec![sk.pk.to_string()]); client_args.insert(IAT_ARG.into(), vec!["0".into()]); @@ -52,7 +50,6 @@ pub mod dev { use tokio::net::TcpStream; let args = Args::parse_client_parameters(CLIENT_ARGS).unwrap(); - println!("client args: {args:?}"); let mut builder = ClientBuilder::default(); >::options(&mut builder, &args) .unwrap(); diff --git a/crates/obfs4/src/obfs4/handshake/mod.rs b/crates/obfs4/src/obfs4/handshake/mod.rs index 6d706d7..4f595da 100644 --- a/crates/obfs4/src/obfs4/handshake/mod.rs +++ b/crates/obfs4/src/obfs4/handshake/mod.rs @@ -20,7 +20,10 @@ use crate::{ use std::borrow::Borrow; -use base64::{engine::general_purpose::STANDARD_NO_PAD, Engine as _}; +use base64::{ + engine::general_purpose::{STANDARD, STANDARD_NO_PAD}, + Engine as _, +}; use bytes::BytesMut; use digest::Mac; use hmac::Hmac; @@ -142,7 +145,7 @@ impl std::str::FromStr for Obfs4NtorPublicKey { fn from_str(s: &str) -> std::prelude::v1::Result { let mut cert = String::from(s); cert.push_str(Self::CERT_SUFFIX); - let decoded = STANDARD_NO_PAD + let decoded = STANDARD .decode(cert.as_bytes()) .map_err(|e| format!("failed to decode cert: {e}"))?; if decoded.len() != Self::CERT_LENGTH { @@ -175,7 +178,8 @@ pub(crate) struct Obfs4NtorSecretKey { impl Obfs4NtorSecretKey { /// Construct a new Obfs4NtorSecretKey from its components. #[allow(unused)] - pub(crate) fn new(sk: StaticSecret, pk: PublicKey, id: RsaIdentity) -> Self { + pub(crate) fn new(sk: StaticSecret, id: RsaIdentity) -> Self { + let pk = PublicKey::from(&sk); Self { pk: Obfs4NtorPublicKey { id, pk }, sk, @@ -185,10 +189,9 @@ impl Obfs4NtorSecretKey { /// Construct a new ['Obfs4NtorSecretKey'] from a CSPRNG. pub(crate) fn getrandom() -> Self { let sk = Representable::random_static(); - let pk: PublicKey = (&sk).into(); let mut id = [0_u8; NODE_ID_LENGTH]; getrandom::getrandom(&mut id).expect("internal randomness error"); - Self::new(sk, pk, RsaIdentity::from(id)) + Self::new(sk, RsaIdentity::from(id)) } /// Generate a key using the given `rng`, suitable for testing. diff --git a/crates/obfs4/src/obfs4/server.rs b/crates/obfs4/src/obfs4/server.rs index c54a454..4c1861a 100644 --- a/crates/obfs4/src/obfs4/server.rs +++ b/crates/obfs4/src/obfs4/server.rs @@ -4,8 +4,7 @@ use super::*; use crate::{ common::{ colorize, - curve25519::PublicKey, - curve25519::StaticSecret, + curve25519::{PublicKey, StaticSecret}, drbg, replay_filter::{self, ReplayFilter}, HmacSha256, @@ -22,15 +21,17 @@ use crate::{ Error, Result, }; -use std::{borrow::BorrowMut, ops::Deref, sync::Arc}; +use std::{borrow::BorrowMut, ops::Deref, str::FromStr, sync::Arc}; use bytes::{Buf, BufMut, Bytes}; +use hex::FromHex; use hmac::{Hmac, Mac}; use rand::prelude::*; use subtle::ConstantTimeEq; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; use tokio::time::{Duration, Instant}; use tokio_util::codec::Encoder; +use tor_llcrypto::pk::rsa::RsaIdentity; use tracing::{debug, info}; pub struct ServerBuilder { @@ -137,6 +138,34 @@ impl ServerBuilder { replay_filter: ReplayFilter::new(REPLAY_TTL), })) } + + pub fn parse_args_json(arg_str: impl AsRef) -> Result { + let state: ServerState = + serde_json::from_str(arg_str.as_ref()).map_err(|e| Error::Other(Box::new(e)))?; + + let node_id = <[u8; NODE_ID_LENGTH]>::from_hex(state.node_id)?; + let seed = drbg::Seed::from_hex(state.drbg_seed)?; + let sk = <[u8; KEY_LENGTH]>::from_hex(state.private_key)?; + let secret_key = StaticSecret::from(sk); + let obf4_ntsk = Obfs4NtorSecretKey::new(secret_key, RsaIdentity::from(node_id)); + + let iat_mode = match state.iat_mode { + Some(s) => IAT::from_str(&s)?, + None => IAT::default(), + }; + + let args = ptrs::args::Args::new(); + Ok(args) + } +} + +#[derive(serde::Serialize, serde::Deserialize)] +struct ServerState { + node_id: String, + private_key: String, + public_key: String, + drbg_seed: String, + iat_mode: Option, } #[derive(Clone)] diff --git a/crates/obfs4/src/pt.rs b/crates/obfs4/src/pt.rs index 776b965..f1b3e8f 100644 --- a/crates/obfs4/src/pt.rs +++ b/crates/obfs4/src/pt.rs @@ -22,6 +22,7 @@ use tokio::{ io::{AsyncRead, AsyncWrite}, net::TcpStream, }; +use tracing::trace; pub type Obfs4PT = Transport; @@ -128,6 +129,7 @@ where if cert_strs.is_empty() { return Err(format!("missing argument '{NODE_ID_ARG}'").into()); } + trace!("cert string: {}", &cert_strs[0]); let ntor_pk = Obfs4NtorPublicKey::from_str(&cert_strs[0])?; let pk: [u8; NODE_PUBKEY_LENGTH] = *ntor_pk.pk.as_bytes(); let id: [u8; NODE_ID_LENGTH] = ntor_pk.id.as_bytes().try_into().unwrap();