portal-lib

A small Protocol Library for Portal - An encrypted file transfer utility

This crate enables a consumer to:

The library is broken up into two abstractions:

Higher Level API - Example of Sending a file:

```rust use std::path::Path; use std::error::Error; use std::net::TcpStream; use portal_lib::{Portal, Direction, TransferInfoBuilder};

fn my_send() -> Result<(), Box> {

// Securely generate/exchange ID & Password with peer out-of-band
let id = String::from("id");
let password = String::from("password");

// Connect to the relay - the ID will be used to connect the peers
let mut portal = Portal::init(Direction::Sender, id, password)?;
let mut stream = TcpStream::connect("127.0.0.1:34254")?;

// The handshake must be performed first, otherwise
// there is no shared key to encrypt the file with
portal.handshake(&mut stream)?;

// Add any files/directories
let info = TransferInfoBuilder::new()
    .add_file(Path::new("/etc/passwd"))?
    .finalize();

// Optional: implement a custom callback to display how much
// has been transferred
fn progress(transferred: usize) {
   println!("sent {:?} bytes", transferred);
}

// Send every file in TransferInfo
for (fullpath, metadata) in portal.outgoing(&mut stream, &info)? {
    portal.send_file(&mut stream, fullpath, Some(progress))?;
}
Ok(())

} ```

Higher Level API - Example of Receiving a file:

```rust use std::path::Path; use std::error::Error; use std::net::TcpStream; use portal_lib::{Portal, Direction, TransferInfo};

fn my_recv() -> Result<(), Box> {

// Securely generate/exchange ID & Password with peer out-of-band
let id = String::from("id");
let password = String::from("password");

// Connect to the relay - the ID will be used to connect the peers
let mut portal = Portal::init(Direction::Sender, id, password)?;
let mut stream = TcpStream::connect("127.0.0.1:34254")?;

// The handshake must be performed first, otherwise
// there is no shared key to encrypt the file with
portal.handshake(&mut stream)?;

// Optional: User callback to confirm/deny a transfer. If
// none is provided, this will default accept the incoming file.
// Return true to accept, false to reject the transfer.
fn confirm_download(_info: &TransferInfo) -> bool { true }

// Optional: implement a custom callback to display how much
// has been transferred
fn progress(transferred: usize) {
    println!("received {:?} bytes", transferred);
}

// Decide where downloads should go
let my_downloads = Path::new("/tmp");

// Receive every file in TransferInfo
for metadata in portal.incoming(&mut stream, Some(confirm_download))? {
    portal.recv_file(&mut stream, my_downloads, Some(&metadata), Some(progress))?;
}
Ok(())

} ```

Lower Level API - Example of SPAKE2 key negotiation:

```rust use spake2::{Ed25519Group, Identity, Password, Spake2};

// Securely receive/derive your id & password for this session let channel_id = String::from("myid"); let password = String::from("mysecurepassword");

// Init a Spake2 context let (state, outboundmsg) = Spake2::::startsymmetric( &Password::new(&password.asbytes()), &Identity::new(&channelid.as_bytes()), );

// Connect to the relay let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap();

// Send the connection message to the relay. If the relay cannot // match us with a peer this will fail. let confirm = Protocol::connect(&mut stream, &channelid, Direction::Sender, outboundmsg).unwrap();

// Derive the shared session key let key = Protocol::derive_key(state, &confirm).unwrap();

// confirm that the peer has the same key Protocol::confirmpeer(&mut stream, &channelid, Direction::Sender, &key)?; ```

You can use the confirm_peer() method to verify that a remote peer has derived the same key as you, as long as the communication stream implements the std::io::Read and std::io::Write traits.