commit
035dabf869
@ -0,0 +1,2 @@
|
|||||||
|
/target
|
||||||
|
*~
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,20 @@
|
|||||||
|
[package]
|
||||||
|
name = "transfer"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
async-compression = { version = "0.3.8", features = ["tokio", "brotli"] }
|
||||||
|
base64 = "0.13.0"
|
||||||
|
color-eyre = { version = "0.5.11", default-features = false }
|
||||||
|
cryptohelpers = { version = "1.8.2", features = ["full"] }
|
||||||
|
getrandom = "0.2.3"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
log = "0.4.14"
|
||||||
|
openssl = "0.10.36"
|
||||||
|
pretty_env_logger = "0.4.0"
|
||||||
|
serde = { version = "1.0.130", features = ["derive"] }
|
||||||
|
serde_cbor = "0.11.2"
|
||||||
|
tokio = { version = "1.12.0", features = ["full"] }
|
@ -0,0 +1,60 @@
|
|||||||
|
//! Arg parsing and process info
|
||||||
|
use super::*;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
lazy_static!{
|
||||||
|
static ref EXEC: String = std::env::args().next().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn program_name() -> &'static str
|
||||||
|
{
|
||||||
|
&EXEC[..]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Program usage
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Usage;
|
||||||
|
|
||||||
|
impl Usage
|
||||||
|
{
|
||||||
|
pub fn print_and_exit(self, code: i32) -> !
|
||||||
|
{
|
||||||
|
if code == 0 {
|
||||||
|
print!("{}", self);
|
||||||
|
} else {
|
||||||
|
eprint!("{}", self);
|
||||||
|
}
|
||||||
|
std::process::exit(code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn splash(f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
writeln!(f, "transfer v{} - simple network file transfer", env!("CARGO_PKG_VERSION"))?;
|
||||||
|
writeln!(f, " written by {} with <3. License GPL3+", env!("CARGO_PKG_AUTHORS"))?;
|
||||||
|
writeln!(f, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Usage
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
splash(f)?;
|
||||||
|
|
||||||
|
writeln!(f, "Usage: {} --send <bind> [SEND OPTIONS] <file...>", program_name())?;
|
||||||
|
writeln!(f, "Usage: {} --recv <endpoint> [RECV OPTIONS] <output...>", program_name())?;
|
||||||
|
writeln!(f, "\nSEND OPTIONS:")?;
|
||||||
|
writeln!(f, " -e\t\t\tEncrypt file(s)")?;
|
||||||
|
writeln!(f, " -c\t\t\tCompress files")?;
|
||||||
|
writeln!(f, " --buffer-size <bytes>\tSize of file buffer")?;
|
||||||
|
writeln!(f, " -a\t\t\tSend file names")?;
|
||||||
|
writeln!(f, " -1\t\t\tExit after 1 client has been served")?;
|
||||||
|
writeln!(f, " -k\t\t\tSupport continuation of failed downloads")?;
|
||||||
|
|
||||||
|
writeln!(f, "\nRECV OPTIONS:")?;
|
||||||
|
writeln!(f, " -i\t\t\tAsk before starting downloads")?;
|
||||||
|
writeln!(f, " -k\t\t\tContinue a previously started download")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
use openssl::{
|
||||||
|
symm::{
|
||||||
|
Cipher, Crypter, Mode,
|
||||||
|
},
|
||||||
|
error::ErrorStack,
|
||||||
|
};
|
||||||
|
use crate::key::{Key, IV};
|
||||||
|
|
||||||
|
/// Size of the key used for the cipher
|
||||||
|
pub const KEY_SIZE: usize = 32;
|
||||||
|
/// Size of the IV used for the cipher
|
||||||
|
pub const IV_SIZE: usize = 12;
|
||||||
|
|
||||||
|
static NEW_CIPHER: fn() -> Cipher = Cipher::chacha20_poly1305;
|
||||||
|
|
||||||
|
#[inline] pub fn decrypter(key: impl AsRef<Key>, iv: impl AsRef<IV>) -> Result<Crypter, ErrorStack>
|
||||||
|
{
|
||||||
|
Crypter::new(
|
||||||
|
NEW_CIPHER(),
|
||||||
|
Mode::Decrypt,
|
||||||
|
key.as_ref().as_ref(),
|
||||||
|
Some(iv.as_ref().as_ref())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
#[inline] pub fn encrypter(key: impl AsRef<Key>, iv: impl AsRef<IV>) -> Result<Crypter, ErrorStack>
|
||||||
|
{
|
||||||
|
Crypter::new(
|
||||||
|
NEW_CIPHER(),
|
||||||
|
Mode::Encrypt,
|
||||||
|
key.as_ref().as_ref(),
|
||||||
|
Some(iv.as_ref().as_ref())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a random key and IV for the chacha20_poly1305 cipher
|
||||||
|
#[inline(always)] pub fn keygen() -> (Key, IV)
|
||||||
|
{
|
||||||
|
(Key::new(), IV::new())
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
//! Configuration
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub const DEFAULT_BUFFER_SIZE: usize = 4096;
|
||||||
|
|
||||||
|
/// Configuration for sending
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct SendConfig
|
||||||
|
{
|
||||||
|
encrypt: bool,
|
||||||
|
compress: bool,
|
||||||
|
buffer_size: usize,
|
||||||
|
archive: bool,
|
||||||
|
oneshot: bool,
|
||||||
|
continuation: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SendConfig
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
encrypt: false,
|
||||||
|
compress: false,
|
||||||
|
buffer_size: DEFAULT_BUFFER_SIZE,
|
||||||
|
archive: false,
|
||||||
|
oneshot: false,
|
||||||
|
continuation: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configuration for receiving
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct RecvConfig
|
||||||
|
{
|
||||||
|
interactive: bool,
|
||||||
|
continuation: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for RecvConfig
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
interactive: false,
|
||||||
|
continuation: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Program configuration
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum Config
|
||||||
|
{
|
||||||
|
Send(SendConfig),
|
||||||
|
Recv(RecvConfig),
|
||||||
|
}
|
@ -0,0 +1,124 @@
|
|||||||
|
use std::{
|
||||||
|
mem,
|
||||||
|
iter::{
|
||||||
|
self,
|
||||||
|
ExactSizeIterator,
|
||||||
|
FusedIterator,
|
||||||
|
},
|
||||||
|
slice,
|
||||||
|
fmt,
|
||||||
|
};
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct HexStringIter<I>(I, [u8; 2]);
|
||||||
|
|
||||||
|
impl<I: Iterator<Item = u8>> HexStringIter<I>
|
||||||
|
{
|
||||||
|
/// Write this hex string iterator to a formattable buffer
|
||||||
|
pub fn consume<F>(self, f: &mut F) -> fmt::Result
|
||||||
|
where F: std::fmt::Write
|
||||||
|
{
|
||||||
|
if self.1[0] != 0 {
|
||||||
|
write!(f, "{}", self.1[0] as char)?;
|
||||||
|
}
|
||||||
|
if self.1[1] != 0 {
|
||||||
|
write!(f, "{}", self.1[1] as char)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for x in self.0 {
|
||||||
|
write!(f, "{:02x}", x)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consume into a string
|
||||||
|
pub fn into_string(self) -> String
|
||||||
|
{
|
||||||
|
let mut output = match self.size_hint() {
|
||||||
|
(0, None) => String::new(),
|
||||||
|
(_, Some(x)) |
|
||||||
|
(x, None) => String::with_capacity(x),
|
||||||
|
};
|
||||||
|
self.consume(&mut output).unwrap();
|
||||||
|
output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait HexStringIterExt<I>: Sized
|
||||||
|
{
|
||||||
|
fn into_hex(self) -> HexStringIter<I>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type HexStringSliceIter<'a> = HexStringIter<iter::Copied<slice::Iter<'a, u8>>>;
|
||||||
|
|
||||||
|
pub trait HexStringSliceIterExt
|
||||||
|
{
|
||||||
|
fn hex(&self) -> HexStringSliceIter<'_>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> HexStringSliceIterExt for S
|
||||||
|
where S: AsRef<[u8]>
|
||||||
|
{
|
||||||
|
fn hex(&self) -> HexStringSliceIter<'_>
|
||||||
|
{
|
||||||
|
self.as_ref().iter().copied().into_hex()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: IntoIterator<Item=u8>> HexStringIterExt<I::IntoIter> for I
|
||||||
|
{
|
||||||
|
#[inline] fn into_hex(self) -> HexStringIter<I::IntoIter> {
|
||||||
|
HexStringIter(self.into_iter(), [0u8; 2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Iterator<Item = u8>> Iterator for HexStringIter<I>
|
||||||
|
{
|
||||||
|
type Item = char;
|
||||||
|
fn next(&mut self) -> Option<Self::Item>
|
||||||
|
{
|
||||||
|
match self.1 {
|
||||||
|
[_, 0] => {
|
||||||
|
use std::io::Write;
|
||||||
|
write!(&mut self.1[..], "{:02x}", self.0.next()?).unwrap();
|
||||||
|
|
||||||
|
Some(mem::replace(&mut self.1[0], 0) as char)
|
||||||
|
},
|
||||||
|
[0, _] => Some(mem::replace(&mut self.1[1], 0) as char),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
let (l, h) = self.0.size_hint();
|
||||||
|
|
||||||
|
(l * 2, h.map(|x| x*2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Iterator<Item = u8> + ExactSizeIterator> ExactSizeIterator for HexStringIter<I>{}
|
||||||
|
impl<I: Iterator<Item = u8> + FusedIterator> FusedIterator for HexStringIter<I>{}
|
||||||
|
|
||||||
|
impl<I: Iterator<Item = u8>> From<HexStringIter<I>> for String
|
||||||
|
{
|
||||||
|
fn from(from: HexStringIter<I>) -> Self
|
||||||
|
{
|
||||||
|
from.into_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Iterator<Item = u8> + Clone> fmt::Display for HexStringIter<I>
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
self.clone().consume(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
#[macro_export] macro_rules! prog1 {
|
||||||
|
($first:expr, $($rest:expr);+ $(;)?) => {
|
||||||
|
($first, $( $rest ),+).0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
@ -0,0 +1,289 @@
|
|||||||
|
//! Key and IV structures for the cipher
|
||||||
|
|
||||||
|
use getrandom::getrandom;
|
||||||
|
use std::{fmt, str};
|
||||||
|
pub use crate::cha::{
|
||||||
|
KEY_SIZE,
|
||||||
|
IV_SIZE,
|
||||||
|
};
|
||||||
|
use crate::ext::*;
|
||||||
|
|
||||||
|
/// A 32 byte key for the chacha20_poly1305 cipher
|
||||||
|
///
|
||||||
|
/// # Generation
|
||||||
|
/// You can generate a random key with `Key::new()`.
|
||||||
|
/// To create a key structure from bytes, you can use `Key::from_bytes()` if the size of the buffer is exact, or you can write to an empty `Key` as it implements `Default`.
|
||||||
|
/// ```
|
||||||
|
/// # use chacha20stream::{Key, key::KEY_SIZE};
|
||||||
|
/// # let key_bytes = [0u8; 32];
|
||||||
|
/// let mut key = Key::default();
|
||||||
|
/// key.as_mut().copy_from_slice(&key_bytes[..KEY_SIZE]);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// You can also generate a random key/IV pair with `chacha20stream::keygen()`.
|
||||||
|
///
|
||||||
|
/// # Encoding
|
||||||
|
/// This type implements `std::fmt::Display`, which prints the key as a base64 string.
|
||||||
|
/// Additionally, it implements `std::str::FromStr`, which decodes a base64 string into a `Key` instance.
|
||||||
|
/// If the input base64 string data decoded is shorter than `KEY_SIZE`, the rest of the key instance is padded with 0s.
|
||||||
|
/// If it is longer, the rest is ignored.
|
||||||
|
///
|
||||||
|
/// The key can also be lazily formatted as a hex string, with the method `to_hex_string()`.
|
||||||
|
/// ```
|
||||||
|
/// # use chacha20stream::Key;
|
||||||
|
/// let key = Key::new();
|
||||||
|
/// let key_encoded = key.to_string();
|
||||||
|
///
|
||||||
|
/// println!("Key base64: {}", key_encoded);
|
||||||
|
/// println!("Key hex: {}", key.to_hex_string());
|
||||||
|
///
|
||||||
|
/// assert_eq!(key_encoded.parse::<Key>().unwrap(), key);
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy, Default)]
|
||||||
|
#[cfg_attr(feature="serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Key([u8; KEY_SIZE]);
|
||||||
|
|
||||||
|
/// A 12 byte IV for the chacha20_poly1305 cipher
|
||||||
|
///
|
||||||
|
/// # Generation
|
||||||
|
/// You can generate a random IV with `IV::new()`.
|
||||||
|
/// To create an IV structure from bytes, you can use `IV::from_bytes()` if the size of the buffer is exact, or you can write to an empty `IV` as it implements `Default`.
|
||||||
|
/// ```
|
||||||
|
/// # use chacha20stream::{IV, key::IV_SIZE};
|
||||||
|
/// # let iv_bytes = [0u8; 12];
|
||||||
|
/// let mut iv = IV::default();
|
||||||
|
/// iv.as_mut().copy_from_slice(&iv_bytes[..IV_SIZE]);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// You can also generate a random key/IV pair with `chacha20stream::keygen()`.
|
||||||
|
///
|
||||||
|
/// # Encoding
|
||||||
|
/// This type implements `std::fmt::Display`, which prints the IV as a base64 string.
|
||||||
|
/// Additionally, it implements `std::str::FromStr`, which decodes a base64 string into a `IV` instance.
|
||||||
|
/// If the input base64 string data decoded is shorter than `IV_SIZE`, the rest of the IV instance is padded with 0s.
|
||||||
|
/// If it is longer, the rest is ignored.
|
||||||
|
///
|
||||||
|
/// The IV can also be lazily formatted as a hex string, with the method `to_hex_string()`.
|
||||||
|
/// ```
|
||||||
|
/// # use chacha20stream::IV;
|
||||||
|
/// let iv = IV::new();
|
||||||
|
/// let iv_encoded = iv.to_string();
|
||||||
|
///
|
||||||
|
/// println!("IV base64: {}", iv_encoded);
|
||||||
|
/// println!("IV hex: {}", iv.to_hex_string());
|
||||||
|
///
|
||||||
|
/// assert_eq!(iv_encoded.parse::<IV>().unwrap(), iv);
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy, Default)]
|
||||||
|
#[cfg_attr(feature="serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct IV([u8; IV_SIZE]);
|
||||||
|
|
||||||
|
impl Key
|
||||||
|
{
|
||||||
|
/// Construct a `Key` from an exact length (32 bytes) buffer.
|
||||||
|
#[inline] pub fn from_bytes(k: [u8; KEY_SIZE]) -> Self
|
||||||
|
{
|
||||||
|
Self(k)
|
||||||
|
}
|
||||||
|
/// Create a new random 32 byte chacha20_poly1305 `Key`.
|
||||||
|
pub fn new() -> Self
|
||||||
|
{
|
||||||
|
let mut output = [0u8; KEY_SIZE];
|
||||||
|
getrandom(&mut output[..]).expect("rng fatal");
|
||||||
|
Self(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Format this key as a hex string
|
||||||
|
///
|
||||||
|
/// Returns an opaque type that lazily formats the key into a hex string when written.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use chacha20stream::Key;
|
||||||
|
/// fn print_key_info(key: &Key) {
|
||||||
|
/// println!("Key base64: {}", key);
|
||||||
|
/// println!("Key hex: {}", key.to_hex_string());
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// Formatting to `String`
|
||||||
|
/// ```
|
||||||
|
/// # use chacha20stream::Key;
|
||||||
|
/// # let key = Key::new();
|
||||||
|
/// let key_hex_string = key.to_hex_string().to_string();
|
||||||
|
/// ```
|
||||||
|
pub fn to_hex_string(&self) -> impl fmt::Display + '_
|
||||||
|
{
|
||||||
|
self.0.iter().copied().into_hex()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IV
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Construct a `IV` from an exact length (12 bytes) buffer.
|
||||||
|
#[inline] pub fn from_bytes(k: [u8; IV_SIZE]) -> Self
|
||||||
|
{
|
||||||
|
Self(k)
|
||||||
|
}
|
||||||
|
/// Create a new random 12 byte chacha20_poly1305 `IV`.
|
||||||
|
pub fn new() -> Self
|
||||||
|
{
|
||||||
|
let mut output = [0u8; IV_SIZE];
|
||||||
|
getrandom(&mut output[..]).expect("rng fatal");
|
||||||
|
Self(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Format this IV as a hex string
|
||||||
|
///
|
||||||
|
/// Returns an opaque type that lazily formats the IV into a hex string when written.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use chacha20stream::IV;
|
||||||
|
/// fn print_iv_info(iv: &IV) {
|
||||||
|
/// println!("IV base64: {}", iv);
|
||||||
|
/// println!("IV hex: {}", iv.to_hex_string());
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// Formatting to `String`
|
||||||
|
/// ```
|
||||||
|
/// # use chacha20stream::IV;
|
||||||
|
/// # let iv = IV::new();
|
||||||
|
/// let iv_hex_string = iv.to_hex_string().to_string();
|
||||||
|
/// ```
|
||||||
|
pub fn to_hex_string(&self) -> impl fmt::Display + '_
|
||||||
|
{
|
||||||
|
self.0.iter().copied().into_hex()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<[u8; KEY_SIZE]> for Key
|
||||||
|
{
|
||||||
|
#[inline] fn from(from: [u8; KEY_SIZE]) -> Self
|
||||||
|
{
|
||||||
|
Self(from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<[u8; IV_SIZE]> for IV
|
||||||
|
{
|
||||||
|
fn from(from: [u8; IV_SIZE]) -> Self
|
||||||
|
{
|
||||||
|
Self(from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl AsRef<[u8]> for Key
|
||||||
|
{
|
||||||
|
fn as_ref(&self) -> &[u8]
|
||||||
|
{
|
||||||
|
&self.0[..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl AsRef<[u8]> for IV
|
||||||
|
{
|
||||||
|
fn as_ref(&self) -> &[u8]
|
||||||
|
{
|
||||||
|
&self.0[..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsMut<[u8]> for Key
|
||||||
|
{
|
||||||
|
fn as_mut(&mut self) -> &mut [u8]
|
||||||
|
{
|
||||||
|
&mut self.0[..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsMut<[u8]> for IV
|
||||||
|
{
|
||||||
|
fn as_mut(&mut self) -> &mut [u8]
|
||||||
|
{
|
||||||
|
&mut self.0[..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<Key> for Key
|
||||||
|
{
|
||||||
|
#[inline] fn as_ref(&self) -> &Key
|
||||||
|
{
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl AsRef<IV> for IV
|
||||||
|
{
|
||||||
|
#[inline] fn as_ref(&self) -> &IV
|
||||||
|
{
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Key
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
write!(f, "{}", base64::encode(&self.0[..]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for IV
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
write!(f, "{}", base64::encode(&self.0[..]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl str::FromStr for Key
|
||||||
|
{
|
||||||
|
type Err = base64::DecodeError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let mut buffer = Vec::with_capacity(KEY_SIZE);
|
||||||
|
base64::decode_config_buf(s.as_bytes(), base64::STANDARD, &mut buffer)?;
|
||||||
|
|
||||||
|
let mut this = Self::default();
|
||||||
|
let sz = std::cmp::min(KEY_SIZE, buffer.len());
|
||||||
|
(&mut this.0[..sz]).copy_from_slice(&buffer[..sz]);
|
||||||
|
Ok(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl str::FromStr for IV
|
||||||
|
{
|
||||||
|
type Err = base64::DecodeError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let mut buffer = Vec::with_capacity(IV_SIZE);
|
||||||
|
base64::decode_config_buf(s.as_bytes(), base64::STANDARD, &mut buffer)?;
|
||||||
|
|
||||||
|
let mut this = Self::default();
|
||||||
|
let sz = std::cmp::min(IV_SIZE, buffer.len());
|
||||||
|
(&mut this.0[..sz]).copy_from_slice(&buffer[..sz]);
|
||||||
|
Ok(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests
|
||||||
|
{
|
||||||
|
use super::{Key, IV};
|
||||||
|
#[test]
|
||||||
|
fn enc_dec()
|
||||||
|
{
|
||||||
|
let (key, iv) = crate::keygen();
|
||||||
|
|
||||||
|
let key_str = key.to_string();
|
||||||
|
let iv_str = iv.to_string();
|
||||||
|
|
||||||
|
let (key2, iv2): (Key, IV) = (key_str.parse().expect("key"),
|
||||||
|
iv_str.parse().expect("iv"));
|
||||||
|
|
||||||
|
assert_eq!(key, key2);
|
||||||
|
assert_eq!(iv, iv2);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
#[macro_use] extern crate log;
|
||||||
|
#[macro_use] extern crate lazy_static;
|
||||||
|
#[macro_use] extern crate serde;
|
||||||
|
|
||||||
|
use color_eyre::{
|
||||||
|
eyre::{
|
||||||
|
self,
|
||||||
|
eyre,
|
||||||
|
WrapErr,
|
||||||
|
},
|
||||||
|
SectionExt, Help,
|
||||||
|
};
|
||||||
|
|
||||||
|
mod ext;
|
||||||
|
mod key;
|
||||||
|
mod cha;
|
||||||
|
|
||||||
|
mod config;
|
||||||
|
mod args;
|
||||||
|
|
||||||
|
mod send;
|
||||||
|
|
||||||
|
fn setup() -> eyre::Result<()>
|
||||||
|
{
|
||||||
|
color_eyre::install()?;
|
||||||
|
pretty_env_logger::init();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> eyre::Result<()> {
|
||||||
|
setup().wrap_err(eyre!("Failed to initialise logger"))?;
|
||||||
|
|
||||||
|
args::Usage.print_and_exit(0);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
//! Module handles setting up streams for files
|
||||||
|
use super::*;
|
||||||
|
use std::marker::Unpin;
|
||||||
|
use tokio::io::{
|
||||||
|
AsyncRead,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// A read request from the client.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct Request
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn read_req<T>(mut from: T, key: ) -> eyre::Result<Request>
|
||||||
|
where T: AsyncRead + Unpin
|
||||||
|
{
|
||||||
|
todo!("how do we handle encryption of the request data? eh... boring")
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
//! Sending
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub mod handshake;
|
Loading…
Reference in new issue