use crate::common::drbg;
use bytes::{Buf, BufMut};
mod messages_base;
pub use messages_base::*;
mod messages_v1;
pub use messages_v1::{MessageTypes, Messages};
mod codecs;
pub use codecs::EncryptingCodec as Obfs4Codec;
pub(crate) mod handshake;
pub use handshake::*;
pub(crate) const MAX_SEGMENT_LENGTH: usize = 1500 - (40 + 12);
const SECRET_BOX_OVERHEAD: usize = TAG_SIZE;
pub(crate) const FRAME_OVERHEAD: usize = LENGTH_LENGTH + SECRET_BOX_OVERHEAD;
pub(crate) const MAX_FRAME_PAYLOAD_LENGTH: usize = MAX_SEGMENT_LENGTH - FRAME_OVERHEAD;
pub(crate) const NONCE_PREFIX_LENGTH: usize = 16;
pub(crate) const LENGTH_LENGTH: usize = 2;
pub(crate) const KEY_LENGTH: usize = 32;
pub(crate) const TAG_SIZE: usize = 16;
pub(crate) const KEY_MATERIAL_LENGTH: usize = KEY_LENGTH + NONCE_PREFIX_LENGTH + drbg::SEED_LENGTH;
pub trait Marshall {
fn marshall(&mut self, buf: &mut impl BufMut) -> Result<(), FrameError>;
}
pub trait TryParse {
type Output;
fn try_parse(&mut self, buf: &mut impl Buf) -> Result<Self::Output, FrameError>
where
Self: Sized;
}
impl std::error::Error for FrameError {}
#[derive(Debug, PartialEq, Eq)]
pub enum FrameError {
InvalidPayloadLength(usize),
Crypto(crypto_secretbox::Error),
IO(String),
EAgain,
TagMismatch,
NonceCounterWrapped,
ShortBuffer,
InvalidMessage,
InvalidHandshake,
ReplayedHandshake,
UnknownMessageType(u8),
}
impl std::fmt::Display for FrameError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
FrameError::InvalidPayloadLength(s) => {
write!(f, "framing: Invalid payload length: {s}")
}
FrameError::Crypto(e) => write!(f, "framing: Secretbox encrypt/decrypt error: {e}"),
FrameError::IO(e) => {
write!(f, "framing: i/o error occured while processing frame: {e}")
}
FrameError::EAgain => write!(f, "framing: more data needed to decode"),
FrameError::TagMismatch => write!(f, "framing: Poly1305 tag mismatch"),
FrameError::NonceCounterWrapped => write!(f, "framing: Nonce counter wrapped"),
FrameError::ShortBuffer => write!(
f,
"framing: provided bytes buffer was too short for payload"
),
FrameError::InvalidMessage => write!(f, "framing: incorrect message for context"),
FrameError::InvalidHandshake => write!(f, "framing: failed to parse handshake message"),
FrameError::ReplayedHandshake => write!(f, "framing: handshake replayed within TTL"),
FrameError::UnknownMessageType(pt) => write!(f, "framing: unknown packet type ({pt})"),
}
}
}
impl From<crypto_secretbox::Error> for FrameError {
fn from(value: crypto_secretbox::Error) -> Self {
FrameError::Crypto(value)
}
}
impl From<std::io::Error> for FrameError {
fn from(value: std::io::Error) -> Self {
FrameError::IO(value.to_string())
}
}
impl From<FrameError> for std::io::Error {
fn from(value: FrameError) -> Self {
std::io::Error::new(std::io::ErrorKind::Other, format!("{}", value))
}
}
#[cfg(test)]
mod generic_test;
#[cfg(test)]
mod testing;