/handshake

Secure Scuttlebutt handshake + boxstream library

Primary LanguageRustOtherNOASSERTION

Build Status codecov

kuska handshake

kuska means together in Runasimi

kuska is an implementation of decentralized social network Secure Scuttlebut written in rust, it does not aim to provide a user interface and the functionality implemented in some clients like Patchwork, Patchbay, but the full set of libraries to be able to develop applications for the secure scuttlebut network.

kuska-handshake is the implementation of the handhake and box stream used in SSB, detailed information about the protocol can be found in https://ssbc.github.io/scuttlebutt-protocol-guide/.

the current implementation contains:

  • an agnostic implementation of the protcol using sodiumoxide
  • a synchronous version (needs sync feature)
  • an asynchronous async_std version (needs async_std feature, with wrappers for tokio with tokio_compat feature)

sync client/server

server

Create the server key pair

let (pk, sk) = ed25519::gen_keypair();
let pk_b64 = base64::encode_config(&pk, base64::STANDARD);

Define the network to connect

let net_id_hex = "d4a1cb88a66f02f8db635ce26441cc5dac1b08420ceaac230839b755845a9ffb";
let net_id = auth::Key::from_slice(&hex::decode(net_id_hex).unwrap()).unwrap();

Listen, accept the socket, and perform the handshake

let listener = TcpListener::bind(...).unwrap();
let (socket, addr) = listener.accept().unwrap();
let handshake = handshake_server(&socket, net_id, pk, sk)?;

Once the handshake is performed, create both box streams, one to send and another to recieve data, those box streams implements std::io::Read and std::io::Write to perform usual i/o operations on them.

let (key_nonce_send, key_nonce_recv) = KeyNonce::from_handshake(handshake);
let (mut box_stream_read, mut box_stream_write) =
        BoxStream::new(&socket, &socket, key_nonce_send, key_nonce_recv).split_read_write();

box_stream_read.read_exact(...)
box_stream_write.write_all(...)

client

Create the client key pair

let (pk, sk) = ed25519::gen_keypair();
let pk_b64 = base64::encode_config(&pk, base64::STANDARD);

Connect to the server, perform the handshake (you need the server public key), and create the box streams to communicate

let socket = TcpStream::connect(...).unwrap();
let handshake = handshake_client(&socket, net_id, pk, sk, server_pk)?;

let (key_nonce_send, key_nonce_recv) = KeyNonce::from_handshake(handshake);
let (mut box_stream_read, mut box_stream_write) =
  BoxStream::new(&socket, &socket, key_nonce_send, key_nonce_recv).split_read_write();

box_stream_read.read_exact(...)
box_stream_write.write_all(...)

async_std client

The async_std client is analogous to the sync version, just all functions are async and uses async_std::io::Read and async_std::io::Write for box streams

use async_std::io::{Read,Write};
use async_std::net::TcpStream;
use kuska_handshake::async_std::{handshake_client,BoxStream};

#[async_std::main]
async fn main() -> Result<T, Box<dyn Error>> {
  ...
  let mut socket = TcpStream::connect("127.0.0.1:8008").await?;
  let (_,handshake) = handshake_client(&mut socket, ssb_net_id(), pk, sk, server_pk).await?;

  let (box_stream_read, box_stream_write) =
      BoxStream::from_handhake(&socket, &socket, handshake, 0x8000)
      .split_read_write();

tokio client

To use the tokio you need the wrappers used in kuska_handshake::async_std::tokio_compat:

use tokio::net::TcpStream;
use kuska_handshake::async_std::{BoxStream,handshake_client,TokioCompatExt,TokioCompatExtRead,TokioCompatExtWrite};

let tokio_socket : TcpStream = TcpStream::connect("127.0.0.1:8008").await?;
let asyncstd_socket = TokioCompatExt::wrap(tokio_socket);

let (asyncstd_socket,handshake) = handshake_client(asyncstd_socket, ssb_net_id(), pk, sk.clone(), pk).await?;
let mut tokio_socket = asyncstd_socket.into_inner();
let (read,write) = tokio_socket.split();

let read = TokioCompatExtRead::wrap(read);
let write = TokioCompatExtWrite::wrap(write);

let (box_stream_read, box_stream_write) =
    BoxStream::from_handhake(read, write, handshake, 0x8000)
    .split_read_write();