pub mod packet;
pub mod codec;
pub use self::packet::*;
pub use self::codec::*;
use tox_binary_io::*;
use tox_crypto::*;
use crate::relay::secure;
use futures::{self, StreamExt, SinkExt, TryFutureExt};
use std::io::{Error, ErrorKind};
use tokio_util::codec::Framed;
use tokio::net::TcpStream;
pub fn create_client_handshake(client_pk: &PublicKey,
client_sk: &SecretKey,
server_pk: &PublicKey)
-> Result<(secure::Session, PrecomputedKey, ClientHandshake), Error> {
let session = secure::Session::random();
let payload = HandshakePayload { session_pk: *session.pk(), session_nonce: *session.nonce() };
let mut serialized_payload = [0; PAYLOAD_SIZE];
let (serialized_payload, _) = payload.to_bytes((&mut serialized_payload, 0)).unwrap();
let common_key = encrypt_precompute(server_pk, client_sk);
let nonce = gen_nonce();
let encrypted_payload = encrypt_data_symmetric(&common_key, &nonce, serialized_payload);
let handshake = ClientHandshake { pk: *client_pk, nonce, payload: encrypted_payload };
Ok((session, common_key, handshake))
}
pub fn handle_client_handshake(server_sk: &SecretKey,
client_handshake: &ClientHandshake)
-> Result<(secure::Channel, PublicKey, ServerHandshake), Error> {
let common_key = encrypt_precompute(&client_handshake.pk, server_sk);
let payload_bytes = decrypt_data_symmetric(&common_key, &client_handshake.nonce, &client_handshake.payload)
.map_err(
|_| Error::new(ErrorKind::Other, "Failed to decrypt ClientHandshake payload")
)?;
let (_, payload) = HandshakePayload::from_bytes(&payload_bytes)
.map_err(
|_| Error::new(ErrorKind::Other, "Failed to deserialize ClientHandshake payload")
)?;
let client_pk = payload.session_pk;
let client_nonce = payload.session_nonce;
let session = secure::Session::random();
let server_payload = HandshakePayload { session_pk: *session.pk(), session_nonce: *session.nonce() };
let mut serialized_payload = [0; PAYLOAD_SIZE];
let (serialized_payload, _) = server_payload.to_bytes((&mut serialized_payload, 0)).unwrap();
let nonce = gen_nonce();
let server_encrypted_payload = encrypt_data_symmetric(&common_key, &nonce, serialized_payload);
let server_handshake = ServerHandshake { nonce, payload: server_encrypted_payload };
let channel = secure::Channel::new(&session, &client_pk, &client_nonce);
Ok((channel, client_handshake.pk, server_handshake))
}
pub fn handle_server_handshake(common_key: &PrecomputedKey,
client_session: &secure::Session,
server_handshake: &ServerHandshake)
-> Result<secure::Channel, Error> {
let payload_bytes = decrypt_data_symmetric(common_key, &server_handshake.nonce, &server_handshake.payload)
.map_err(
|_| Error::new(ErrorKind::Other, "Failed to decrypt ServerHandshake payload")
)?;
let (_, payload) = HandshakePayload::from_bytes(&payload_bytes)
.map_err(
|_| Error::new(ErrorKind::Other, "Failed to deserialize ServerHandshake payload")
)?;
let server_pk = payload.session_pk;
let server_nonce = payload.session_nonce;
let channel = secure::Channel::new(client_session, &server_pk, &server_nonce);
Ok(channel)
}
pub async fn make_client_handshake(
socket: TcpStream,
client_pk: &PublicKey,
client_sk: &SecretKey,
server_pk: &PublicKey
) -> Result<(TcpStream, secure::Channel), Error> {
let (session, common_key, handshake) =
create_client_handshake(client_pk, client_sk, server_pk)?;
let mut client = Framed::new(socket, ClientHandshakeCodec);
client.send(handshake)
.map_err(|e| {
Error::new(
ErrorKind::Other,
format!("Could not send ClientHandshake {:?}", e),
)
})
.await?;
let socket = client.into_inner();
let server = Framed::new(socket, ServerHandshakeCodec);
let (handshake, server_socket) = server.into_future().await;
let handshake = match handshake {
None => Err(Error::new(
ErrorKind::Other, "Option<ServerHandshake> is empty"
)),
Some(Err(e)) => Err(Error::new(
ErrorKind::Other,
format!("Could not read ServerHandshake {:?}", e),
)),
Some(res) => res,
}?;
handle_server_handshake(&common_key, &session, &handshake)
.map(|chan| (server_socket.into_inner(), chan))
}
pub async fn make_server_handshake(
socket: TcpStream,
server_sk: SecretKey
) -> Result<(TcpStream, secure::Channel, PublicKey), Error> {
let client = Framed::new(socket, ClientHandshakeCodec);
let (handshake, client) = client.into_future().await;
let handshake = match handshake {
None => Err(Error::new(
ErrorKind::Other, "Option<ClientHandshake> is empty"
)),
Some(Err(e)) => Err(Error::new(
ErrorKind::Other,
format!("Could not read ClientHandshake {:?}", e),
)),
Some(res) => res,
}?;
let (channel, client_pk, server_handshake) =
handle_client_handshake(&server_sk, &handshake)?;
let socket = client.into_inner();
let mut server = Framed::new(socket, ServerHandshakeCodec);
server.send(server_handshake).await
.map_err(|e| {
Error::new(
ErrorKind::Other,
format!("Could not send ServerHandshake {:?}", e),
)
})?;
let socket = server.into_inner();
Ok((socket, channel, client_pk))
}
#[cfg(test)]
mod tests {
use std::net::SocketAddr;
use tox_crypto::*;
use crate::relay::*;
use crate::relay::handshake::*;
fn create_channels_with_handshake() -> (secure::Channel, secure::Channel) {
crypto_init().unwrap();
let (client_pk, client_sk) = gen_keypair();
let (server_pk, server_sk) = gen_keypair();
let (client_session, common_key, client_handshake) = create_client_handshake(&client_pk, &client_sk, &server_pk).unwrap();
assert_eq!(handshake::ENC_PAYLOAD_SIZE, client_handshake.payload.len());
let (server_channel, received_client_pk, server_handshake) = handle_client_handshake(&server_sk, &client_handshake).unwrap();
assert_eq!(received_client_pk, client_pk);
let client_channel = handle_server_handshake(&common_key, &client_session, &server_handshake).unwrap();
(client_channel, server_channel)
}
#[test]
fn secure_communication_with_handshake() {
let (alice_channel, bob_channel) = create_channels_with_handshake();
let alice_msg = "Hello Bob!";
let alice_msg_encrypted = alice_channel.encrypt(alice_msg.as_bytes());
assert_ne!(alice_msg.as_bytes().to_vec(), alice_msg_encrypted);
assert_eq!( alice_msg.as_bytes().to_vec(), bob_channel.decrypt(alice_msg_encrypted.as_ref()).unwrap() );
let bob_msg = "Oh hello Alice!";
let bob_msg_encrypted = bob_channel.encrypt(bob_msg.as_bytes());
assert_ne!(bob_msg.as_bytes().to_vec(), bob_msg_encrypted);
assert_eq!( bob_msg.as_bytes().to_vec(), alice_channel.decrypt(bob_msg_encrypted.as_ref()).unwrap() );
}
#[test]
fn client_handshake_with_different_keypair() {
crypto_init().unwrap();
let (client_pk, client_sk) = gen_keypair();
let (server_pk, _) = gen_keypair();
let (_, mallory_sk) = gen_keypair();
let (_client_session, _common_key, client_handshake) = create_client_handshake(&client_pk, &client_sk, &server_pk).unwrap();
assert!(handle_client_handshake(&mallory_sk, &client_handshake).is_err());
}
#[test]
fn server_handshake_with_different_keypair() {
crypto_init().unwrap();
let (client_pk, client_sk) = gen_keypair();
let (server_pk, server_sk) = gen_keypair();
let (_, mallory_sk) = gen_keypair();
let (client_session, _common_key, client_handshake) = create_client_handshake(&client_pk, &client_sk, &server_pk).unwrap();
let (_server_channel, _client_pk, server_handshake) = handle_client_handshake(&server_sk, &client_handshake).unwrap();
let common_key = encrypt_precompute(&client_pk, &mallory_sk);
assert!(handle_server_handshake(&common_key, &client_session, &server_handshake).is_err());
}
#[test]
fn client_handshake_with_bad_payload() {
crypto_init().unwrap();
let (client_pk, client_sk) = gen_keypair();
let (server_pk, server_sk) = gen_keypair();
fn create_bad_client_handshake(client_pk: &PublicKey,
client_sk: &SecretKey,
server_pk: &PublicKey)
-> ClientHandshake
{
let common_key = encrypt_precompute(server_pk, client_sk);
let nonce = gen_nonce();
let encrypted_payload = encrypt_data_symmetric(&common_key, &nonce, &[1, 2, 3]);
ClientHandshake { pk: *client_pk, nonce, payload: encrypted_payload }
}
let client_handshake = create_bad_client_handshake(&client_pk, &client_sk, &server_pk);
assert!(handle_client_handshake(&server_sk, &client_handshake).is_err());
}
#[test]
fn server_handshake_with_bad_payload() {
use self::secure::*;
crypto_init().unwrap();
let (client_pk, _) = gen_keypair();
let (_, server_sk) = gen_keypair();
let common_key = encrypt_precompute(&client_pk, &server_sk);
let client_session = Session::random();
fn create_bad_server_handshake(common_key: &PrecomputedKey)
-> ServerHandshake
{
let nonce = gen_nonce();
let server_encrypted_payload = encrypt_data_symmetric(common_key, &nonce, &[1, 2, 3]);
ServerHandshake { nonce, payload: server_encrypted_payload }
}
let server_handshake = create_bad_server_handshake(&common_key);
assert!(handle_server_handshake(&common_key, &client_session, &server_handshake).is_err());
}
#[tokio::test]
async fn network_handshake() {
use futures::{StreamExt};
use tokio::net::{TcpListener, TcpStream};
crypto_init().unwrap();
let (client_pk, client_sk) = gen_keypair();
let (server_pk, server_sk) = gen_keypair();
let addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
let mut listener = TcpListener::bind(&addr).await.unwrap();
let addr = listener.local_addr().unwrap();
let server = async {
let connection = listener.incoming().next().await.unwrap().unwrap();
make_server_handshake(connection, server_sk.clone()).await
};
let client = async {
let socket = TcpStream::connect(&addr).map_err(Error::from).await?;
make_client_handshake(socket, &client_pk, &client_sk, &server_pk).await
};
let res = futures::try_join!(server, client);
drop(res.unwrap())
}
}