initial commit
This commit is contained in:
commit
565e400e8d
9 changed files with 796 additions and 0 deletions
159
src/lib.rs
Normal file
159
src/lib.rs
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
use chacha::Block;
|
||||
use std::io::{Error, Read, Write};
|
||||
use std::net::{Shutdown, TcpStream};
|
||||
use rand::{rng, RngCore};
|
||||
use x25519_dalek::{EphemeralSecret, PublicKey};
|
||||
|
||||
#[inline]
|
||||
fn u8_to_u32(to: &mut [u32], from: &[u8]) {
|
||||
for i in 0..to.len() {
|
||||
to[i] = u32::from_le_bytes(from[4*i..][..4].try_into().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#[repr(u8)]
|
||||
enum Exchange {
|
||||
DHCurve25519 = 0
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for Exchange {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
0 => Ok(Exchange::DHCurve25519),
|
||||
_ => Err(Error::new(ErrorKind::InvalidData, "Invalid exchange code")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
enum Encryption {
|
||||
ChaCha = 0
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for Encryption {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
0 => Ok(Encryption::ChaCha),
|
||||
_ => Err(Error::new(ErrorKind::InvalidData, "Invalid encryption code")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EncryptedStream {
|
||||
socket: TcpStream,
|
||||
block: Block,
|
||||
}
|
||||
|
||||
impl EncryptedStream {
|
||||
pub fn bind(address: &str) -> Result<EncryptedStream, Error> {
|
||||
let secret = EphemeralSecret::random();
|
||||
let public = PublicKey::from(&secret);
|
||||
|
||||
let mut socket = TcpStream::connect(address)?;
|
||||
|
||||
socket.write(public.as_bytes())?;
|
||||
|
||||
let mut their_public_bytes = [0u8; 32];
|
||||
socket.read_exact(&mut their_public_bytes)?;
|
||||
|
||||
let their_public = PublicKey::from(their_public_bytes);
|
||||
|
||||
let shared_secret = secret.diffie_hellman(&their_public);
|
||||
|
||||
let mut nonce_bytes = [0u8; 12];
|
||||
socket.read_exact(&mut nonce_bytes)?;
|
||||
|
||||
let mut nonce_u32s = [0u32; 3];
|
||||
u8_to_u32(&mut nonce_u32s, &nonce_bytes);
|
||||
|
||||
let mut key_u32s = [0u32; 8];
|
||||
u8_to_u32(&mut key_u32s, &shared_secret.to_bytes());
|
||||
|
||||
Ok(EncryptedStream {
|
||||
socket,
|
||||
block: Block::new(key_u32s, 0, nonce_u32s, 20)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn shutdown(&self, how: Shutdown) -> Result<(), Error> {
|
||||
self.socket.shutdown(how)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<TcpStream> for EncryptedStream {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(mut socket: TcpStream) -> Result<Self, Self::Error> {
|
||||
let secret = EphemeralSecret::random();
|
||||
let public = PublicKey::from(&secret);
|
||||
|
||||
let mut their_public_bytes = [0u8; 32];
|
||||
socket.read(&mut their_public_bytes)?;
|
||||
|
||||
socket.write(public.as_bytes())?;
|
||||
|
||||
let their_public = PublicKey::from(their_public_bytes);
|
||||
|
||||
let shared_secret = secret.diffie_hellman(&their_public);
|
||||
|
||||
let mut nonce_bytes = [0u8; 12];
|
||||
rng().fill_bytes(&mut nonce_bytes);
|
||||
|
||||
socket.write(&nonce_bytes)?;
|
||||
|
||||
let mut nonce_u32s = [0u32; 3];
|
||||
u8_to_u32(&mut nonce_u32s, &nonce_bytes);
|
||||
|
||||
let mut key_u32s = [0u32; 8];
|
||||
u8_to_u32(&mut key_u32s, &shared_secret.to_bytes());
|
||||
|
||||
Ok(EncryptedStream {
|
||||
socket,
|
||||
block: Block::new(key_u32s, 0, nonce_u32s, 20)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for EncryptedStream {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
let n = self.socket.read(buf)?;
|
||||
|
||||
self.block.process(&mut buf[..n]);
|
||||
|
||||
Ok(n)
|
||||
}
|
||||
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize, Error> {
|
||||
let n = self.socket.read_to_end(buf)?;
|
||||
|
||||
self.block.process(buf.as_mut_slice());
|
||||
|
||||
Ok(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for EncryptedStream {
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
|
||||
let mut new = Vec::from(buf);
|
||||
|
||||
self.block.process(new.as_mut_slice());
|
||||
|
||||
self.socket.write(&new)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
self.socket.flush()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {}
|
||||
47
src/main.rs
Normal file
47
src/main.rs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
use hermes::EncryptedStream;
|
||||
use std::env::args;
|
||||
use std::io::{Read, Write};
|
||||
use std::net::{Shutdown, TcpListener};
|
||||
use std::process::exit;
|
||||
|
||||
fn main() {
|
||||
let args = args().skip(1).collect::<Vec<_>>();
|
||||
if args.len() == 0 {
|
||||
println!("missing arg (Client or Server?)");
|
||||
exit(1)
|
||||
}
|
||||
|
||||
match args[0].as_ref() {
|
||||
"s" => {
|
||||
let server = TcpListener::bind("127.0.0.1:2007").unwrap();
|
||||
println!("listening");
|
||||
|
||||
for incoming in server.incoming() {
|
||||
println!("got incoming connection");
|
||||
let mut encrypted = EncryptedStream::try_from(incoming.unwrap()).unwrap();
|
||||
println!("successfully encrypted stream");
|
||||
|
||||
encrypted.write(b"the fitness gram pacer test is a multi-stage aerobic fitness test...").unwrap();
|
||||
println!("successfully wrote data");
|
||||
|
||||
encrypted.flush().unwrap();
|
||||
encrypted.shutdown(Shutdown::Both).unwrap();
|
||||
println!("closed connection");
|
||||
}
|
||||
}
|
||||
"c" => {
|
||||
let mut client = EncryptedStream::bind("127.0.0.1:2007").unwrap();
|
||||
println!("successfully connected client");
|
||||
|
||||
let mut buf = Vec::new();
|
||||
client.read_to_end(&mut buf).unwrap();
|
||||
println!("successfully read data");
|
||||
|
||||
println!("data: {}", String::from_utf8_lossy(&buf));
|
||||
}
|
||||
_ => {
|
||||
println!("Unknown command (not client or server)");
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue