use crate::error::TaskError;
use bytes::{BytesRead, BytesSeek, BytesWrite, Cursor};
use crypto::cipher::{EphemeralKeypair, Key, Nonce, PublicKey};
use crypto::signature::{self as sign, Signature};
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,
})
}