Compare commits

..

No commits in common. 'master' and 'no-dual' have entirely different histories.

@ -12,5 +12,4 @@ chacha20stream = {version = "1.0", features=["async"]}
openssl = "0.10.33"
stackalloc = "1.1.0"
pin-project = "1.0.6"
bytes = "0.5.6"
log = {version = "0.4.14", optional=true}
bytes = "0.5.6"

@ -1,27 +1,7 @@
use super::*;
use std::io::{
self,
Write,
};
/// TODO: RSA private key
pub type RsaPrivateKey = ();
/// TODO: RSA public key
pub type RsaPublicKey = ();
pub(crate) fn rsa_encrypt<W: io::Write>(with: &RsaPublicKey, to: &mut W, buf: &[u8]) -> io::Result<usize>
{
todo!()
}
pub(crate) fn generate() -> RsaPrivateKey
{
todo!()
}
pub use chacha20stream::{
Key,
IV,
keygen as chacha_keygen,
};

@ -202,66 +202,6 @@ where F: FnOnce(&mut [u8]) -> T
}
#[macro_export] macro_rules! lazy_format {
($msg:literal $($tt:tt)*) => {
{
use ::std::fmt::{self, Write, Formatter};
use ::std::sync::Mutex;
use ::std::io;
let pfn = move |fmt| {
write!(fmt, $msg $($tt)*)?;
let mut sfmt = String::new();
write!(&mut sfmt, $msg $($tt)*)?;
Ok(sfmt)
};
enum LazyFormatInner<F>
{
//todo: redo this entire thing
Pending(F),
Complete(String),
Error(fmt::Error),
Panicked,
}
struct LazyFormat<F>(Mutex<LazyFormatInner<F>>);
impl<F: FnOnce(&mut fmt::Formatter<'_>) -> io::Result<String>> fmt::Display for LazyFormat<F>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
//todo: redo this entire thing
/*
let mut inner = self.0.lock().unwrap();
let this = std::mem::replace(inner, LazyFormatInner::Panicked);
//TODO: impl fmt::Write wrapper that multi-writes to 2 outputs
let string = match this {
LazyFormatInner::Pending(func) => func(f),
LazyFormatInner::Complete(string) => write!(f, "{}", string).map(move |_| string),
LazyFormatInner::Error(err) => return Err(err),
LazyFormatInner::Panicked => panic!(),
};
match string {
Err(err) => {
*inner = LazyFormatInner::Error(err),
},
}*/
}
}
}
}
}
#[cfg(not(feature="log"))] #[macro_export] macro_rules! trace {
($fmt:literal $($tt:tt)*) => {
{
((), $($tt)*);
}
}
}
pub mod bytes
{
use super::*;
@ -276,4 +216,3 @@ pub mod bytes
mod slice;
pub use slice::*;

@ -2,15 +2,17 @@
#![allow(dead_code)]
#[macro_use] extern crate pin_project;
#[cfg(feature="log")] #[macro_use] extern crate log;
// Extensions & macros
#[macro_use] mod ext;
#[allow(unused_imports)] use ext::*;
pub mod dual;
// Wrapper for plain/symm-enc stream swapping
// RSA crypto shit
// TODO: We're getting rid of this and swithcing to a different model.
//mod dual;
// Crypto shit
mod crypt;
// Stream impls
mod stream;
@ -18,12 +20,7 @@ mod stream;
pub use stream::{
AsyncStream,
Stream,
// EncryptedStream,
// EncryptedStream,
WriteHalf,
EncryptedWriteHalf,
ReadHalf,
EncryptedReadHalf,
};

@ -18,190 +18,9 @@ use crypt::{
RsaPrivateKey,
};
mod traits;
pub use traits::*;
mod exchange;
/// Combined Read + Write encryptable async stream.
///
/// The `AsyncRead` and `AsyncWrite` impls of this type forward to the backing impls for `S`.
///
/// # Exchange
/// A combined stream is the only way to exchange pubkeys and enabling the creation of encrypted read/write wrappers on the combined stream or splits.
#[pin_project]
#[derive(Debug)]
pub struct Stream<S>
{
meta: EncryptedStreamMeta,
#[pin] stream: S,
}
/// `Stream` with enabled encryption.
pub struct EncryptedStream<'a, S>
{
read_cipher: Crypter,
write_cipher: Crypter,
write_crypt_buf_ptr: SliceMeta<u8>,
write_crypt_buffer: Vec<u8>,
backing: &'a mut Stream<S>,
}
impl<Tx, Rx> Stream<Merge<Tx, Rx>>
where Tx: AsyncWrite,
Rx: AsyncRead
{
/// Exchange RSA keys through this stream.
pub async fn exchange(&mut self) -> io::Result<()>
{
todo!()
}
/// Merge an `AsyncWrite`, and `AsyncRead` stream into `Stream`.
pub fn merged(tx: Tx, rx: Rx) -> Self
{
Self {
meta: EncryptedStreamMeta::new(),
stream: Merge(tx, rx),
}
}
}
/*
impl<S> Stream<S>
where S: Split,
S::First: AsyncWrite,
S::Second: AsyncRead
{
/// Create a new `Stream` from two streams, one implemetor of `AsyncWrite`, and one of `AsyncRead`.
pub fn new(tx: S::First, rx: S::Second) -> Self
{
Self {
meta: EncryptedStreamMeta {
them: None,
us: crypt::generate(),
},
stream: S::unsplit(tx, rx),
}
}
}
impl<S: AsyncStream> Stream<S>
{
/// Create a new `Stream` from an implementor of both `AsyncRead` and `AsyncWrite`.
pub fn new_single(stream: S) -> Self
{
Self {
meta: EncryptedStreamMeta {
them: None,
us: crypt::generate(),
},
stream,
}
}
/// Create a split by cloning `S`.
pub fn split_clone(self) -> (WriteHalf<S>, ReadHalf<S>)
where S: Clone
{
Stream {
stream: (self.stream.clone(), self.stream),
meta: self.meta
}.split()
}
}*/
impl<S> Split for Stream<S>
where S: Split,
S::First: AsyncWrite,
S::Second: AsyncRead
{
type First = WriteHalf<S::First>;
type Second = ReadHalf<S::Second>;
#[inline] fn split(self) -> (Self::First, Self::Second) {
self.split()
}
#[inline] fn unsplit(a: Self::First, b: Self::Second) -> Self {
Self::unsplit(a, b)
}
}
impl<S> Stream<S>
where S: Split,
S::First: AsyncWrite,
S::Second: AsyncRead
{
/// Combine a previously split `EncryptedStream`'s halves back into a single type.
///
/// # Panics
/// If the two halves didn't originally come from the same `EncryptedStream`.
pub fn unsplit(tx: WriteHalf<S::First>, rx: ReadHalf<S::Second>) -> Self
{
#[inline(never)] fn panic_not_ptr_eq() -> !
{
panic!("Cannot join halves from different splits")
}
if !Arc::ptr_eq(&tx.meta, &rx.meta) {
panic_not_ptr_eq();
}
let WriteHalf { meta: _meta, backing_write: tx } = tx;
drop(_meta);
let ReadHalf { meta, backing_read: rx } = rx;
let meta = Arc::try_unwrap(meta).unwrap();
Self {
meta,
stream: S::unsplit(tx, rx),
}
}
/// Split this `EncryptedStream` into a read and a write half.
pub fn split(self) -> (WriteHalf<S::First>, ReadHalf<S::Second>)
{
let meta = Arc::new(self.meta);
let (tx, rx) = self.stream.split();
(WriteHalf {
meta: meta.clone(),
backing_write: tx,
}, ReadHalf {
meta,
backing_read: rx,
})
}
}
impl<S: AsyncRead> AsyncRead for Stream<S>
{
#[inline] fn poll_read(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
self.project().stream.poll_read(cx, buf)
}
#[inline] fn poll_read_buf<B: BufMut>(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut B) -> Poll<io::Result<usize>>
where
Self: Sized, {
self.project().stream.poll_read_buf(cx, buf)
}
}
impl<S: AsyncWrite> AsyncWrite for Stream<S>
{
#[inline] fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize, io::Error>> {
self.project().stream.poll_write(cx, buf)
}
#[inline] fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
self.project().stream.poll_flush(cx)
}
#[inline] fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
self.project().stream.poll_shutdown(cx)
}
#[inline] fn poll_write_buf<B: Buf>(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut B) -> Poll<Result<usize, io::Error>>
where
Self: Sized, {
self.project().stream.poll_write_buf(cx, buf)
}
}
/// A type that implements both `AsyncWrite` and `AsyncRead`
pub trait AsyncStream: AsyncRead + AsyncWrite{}
impl<T: AsyncRead + AsyncWrite + ?Sized> AsyncStream for T{}
/// Inner rsa data for encrypted stream read+write halves
///
@ -211,28 +30,14 @@ impl<S: AsyncWrite> AsyncWrite for Stream<S>
/// Therefore exchange should happen before the original stream is split at all.
///
/// Only the combined stream can mutate this structure. The halves hold it behind an immutable shared reference.
#[derive(Debug)]
struct EncryptedStreamMeta
{
us: RsaPrivateKey,
them: Option<RsaPublicKey>,
}
impl EncryptedStreamMeta
{
/// Create a new meta with a newly generated private key.
#[inline(always)] pub fn new() -> Self
{
Self {
them: None,
us: crypt::generate(),
}
}
}
/// Writable half of `EncryptedStream`.
#[pin_project]
#[derive(Debug)]
pub struct WriteHalf<S>
where S: AsyncWrite
{
@ -355,7 +160,6 @@ impl<'a, S: AsyncWrite> AsyncWrite for EncryptedWriteHalf<'a, S>
/// Readable half of `EncryptedStream`.
#[pin_project]
#[derive(Debug)]
pub struct ReadHalf<S>
where S: AsyncRead
{
@ -428,3 +232,114 @@ impl<S: AsyncWrite> AsyncWrite for WriteHalf<S>
self.project().backing_write.poll_write_buf(cx, buf)
}
}
//TODO: Rework everything past this point:
/*
struct ReadWriteCombined<R, W>
{
/// Since chacha20stream has no AsyncRead counterpart, we have to do it ourselves.
cipher_read: Option<Crypter>,
backing_read: R,
backing_write: dual::DualStream<W>,
}
/// RSA/chacha20 encrypted stream
pub struct EncryptedStream<R, W>
where R: AsyncRead,
W: AsyncWrite,
{
meta: EncryptedStreamMeta,
// Keep the streams on the heap to keep this type not hueg.
backing: Box<ReadWriteCombined<R, W>>,
}
//TODO: How do we use this with a single AsyncStream instead of requiring 2? Will we need to make our own Arc wrapper?? Ugh,, for now let's ignore this I guess... Most read+write thingies have a Read/WriteHalf split mechanism.
//
// Note that this does actually work fine with things like tokio's `duplex()` (i think)
impl<R: AsyncRead, W: AsyncWrite> EncryptedStream<R, W>
{
/// Has this stream done its RSA key exchange?
pub fn has_exchanged(&self) -> bool
{
self.meta.them.is_some()
}
/// Split this stream into a read and writeable half.
pub fn split(self) -> (WriteHalf<W>, ReadHalf<R>)
{
let meta = Arc::new(self.meta);
let (read, write) = {
let ReadWriteCombined { cipher_read, backing_read, backing_write } = *self.backing;
((cipher_read, backing_read), backing_write)
};
(WriteHalf {
meta: Arc::clone(&meta),
backing_write: Box::new(write),
}, ReadHalf {
meta,
cipher: read.0,
backing_read: Box::new(read.1),
})
}
/// Join a split `EncryptedStream` from halves.
///
/// # Panics
/// If the read and write half are not from the same split.
pub fn from_split((write, read): (WriteHalf<W>, ReadHalf<R>)) -> Self
{
if !Arc::ptr_eq(&write.meta, &read.meta) {
panic!("Read and Write halves are not from the same split");
}
todo!("Drop write's `meta`, consume read's `meta`. Move the streams into `ReadWriteCombined`")
}
}
/*
impl<S: AsyncWrite> AsyncWrite for WriteHalf<S>
{
#[inline] fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize, io::Error>> {
unsafe {self.map_unchecked_mut(|this| this.backing_write.as_mut())}.poll_write(cx, buf)
}
#[inline] fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
unsafe {self.map_unchecked_mut(|this| this.backing_write.as_mut())}.poll_flush(cx)
}
#[inline] fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
unsafe {self.map_unchecked_mut(|this| this.backing_write.as_mut())}.poll_shutdown(cx)
}
}
impl<S: AsyncRead> AsyncRead for ReadHalf<S>
{
fn poll_read(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
let this = self.project();
let cipher = this.cipher.as_mut();
let stream = unsafe {this.backing_read.map_unchecked_mut(|f| f.as_mut())};
let res = stream.poll_read(cx,buf);
if let Some(cipher) = cipher {
// Decrypt the buffer if the read succeeded
res.map(move |res| res.and_then(move |sz| {
alloca_limit(sz, move |obuf| -> io::Result<usize> {
// This `sz` and old `sz` should always be the same.
let sz = cipher.update(&buf[..sz], &mut obuf[..])?;
let _f = cipher.finalize(&mut obuf[..sz])?;
debug_assert_eq!(_f, 0);
// Copy decrypted buffer into output buffer
buf.copy_from_slice(&obuf[..sz]);
Ok(sz)
})
}))
} else {
res
}
}
}
*/
*/

@ -1,40 +0,0 @@
//! RSA and chacha20 key exchange methods
use super::*;
/*
use tokio::prelude::*;
pub async fn write_cckey<W: AsyncWrite + Unpin>(mut to: W, rsa: &crypt::RsaPublicKey, key: &crypt::Key, iv: &crypt::IV) -> std::io::Result<()>
{
let key = {
let mut buf = Vec::with_capacity(chacha20stream::key::KEY_SIZE);
crypt::rsa_encrypt(rsa, &mut buf, key.as_ref())?;
buf
};
to.write_all(&key[..]).await?; //TODO: Find size of `key` here.
to.write_all(iv.as_ref()).await?;
Ok(())
}
*/
/// A future that writes an RSA encrypted chacha20 key to a stream when awaited
//TODO: Find size of RSA ecnrypted chacha `Key`.
#[pin_project]
struct CCKeyWrite<'a, W: AsyncWrite>{
/// The bytes of an **already encrypted** chacha20 key.
enc_key: Vec<u8>,
/// A non-encrypted chacha20 IV.
iv: [u8; chacha20stream::key::IV_SIZE],
/// Stream to write the data to when this future is awaited.
#[pin] stream: &'a mut W,
}
//TODO: impl `Future` for CCKeyWrite should `write_all` both `enc_key` and `iv` to `stream` when `.await`ed.
impl<'a, W: AsyncWrite> Future for CCKeyWrite<'a, S>
{
type Output = io::Result<()>;
//todo: how to we `write_all` in `poll`? implement it outselves with looping `poll_write` and `futures::ready!()`?
}

@ -1,153 +0,0 @@
//! Stream traits
use super::*;
/// A type that implements both `AsyncWrite` and `AsyncRead`
pub trait AsyncStream: AsyncRead + AsyncWrite{}
impl<T: AsyncRead + AsyncWrite + ?Sized> AsyncStream for T{}
/// A type that can split itself into other types, and combine back from those types.
pub trait Split: Sized
{
/// First half of the split
type First;
/// Second half of the split
type Second;
fn split(self) -> (Self::First, Self::Second);
fn unsplit(a: Self::First, b: Self::Second) -> Self;
#[inline(always)] fn split_reverse(self) -> (Self::Second, Self::First)
{
let (tx, rx) = self.split();
(rx, tx)
}
#[inline(always)] fn unsplit_reverse(b: Self::Second, a: Self::First) -> Self
{
Self::unsplit(a, b)
}
}
impl<T, U> Split for (T, U)
{
type First = T;
type Second = U;
#[inline(always)] fn split(self) -> (Self::First, Self::Second) {
self
}
#[inline(always)] fn unsplit(a: Self::First, b: Self::Second) -> Self {
(a, b)
}
}
//TODO: Add trait `SplitRef` for exchange, I guess?
/// Merges a Read and Write stream in an implementor of `Split`, `AsyncRead`, and `Asyncwrite`.
///
/// Used for internal of `Stream`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub(super) struct Merge<Tx, Rx>(pub Tx, pub Rx);
impl<Tx, Rx> Merge<Tx, Rx>
{
fn rx(self: Pin<&mut Self>) -> Pin<&mut Rx>
{
unsafe {self.map_unchecked_mut(|this| &mut this.1)}
}
fn tx(self: Pin<&mut Self>) -> Pin<&mut Tx>
{
unsafe {self.map_unchecked_mut(|this| &mut this.0)}
}
}
impl<Tx, Rx> Split for Merge<Tx, Rx>
{
type First = Tx;
type Second = Rx;
#[inline] fn split(self) -> (Self::First, Self::Second) {
(self.0, self.1)
}
#[inline] fn unsplit(a: Self::First, b: Self::Second) -> Self {
Self(a, b)
}
}
impl<Tx, Rx> AsyncWrite for Merge<Tx, Rx>
where Tx: AsyncWrite
{
#[inline] fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize, io::Error>> {
self.tx().poll_write(cx, buf)
}
#[inline] fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
self.tx().poll_flush(cx)
}
#[inline] fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
self.tx().poll_flush(cx)
}
#[inline] fn poll_write_buf<B: Buf>(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut B) -> Poll<Result<usize, io::Error>>
where
Self: Sized, {
self.tx().poll_write_buf(cx, buf)
}
}
impl<Tx, Rx> AsyncRead for Merge<Tx, Rx>
where Rx: AsyncRead
{
#[inline] fn poll_read(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
self.rx().poll_read(cx, buf)
}
#[inline] fn poll_read_buf<B: BufMut>(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut B) -> Poll<io::Result<usize>>
where
Self: Sized, {
self.rx().poll_read_buf(cx, buf)
}
}
/*
pub(super) enum MaybeFullWrite<'a, S: AsyncWrite>
{
Full(&'a mut Stream<S>),
Half(&'a mut WriteHalf<S>),
}
pub(super) enum MaybeFullRead<'a, S: AsyncRead>
{
Full(&'a mut Stream<S>),
Half(&'a mut ReadHalf<S>),
}
impl<'a, S: AsyncRead> AsMut<dyn AsyncRead + 'a> for MaybeFullRead<'a, S>
{
#[inline] fn as_mut(&mut self) -> &mut (dyn AsyncRead + 'a)
{
self.as_dyn()
}
}
impl<'a, S: AsyncWrite> AsMut<dyn AsyncWrite + 'a> for MaybeFullWrite<'a, S>
{
#[inline] fn as_mut(&mut self) -> &mut (dyn AsyncWrite + 'a)
{
self.as_dyn()
}
}
impl<'a, S: AsyncRead> MaybeFullRead<'a, S>
{
#[inline(always)] fn as_dyn(&mut self) -> &mut (dyn AsyncRead + 'a)
{
match self {
Self::Full(f) => f,
Self::Half(h) => h,
}
}
}
impl<'a, S: AsyncWrite> MaybeFullWrite<'a, S>
{
#[inline(always)] fn as_dyn(&mut self) -> &mut (dyn AsyncWrite + 'a)
{
match self {
Self::Full(f) => f,
Self::Half(h) => h,
}
}
}
*/
Loading…
Cancel
Save