use crate::error::TaskError;
use crypto::cipher::{EphemeralKeypair, Key, Nonce, PublicKey};
use crypto::signature::{self as sign, Signature};
use bytes::{Cursor, BytesRead, BytesWrite, BytesSeek};
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
const BASE_LEN: usize = PublicKey::LEN + Nonce::LEN * 2;
const TO_SIGN_LEN: usize = BASE_LEN + PublicKey::LEN;
const TO_SEND_LEN: usize = BASE_LEN + Signature::LEN;
const MAX_LEN: usize = const_max(TO_SIGN_LEN, TO_SEND_LEN);
const fn const_max(a: usize, b: usize) -> usize {
match a > b {
true => a,
false => b
}
}
pub(crate) struct Handshake {
pub send_key: Key,
pub recv_key: Key,
#[allow(dead_code)]
pub public_key: PublicKey
}
pub(crate) async fn server_handshake<S>(
sign_key: &sign::Keypair,
stream: &mut S
) -> Result<Handshake, TaskError>
where S: AsyncRead + AsyncWrite + Unpin {
let client_pk = {
let mut buffer = [0u8; PublicKey::LEN];
stream.read_exact(&mut buffer).await
.map_err(TaskError::Io)?;
PublicKey::from(buffer)
};
let server_kp = EphemeralKeypair::new();
let send_nonce = Nonce::new();
let recv_nonce = Nonce::new();
debug_assert_ne!(send_nonce, recv_nonce);
{
let mut buffer = Cursor::new([0u8; MAX_LEN]);
buffer.write(server_kp.public());
buffer.write(&send_nonce);
buffer.write(&recv_nonce);
buffer.write(&client_pk);
buffer.seek(0);
let sign = sign_key.sign(buffer.read(TO_SIGN_LEN));
buffer.seek(BASE_LEN);
buffer.write(sign.to_bytes());
buffer.seek(0);
stream.write_all(buffer.read(TO_SEND_LEN)).await
.map_err(TaskError::Io)?;
}
let shared_secret = server_kp.diffie_hellman(&client_pk);
let send_key = shared_secret.to_key(send_nonce);
let recv_key = shared_secret.to_key(recv_nonce);
Ok(Handshake {
send_key,
recv_key,
public_key: client_pk
})
}
pub(crate) async fn client_handshake<S>(
sign_pk: &sign::PublicKey,
stream: &mut S
) -> Result<Handshake, TaskError>
where S: AsyncRead + AsyncWrite + Unpin {
let client_kp = EphemeralKeypair::new();
stream.write_all(client_kp.public().as_ref()).await
.map_err(TaskError::Io)?;
let (server_pk, send_nonce, recv_nonce) = {
let mut buffer = Cursor::new([0u8; MAX_LEN]);
stream.read_exact(&mut buffer.as_mut()[..TO_SEND_LEN]).await
.map_err(TaskError::Io)?;
buffer.seek(BASE_LEN);
let sign = Signature::from_slice(buffer.read(Signature::LEN));
buffer.seek(BASE_LEN);
buffer.write(client_kp.public());
buffer.seek(0);
if !sign_pk.verify(buffer.read(TO_SIGN_LEN), &sign) {
return Err(TaskError::IncorrectSignature)
}
buffer.seek(0);
let server_pk = PublicKey::from_slice(
buffer.read(PublicKey::LEN)
);
let recv_nonce = Nonce::from_slice(
buffer.read(Nonce::LEN)
);
let send_nonce = Nonce::from_slice(
buffer.read(Nonce::LEN)
);
debug_assert_ne!(recv_nonce, send_nonce);
(server_pk, send_nonce, recv_nonce)
};
let shared_secret = client_kp.diffie_hellman(&server_pk);
let send_key = shared_secret.to_key(send_nonce);
let recv_key = shared_secret.to_key(recv_nonce);
Ok(Handshake {
send_key,
recv_key,
public_key: server_pk
})
}