use std::io::{Read, Write};
use std::marker::PhantomData;
use super::WellFormed;
use super::buffers::{RecvBuffer, SendBuffer};
use super::cipher::Cipher;
use super::error::HandshakeError;
use super::handshake::HandshakeInner;
use super::hash::Hash;
use super::pattern::Pattern;
use super::process::{
do_psk, recv_e, recv_payload, recv_s, recv_to_transport, send_payload, send_s,
};
use super::role::{Initiator, Responder, Role};
use super::tokens::*;
use super::transport::Transport;
use super::{Noise, Protocol};
use crate::curve::{Curve, DhCurve};
use crate::provider::{CryptoKeyProvider, DhProvider};
const TOKEN_SCRATCH: usize = 128;
fn sync_send_e<Cu, Ci, H, CP>(
inner: &mut HandshakeInner<Cu, Ci, H, CP>,
buffer: &mut SendBuffer<'_>,
) -> Result<(), HandshakeError>
where
Cu: DhCurve,
Cu::PublicKey: AsRef<[u8]>,
Ci: Cipher,
H: Hash,
CP: DhProvider<Cu>,
{
let e = inner
.provider
.generate_ephemeral_key()
.map_err(|e| HandshakeError::Crypto(Box::new(e)))?;
let e_pub = inner
.provider
.public_key(&e)
.map_err(|e| HandshakeError::Crypto(Box::new(e)))?;
buffer.write(e_pub.as_ref());
inner.symmetric.mix_hash(e_pub.as_ref());
if inner.has_psk {
inner.symmetric.mix_key(e_pub.as_ref());
}
inner.e = Some(e);
inner.e_pub = Some(e_pub);
Ok(())
}
fn sync_do_es_initiator<Cu, Ci, H, CP>(
inner: &mut HandshakeInner<Cu, Ci, H, CP>,
) -> Result<(), HandshakeError>
where
Cu: DhCurve,
Cu::SharedSecret: AsRef<[u8]>,
Ci: Cipher,
H: Hash,
CP: DhProvider<Cu>,
{
let e = inner
.e
.as_ref()
.ok_or(HandshakeError::MissingEphemeralKey)?;
let rs = inner
.rs
.as_ref()
.ok_or(HandshakeError::MissingRemoteStatic)?;
let ss = inner
.provider
.dh(e, rs)
.map_err(|e| HandshakeError::Crypto(Box::new(e)))?;
inner.symmetric.mix_key(ss.as_ref());
Ok(())
}
fn sync_do_es_responder<Cu, Ci, H, CP>(
inner: &mut HandshakeInner<Cu, Ci, H, CP>,
) -> Result<(), HandshakeError>
where
Cu: DhCurve,
Cu::SharedSecret: AsRef<[u8]>,
Ci: Cipher,
H: Hash,
CP: DhProvider<Cu>,
{
let s = inner.s.as_ref().ok_or(HandshakeError::MissingStaticKey)?;
let re = inner
.re
.as_ref()
.ok_or(HandshakeError::MissingRemoteEphemeral)?;
let ss = inner
.provider
.dh(s, re)
.map_err(|e| HandshakeError::Crypto(Box::new(e)))?;
inner.symmetric.mix_key(ss.as_ref());
Ok(())
}
fn sync_do_ee<Cu, Ci, H, CP>(
inner: &mut HandshakeInner<Cu, Ci, H, CP>,
) -> Result<(), HandshakeError>
where
Cu: DhCurve,
Cu::SharedSecret: AsRef<[u8]>,
Ci: Cipher,
H: Hash,
CP: DhProvider<Cu>,
{
let e = inner
.e
.as_ref()
.ok_or(HandshakeError::MissingEphemeralKey)?;
let re = inner
.re
.as_ref()
.ok_or(HandshakeError::MissingRemoteEphemeral)?;
let ss = inner
.provider
.dh(e, re)
.map_err(|e| HandshakeError::Crypto(Box::new(e)))?;
inner.symmetric.mix_key(ss.as_ref());
Ok(())
}
fn sync_do_se_initiator<Cu, Ci, H, CP>(
inner: &mut HandshakeInner<Cu, Ci, H, CP>,
) -> Result<(), HandshakeError>
where
Cu: DhCurve,
Cu::SharedSecret: AsRef<[u8]>,
Ci: Cipher,
H: Hash,
CP: DhProvider<Cu>,
{
let s = inner.s.as_ref().ok_or(HandshakeError::MissingStaticKey)?;
let re = inner
.re
.as_ref()
.ok_or(HandshakeError::MissingRemoteEphemeral)?;
let ss = inner
.provider
.dh(s, re)
.map_err(|e| HandshakeError::Crypto(Box::new(e)))?;
inner.symmetric.mix_key(ss.as_ref());
Ok(())
}
fn sync_do_se_responder<Cu, Ci, H, CP>(
inner: &mut HandshakeInner<Cu, Ci, H, CP>,
) -> Result<(), HandshakeError>
where
Cu: DhCurve,
Cu::SharedSecret: AsRef<[u8]>,
Ci: Cipher,
H: Hash,
CP: DhProvider<Cu>,
{
let e = inner
.e
.as_ref()
.ok_or(HandshakeError::MissingEphemeralKey)?;
let rs = inner
.rs
.as_ref()
.ok_or(HandshakeError::MissingRemoteStatic)?;
let ss = inner
.provider
.dh(e, rs)
.map_err(|e| HandshakeError::Crypto(Box::new(e)))?;
inner.symmetric.mix_key(ss.as_ref());
Ok(())
}
fn sync_do_ss<Cu, Ci, H, CP>(
inner: &mut HandshakeInner<Cu, Ci, H, CP>,
) -> Result<(), HandshakeError>
where
Cu: DhCurve,
Cu::SharedSecret: AsRef<[u8]>,
Ci: Cipher,
H: Hash,
CP: DhProvider<Cu>,
{
let s = inner.s.as_ref().ok_or(HandshakeError::MissingStaticKey)?;
let rs = inner
.rs
.as_ref()
.ok_or(HandshakeError::MissingRemoteStatic)?;
let ss = inner
.provider
.dh(s, rs)
.map_err(|e| HandshakeError::Crypto(Box::new(e)))?;
inner.symmetric.mix_key(ss.as_ref());
Ok(())
}
fn sync_stream_e<Cu, Ci, H, CP, Io>(
inner: &mut HandshakeInner<Cu, Ci, H, CP>,
stream: &mut Io,
) -> Result<(), HandshakeError>
where
Cu: DhCurve,
Cu::PublicKey: AsRef<[u8]>,
Ci: Cipher,
H: Hash,
CP: DhProvider<Cu>,
Io: Write,
{
let mut scratch = [0u8; TOKEN_SCRATCH];
let mut buffer = SendBuffer::new(&mut scratch);
sync_send_e(inner, &mut buffer)?;
stream.write_all(buffer.finish())?;
Ok(())
}
fn sync_stream_s<Cu, Ci, H, CP, Io>(
inner: &mut HandshakeInner<Cu, Ci, H, CP>,
stream: &mut Io,
static_key: CP::PrivateKey,
) -> Result<(), HandshakeError>
where
Cu: Curve,
Cu::PublicKey: AsRef<[u8]>,
Ci: Cipher,
H: Hash,
CP: CryptoKeyProvider<Cu>,
Io: Write,
{
let mut scratch = [0u8; TOKEN_SCRATCH];
let mut buffer = SendBuffer::new(&mut scratch);
send_s(inner, &mut buffer, static_key)?;
stream.write_all(buffer.finish())?;
Ok(())
}
fn sync_read_e<Cu, Ci, H, CP, Io>(
inner: &mut HandshakeInner<Cu, Ci, H, CP>,
stream: &mut Io,
) -> Result<Cu::PublicKey, HandshakeError>
where
Cu: Curve,
Cu::PublicKey: AsRef<[u8]>,
Ci: Cipher,
H: Hash,
CP: CryptoKeyProvider<Cu>,
Io: Read,
{
let pk_size = Cu::PUBLIC_KEY_SIZE;
let mut scratch = [0u8; TOKEN_SCRATCH];
stream.read_exact(&mut scratch[..pk_size])?;
let mut buffer = RecvBuffer::new(&scratch[..pk_size]);
recv_e(inner, &mut buffer)
}
fn sync_read_s<Cu, Ci, H, CP, Io>(
inner: &mut HandshakeInner<Cu, Ci, H, CP>,
stream: &mut Io,
) -> Result<Cu::PublicKey, HandshakeError>
where
Cu: Curve,
Cu::PublicKey: AsRef<[u8]>,
Ci: Cipher,
H: Hash,
CP: CryptoKeyProvider<Cu>,
Io: Read,
{
let wire_len = if inner.symmetric.has_key() {
Cu::PUBLIC_KEY_SIZE + Ci::TAG_SIZE
} else {
Cu::PUBLIC_KEY_SIZE
};
const {
assert!(
Cu::PUBLIC_KEY_SIZE + Ci::TAG_SIZE <= TOKEN_SCRATCH,
"curve public key + AEAD tag exceeds the 128-byte scratch buffer"
)
};
let mut scratch = [0u8; TOKEN_SCRATCH];
stream.read_exact(&mut scratch[..wire_len])?;
let mut buffer = RecvBuffer::new(&scratch[..wire_len]);
recv_s(inner, &mut buffer)
}
fn send_message_tail<Cu, Ci, H, CP, Io>(
inner: &mut HandshakeInner<Cu, Ci, H, CP>,
stream: &mut Io,
) -> Result<(), HandshakeError>
where
Cu: Curve,
Ci: Cipher,
H: Hash,
CP: CryptoKeyProvider<Cu>,
Io: Write,
{
let tag_len = if inner.symmetric.has_key() {
Ci::TAG_SIZE
} else {
0
};
let mut scratch = [0u8; TOKEN_SCRATCH];
let mut buffer = SendBuffer::new(&mut scratch[..tag_len]);
send_payload(inner, &mut buffer)?;
stream.write_all(buffer.finish())?;
stream.flush()?;
Ok(())
}
fn recv_message_tail<Cu, Ci, H, CP, Io>(
inner: &mut HandshakeInner<Cu, Ci, H, CP>,
stream: &mut Io,
) -> Result<(), HandshakeError>
where
Cu: Curve,
Ci: Cipher,
H: Hash,
CP: CryptoKeyProvider<Cu>,
Io: Read,
{
let tag_len = if inner.symmetric.has_key() {
Ci::TAG_SIZE
} else {
0
};
let mut scratch = [0u8; TOKEN_SCRATCH];
stream.read_exact(&mut scratch[..tag_len])?;
let mut buffer = RecvBuffer::new(&scratch[..tag_len]);
recv_payload(inner, &mut buffer)
}
pub struct SyncHandshake<Proto, R, Stage, Msgs, CP, Io>
where
Proto: Protocol,
CP: DhProvider<Proto::Curve>,
{
inner: HandshakeInner<Proto::Curve, Proto::Cipher, Proto::Hash, CP>,
stream: Io,
_marker: PhantomData<fn() -> (Proto, R, Stage, Msgs)>,
}
pub struct SyncSending<Proto, R, Tokens, MsgRest, CP, Io>
where
Proto: Protocol,
CP: DhProvider<Proto::Curve>,
{
inner: HandshakeInner<Proto::Curve, Proto::Cipher, Proto::Hash, CP>,
stream: Io,
_marker: PhantomData<fn() -> (Proto, R, Tokens, MsgRest)>,
}
pub struct SyncReceiving<Proto, R, Tokens, MsgRest, CP, Io>
where
Proto: Protocol,
CP: DhProvider<Proto::Curve>,
{
inner: HandshakeInner<Proto::Curve, Proto::Cipher, Proto::Hash, CP>,
stream: Io,
_marker: PhantomData<fn() -> (Proto, R, Tokens, MsgRest)>,
}
pub struct SyncTransport<Proto: Protocol, Io> {
transport: Transport<Proto>,
stream: Io,
}
impl<Proto: Protocol, Io> SyncTransport<Proto, Io> {
pub fn transport(&mut self) -> &mut Transport<Proto> {
&mut self.transport
}
pub fn stream(&mut self) -> &mut Io {
&mut self.stream
}
pub fn into_parts(self) -> (Transport<Proto>, Io) {
(self.transport, self.stream)
}
}
impl<Proto, CP, Io>
SyncHandshake<
Proto,
Initiator,
<Proto::Pattern as Pattern>::PreMessages,
<Proto::Pattern as Pattern>::Messages,
CP,
Io,
>
where
Proto: Protocol,
CP: DhProvider<Proto::Curve>,
{
pub fn initiate(provider: CP, prologue: &[u8], stream: Io) -> Self {
SyncHandshake {
inner: HandshakeInner::new::<Proto>(provider, prologue),
stream,
_marker: PhantomData,
}
}
}
impl<Proto, CP, Io>
SyncHandshake<
Proto,
Responder,
<Proto::Pattern as Pattern>::PreMessages,
<Proto::Pattern as Pattern>::Messages,
CP,
Io,
>
where
Proto: Protocol,
CP: DhProvider<Proto::Curve>,
{
pub fn respond(provider: CP, prologue: &[u8], stream: Io) -> Self {
SyncHandshake {
inner: HandshakeInner::new::<Proto>(provider, prologue),
stream,
_marker: PhantomData,
}
}
}
impl<P: WellFormed, Cu: DhCurve, Ci: Cipher, H: Hash> Noise<P, Cu, Ci, H> {
pub fn sync_initiator<CP, Io>(
provider: CP,
prologue: &[u8],
stream: Io,
) -> SyncHandshake<Self, Initiator, P::PreMessages, P::Messages, CP, Io>
where
CP: DhProvider<Cu>,
{
SyncHandshake::initiate(provider, prologue, stream)
}
pub fn sync_responder<CP, Io>(
provider: CP,
prologue: &[u8],
stream: Io,
) -> SyncHandshake<Self, Responder, P::PreMessages, P::Messages, CP, Io>
where
CP: DhProvider<Cu>,
{
SyncHandshake::respond(provider, prologue, stream)
}
}
impl<Proto, Tokens, Rest, Msgs, CP, Io>
SyncHandshake<Proto, Initiator, Cons<Message<ToInitiator, Tokens>, Rest>, Msgs, CP, Io>
where
Proto: Protocol,
CP: DhProvider<Proto::Curve>,
<Proto::Curve as Curve>::PublicKey: AsRef<[u8]>,
{
pub fn set_rs(
mut self,
remote_static: <Proto::Curve as Curve>::PublicKey,
) -> SyncHandshake<Proto, Initiator, Rest, Msgs, CP, Io> {
self.inner.symmetric.mix_hash(remote_static.as_ref());
self.inner.rs = Some(remote_static);
SyncHandshake {
inner: self.inner,
stream: self.stream,
_marker: PhantomData,
}
}
}
impl<Proto, Tokens, Rest, Msgs, CP, Io>
SyncHandshake<Proto, Responder, Cons<Message<ToInitiator, Tokens>, Rest>, Msgs, CP, Io>
where
Proto: Protocol,
CP: DhProvider<Proto::Curve>,
<Proto::Curve as Curve>::PublicKey: AsRef<[u8]>,
{
pub fn set_s(
mut self,
static_key: CP::PrivateKey,
) -> Result<SyncHandshake<Proto, Responder, Rest, Msgs, CP, Io>, HandshakeError> {
let s_pub = self
.inner
.provider
.public_key(&static_key)
.map_err(|e| HandshakeError::Crypto(Box::new(e)))?;
self.inner.symmetric.mix_hash(s_pub.as_ref());
self.inner.s_pub = Some(s_pub);
self.inner.s = Some(static_key);
Ok(SyncHandshake {
inner: self.inner,
stream: self.stream,
_marker: PhantomData,
})
}
}
impl<Proto, Tokens, Rest, Msgs, CP, Io>
SyncHandshake<Proto, Initiator, Cons<Message<ToResponder, Tokens>, Rest>, Msgs, CP, Io>
where
Proto: Protocol,
CP: DhProvider<Proto::Curve>,
<Proto::Curve as Curve>::PublicKey: AsRef<[u8]>,
{
pub fn set_s(
mut self,
static_key: CP::PrivateKey,
) -> Result<SyncHandshake<Proto, Initiator, Rest, Msgs, CP, Io>, HandshakeError> {
let s_pub = self
.inner
.provider
.public_key(&static_key)
.map_err(|e| HandshakeError::Crypto(Box::new(e)))?;
self.inner.symmetric.mix_hash(s_pub.as_ref());
self.inner.s_pub = Some(s_pub);
self.inner.s = Some(static_key);
Ok(SyncHandshake {
inner: self.inner,
stream: self.stream,
_marker: PhantomData,
})
}
}
impl<Proto, Tokens, Rest, Msgs, CP, Io>
SyncHandshake<Proto, Responder, Cons<Message<ToResponder, Tokens>, Rest>, Msgs, CP, Io>
where
Proto: Protocol,
CP: DhProvider<Proto::Curve>,
<Proto::Curve as Curve>::PublicKey: AsRef<[u8]>,
{
pub fn set_rs(
mut self,
remote_static: <Proto::Curve as Curve>::PublicKey,
) -> SyncHandshake<Proto, Responder, Rest, Msgs, CP, Io> {
self.inner.symmetric.mix_hash(remote_static.as_ref());
self.inner.rs = Some(remote_static);
SyncHandshake {
inner: self.inner,
stream: self.stream,
_marker: PhantomData,
}
}
}
impl<Proto, R, Next, More, MsgRest, Dir, CP, Io>
SyncHandshake<Proto, R, Nil, Cons<Message<Dir, Cons<E, Cons<Next, More>>>, MsgRest>, CP, Io>
where
Proto: Protocol,
R: Role<SendDir = Dir>,
CP: DhProvider<Proto::Curve>,
<Proto::Curve as Curve>::PublicKey: AsRef<[u8]>,
Io: Write,
{
pub fn e(
mut self,
) -> Result<SyncSending<Proto, R, Cons<Next, More>, MsgRest, CP, Io>, HandshakeError> {
sync_stream_e(&mut self.inner, &mut self.stream)?;
Ok(SyncSending {
inner: self.inner,
stream: self.stream,
_marker: PhantomData,
})
}
}
impl<Proto, R, NextMsg, MoreMsgs, Dir, CP, Io>
SyncHandshake<Proto, R, Nil, Cons<Message<Dir, Cons<E, Nil>>, Cons<NextMsg, MoreMsgs>>, CP, Io>
where
Proto: Protocol,
R: Role<SendDir = Dir>,
CP: DhProvider<Proto::Curve>,
<Proto::Curve as Curve>::PublicKey: AsRef<[u8]>,
Io: Write,
{
pub fn e(
mut self,
) -> Result<SyncHandshake<Proto, R, Nil, Cons<NextMsg, MoreMsgs>, CP, Io>, HandshakeError> {
sync_stream_e(&mut self.inner, &mut self.stream)?;
send_message_tail(&mut self.inner, &mut self.stream)?;
Ok(SyncHandshake {
inner: self.inner,
stream: self.stream,
_marker: PhantomData,
})
}
}
impl<Proto, R, Tokens, MsgRest, Dir, CP, Io>
SyncHandshake<Proto, R, Nil, Cons<Message<Dir, Cons<Psk, Tokens>>, MsgRest>, CP, Io>
where
Proto: Protocol,
R: Role<SendDir = Dir>,
CP: DhProvider<Proto::Curve>,
<Proto::Curve as Curve>::PublicKey: AsRef<[u8]>,
{
pub fn psk(
mut self,
psk_key: &crate::psk::Psk,
) -> Result<SyncSending<Proto, R, Tokens, MsgRest, CP, Io>, HandshakeError> {
do_psk(&mut self.inner, psk_key)?;
Ok(SyncSending {
inner: self.inner,
stream: self.stream,
_marker: PhantomData,
})
}
}
impl<Proto, R, Tokens, MsgRest, Dir, CP, Io>
SyncHandshake<Proto, R, Nil, Cons<Message<Dir, Cons<S, Tokens>>, MsgRest>, CP, Io>
where
Proto: Protocol,
R: Role<SendDir = Dir>,
CP: DhProvider<Proto::Curve>,
<Proto::Curve as Curve>::PublicKey: AsRef<[u8]>,
Io: Write,
{
pub fn s(
mut self,
static_key: CP::PrivateKey,
) -> Result<SyncSending<Proto, R, Tokens, MsgRest, CP, Io>, HandshakeError> {
sync_stream_s(&mut self.inner, &mut self.stream, static_key)?;
Ok(SyncSending {
inner: self.inner,
stream: self.stream,
_marker: PhantomData,
})
}
}
impl<Proto, R, Tokens, Rest, Dir, CP, Io>
SyncHandshake<Proto, R, Nil, Cons<Message<Dir, Tokens>, Rest>, CP, Io>
where
Proto: Protocol,
R: Role<RecvDir = Dir>,
CP: DhProvider<Proto::Curve>,
{
pub fn recv(self) -> SyncReceiving<Proto, R, Tokens, Rest, CP, Io> {
SyncReceiving {
inner: self.inner,
stream: self.stream,
_marker: PhantomData,
}
}
}
macro_rules! sync_send_token {
(
role: $R:ty,
token: $Token:ty,
method: $method:ident ($($arg:ident : $arg_ty:ty),*),
bounds: [$($extra:tt)*],
doc: $doc:expr,
body: |$inner:ident, $stream:ident| { $($logic:tt)* }
) => {
impl<Proto, Next, More, MsgRest, CP, Io>
SyncSending<Proto, $R, Cons<$Token, Cons<Next, More>>, MsgRest, CP, Io>
where
Proto: Protocol,
<Proto::Curve as Curve>::PublicKey: AsRef<[u8]>,
CP: DhProvider<Proto::Curve>,
Io: Write,
$($extra)*
{
#[doc = $doc]
pub fn $method(
mut self, $($arg: $arg_ty,)*
) -> Result<SyncSending<Proto, $R, Cons<Next, More>, MsgRest, CP, Io>, HandshakeError> {
{
let $inner = &mut self.inner;
let $stream = &mut self.stream;
$($logic)*
}
Ok(SyncSending { inner: self.inner, stream: self.stream, _marker: PhantomData })
}
}
impl<Proto, NextMsg, MoreMsgs, CP, Io>
SyncSending<Proto, $R, Cons<$Token, Nil>, Cons<NextMsg, MoreMsgs>, CP, Io>
where
Proto: Protocol,
<Proto::Curve as Curve>::PublicKey: AsRef<[u8]>,
CP: DhProvider<Proto::Curve>,
Io: Write,
$($extra)*
{
#[doc = $doc]
pub fn $method(
mut self, $($arg: $arg_ty,)*
) -> Result<SyncHandshake<Proto, $R, Nil, Cons<NextMsg, MoreMsgs>, CP, Io>, HandshakeError> {
{
let $inner = &mut self.inner;
let $stream = &mut self.stream;
$($logic)*
}
send_message_tail(&mut self.inner, &mut self.stream)?;
Ok(SyncHandshake { inner: self.inner, stream: self.stream, _marker: PhantomData })
}
}
impl<Proto, CP, Io>
SyncSending<Proto, $R, Cons<$Token, Nil>, Nil, CP, Io>
where
Proto: Protocol,
<Proto::Curve as Curve>::PublicKey: AsRef<[u8]>,
CP: DhProvider<Proto::Curve>,
Io: Write,
$($extra)*
{
#[doc = $doc]
pub fn $method(
mut self, $($arg: $arg_ty,)*
) -> Result<SyncTransport<Proto, Io>, HandshakeError> {
{
let $inner = &mut self.inner;
let $stream = &mut self.stream;
$($logic)*
}
send_message_tail(&mut self.inner, &mut self.stream)?;
let transport = recv_to_transport::<Proto, $R, CP>(self.inner);
Ok(SyncTransport { transport, stream: self.stream })
}
}
};
}
macro_rules! sync_recv_token {
(
role: $R:ty,
token: $Token:ty,
method: $method:ident ($($arg:ident : $arg_ty:ty),*),
bounds: [$($extra:tt)*],
doc: $doc:expr,
body: |$inner:ident, $stream:ident| { $($logic:tt)* }
) => {
impl<Proto, Next, More, MsgRest, CP, Io>
SyncReceiving<Proto, $R, Cons<$Token, Cons<Next, More>>, MsgRest, CP, Io>
where
Proto: Protocol,
<Proto::Curve as Curve>::PublicKey: AsRef<[u8]>,
CP: DhProvider<Proto::Curve>,
Io: Read,
$($extra)*
{
#[doc = $doc]
pub fn $method(
mut self, $($arg: $arg_ty,)*
) -> Result<SyncReceiving<Proto, $R, Cons<Next, More>, MsgRest, CP, Io>, HandshakeError> {
{
let $inner = &mut self.inner;
let $stream = &mut self.stream;
$($logic)*
}
Ok(SyncReceiving { inner: self.inner, stream: self.stream, _marker: PhantomData })
}
}
impl<Proto, NextMsg, MoreMsgs, CP, Io>
SyncReceiving<Proto, $R, Cons<$Token, Nil>, Cons<NextMsg, MoreMsgs>, CP, Io>
where
Proto: Protocol,
<Proto::Curve as Curve>::PublicKey: AsRef<[u8]>,
CP: DhProvider<Proto::Curve>,
Io: Read,
$($extra)*
{
#[doc = $doc]
pub fn $method(
mut self, $($arg: $arg_ty,)*
) -> Result<SyncHandshake<Proto, $R, Nil, Cons<NextMsg, MoreMsgs>, CP, Io>, HandshakeError> {
{
let $inner = &mut self.inner;
let $stream = &mut self.stream;
$($logic)*
}
recv_message_tail(&mut self.inner, &mut self.stream)?;
Ok(SyncHandshake { inner: self.inner, stream: self.stream, _marker: PhantomData })
}
}
impl<Proto, CP, Io>
SyncReceiving<Proto, $R, Cons<$Token, Nil>, Nil, CP, Io>
where
Proto: Protocol,
<Proto::Curve as Curve>::PublicKey: AsRef<[u8]>,
CP: DhProvider<Proto::Curve>,
Io: Read,
$($extra)*
{
#[doc = $doc]
pub fn $method(
mut self, $($arg: $arg_ty,)*
) -> Result<SyncTransport<Proto, Io>, HandshakeError> {
{
let $inner = &mut self.inner;
let $stream = &mut self.stream;
$($logic)*
}
recv_message_tail(&mut self.inner, &mut self.stream)?;
let transport = recv_to_transport::<Proto, $R, CP>(self.inner);
Ok(SyncTransport { transport, stream: self.stream })
}
}
};
}
macro_rules! sync_recv_reveal_token {
(
role: $R:ty,
token: $Token:ty,
method: $method:ident ($($arg:ident : $arg_ty:ty),*),
bounds: [$($extra:tt)*],
doc: $doc:expr,
body: |$inner:ident, $stream:ident| { $($logic:tt)* }
) => {
impl<Proto, Next, More, MsgRest, CP, Io>
SyncReceiving<Proto, $R, Cons<$Token, Cons<Next, More>>, MsgRest, CP, Io>
where
Proto: Protocol,
<Proto::Curve as Curve>::PublicKey: AsRef<[u8]>,
CP: DhProvider<Proto::Curve>,
Io: Read,
$($extra)*
{
#[doc = $doc]
#[allow(clippy::type_complexity)]
pub fn $method(
mut self, $($arg: $arg_ty,)*
) -> Result<(<Proto::Curve as Curve>::PublicKey, SyncReceiving<Proto, $R, Cons<Next, More>, MsgRest, CP, Io>), HandshakeError> {
let revealed = {
let $inner = &mut self.inner;
let $stream = &mut self.stream;
$($logic)*
};
Ok((revealed, SyncReceiving { inner: self.inner, stream: self.stream, _marker: PhantomData }))
}
}
impl<Proto, NextMsg, MoreMsgs, CP, Io>
SyncReceiving<Proto, $R, Cons<$Token, Nil>, Cons<NextMsg, MoreMsgs>, CP, Io>
where
Proto: Protocol,
<Proto::Curve as Curve>::PublicKey: AsRef<[u8]>,
CP: DhProvider<Proto::Curve>,
Io: Read,
$($extra)*
{
#[doc = $doc]
#[allow(clippy::type_complexity)]
pub fn $method(
mut self, $($arg: $arg_ty,)*
) -> Result<(<Proto::Curve as Curve>::PublicKey, SyncHandshake<Proto, $R, Nil, Cons<NextMsg, MoreMsgs>, CP, Io>), HandshakeError> {
let revealed = {
let $inner = &mut self.inner;
let $stream = &mut self.stream;
$($logic)*
};
recv_message_tail(&mut self.inner, &mut self.stream)?;
Ok((revealed, SyncHandshake { inner: self.inner, stream: self.stream, _marker: PhantomData }))
}
}
impl<Proto, CP, Io>
SyncReceiving<Proto, $R, Cons<$Token, Nil>, Nil, CP, Io>
where
Proto: Protocol,
<Proto::Curve as Curve>::PublicKey: AsRef<[u8]>,
CP: DhProvider<Proto::Curve>,
Io: Read,
$($extra)*
{
#[doc = $doc]
#[allow(clippy::type_complexity)]
pub fn $method(
mut self, $($arg: $arg_ty,)*
) -> Result<(<Proto::Curve as Curve>::PublicKey, SyncTransport<Proto, Io>), HandshakeError> {
let revealed = {
let $inner = &mut self.inner;
let $stream = &mut self.stream;
$($logic)*
};
recv_message_tail(&mut self.inner, &mut self.stream)?;
let transport = recv_to_transport::<Proto, $R, CP>(self.inner);
Ok((revealed, SyncTransport { transport, stream: self.stream }))
}
}
};
}
sync_send_token! {
role: Initiator, token: E, method: e(), bounds: [],
doc: "Process the `e` token: generate a fresh ephemeral key, write its \
public key to the wire, and mix it into the handshake hash (also \
mixing it into the chaining key in a PSK pattern).",
body: |inner, stream| { sync_stream_e(inner, stream)?; }
}
sync_send_token! {
role: Responder, token: E, method: e(), bounds: [],
doc: "Process the `e` token: generate a fresh ephemeral key, write its \
public key to the wire, and mix it into the handshake hash (also \
mixing it into the chaining key in a PSK pattern).",
body: |inner, stream| { sync_stream_e(inner, stream)?; }
}
sync_recv_reveal_token! {
role: Initiator, token: E, method: e(), bounds: [],
doc: "Process the `e` token: read the peer's ephemeral public key from \
the wire and mix it into the handshake hash (also mixing it into \
the chaining key in a PSK pattern). Returns the revealed key.",
body: |inner, stream| { sync_read_e(inner, stream)? }
}
sync_recv_reveal_token! {
role: Responder, token: E, method: e(), bounds: [],
doc: "Process the `e` token: read the peer's ephemeral public key from \
the wire and mix it into the handshake hash (also mixing it into \
the chaining key in a PSK pattern). Returns the revealed key.",
body: |inner, stream| { sync_read_e(inner, stream)? }
}
sync_send_token! {
role: Initiator, token: S, method: s(static_key: CP::PrivateKey), bounds: [],
doc: "Process the `s` token: write our local static public key to the \
wire — encrypted once a key has been established by a prior DH \
token — and mix it into the handshake hash.",
body: |inner, stream| { sync_stream_s(inner, stream, static_key)?; }
}
sync_send_token! {
role: Responder, token: S, method: s(static_key: CP::PrivateKey), bounds: [],
doc: "Process the `s` token: write our local static public key to the \
wire — encrypted once a key has been established by a prior DH \
token — and mix it into the handshake hash.",
body: |inner, stream| { sync_stream_s(inner, stream, static_key)?; }
}
sync_recv_reveal_token! {
role: Initiator, token: S, method: s(), bounds: [],
doc: "Process the `s` token: read the peer's static public key from the \
wire — decrypting it once a key has been established by a prior DH \
token — and mix it into the handshake hash. Returns the revealed key.",
body: |inner, stream| { sync_read_s(inner, stream)? }
}
sync_recv_reveal_token! {
role: Responder, token: S, method: s(), bounds: [],
doc: "Process the `s` token: read the peer's static public key from the \
wire — decrypting it once a key has been established by a prior DH \
token — and mix it into the handshake hash. Returns the revealed key.",
body: |inner, stream| { sync_read_s(inner, stream)? }
}
sync_send_token! {
role: Initiator, token: Ee, method: ee(), bounds: [<Proto::Curve as DhCurve>::SharedSecret: AsRef<[u8]>,],
doc: "Process the `ee` token: perform the Diffie–Hellman between our \
local ephemeral and the remote ephemeral, and mix the shared \
secret into the chaining key. Writes nothing to the wire; \
subsequent payloads are encrypted under the advanced key.",
body: |inner, _stream| { sync_do_ee(inner)?; }
}
sync_send_token! {
role: Responder, token: Ee, method: ee(), bounds: [<Proto::Curve as DhCurve>::SharedSecret: AsRef<[u8]>,],
doc: "Process the `ee` token: perform the Diffie–Hellman between our \
local ephemeral and the remote ephemeral, and mix the shared \
secret into the chaining key. Writes nothing to the wire; \
subsequent payloads are encrypted under the advanced key.",
body: |inner, _stream| { sync_do_ee(inner)?; }
}
sync_recv_token! {
role: Initiator, token: Ee, method: ee(), bounds: [<Proto::Curve as DhCurve>::SharedSecret: AsRef<[u8]>,],
doc: "Process the `ee` token: perform the Diffie–Hellman between our \
local ephemeral and the remote ephemeral, and mix the shared \
secret into the chaining key. Reads nothing from the wire; \
subsequent payloads are decrypted under the advanced key.",
body: |inner, _stream| { sync_do_ee(inner)?; }
}
sync_recv_token! {
role: Responder, token: Ee, method: ee(), bounds: [<Proto::Curve as DhCurve>::SharedSecret: AsRef<[u8]>,],
doc: "Process the `ee` token: perform the Diffie–Hellman between our \
local ephemeral and the remote ephemeral, and mix the shared \
secret into the chaining key. Reads nothing from the wire; \
subsequent payloads are decrypted under the advanced key.",
body: |inner, _stream| { sync_do_ee(inner)?; }
}
sync_send_token! {
role: Initiator, token: Es, method: es(), bounds: [<Proto::Curve as DhCurve>::SharedSecret: AsRef<[u8]>,],
doc: "Process the `es` token (initiator): perform the Diffie–Hellman \
between our local ephemeral and the remote static, and mix the \
shared secret into the chaining key. Writes nothing to the wire; \
subsequent payloads are encrypted under the advanced key.",
body: |inner, _stream| { sync_do_es_initiator(inner)?; }
}
sync_recv_token! {
role: Initiator, token: Es, method: es(), bounds: [<Proto::Curve as DhCurve>::SharedSecret: AsRef<[u8]>,],
doc: "Process the `es` token (initiator): perform the Diffie–Hellman \
between our local ephemeral and the remote static, and mix the \
shared secret into the chaining key. Reads nothing from the wire; \
subsequent payloads are decrypted under the advanced key.",
body: |inner, _stream| { sync_do_es_initiator(inner)?; }
}
sync_send_token! {
role: Responder, token: Es, method: es(), bounds: [<Proto::Curve as DhCurve>::SharedSecret: AsRef<[u8]>,],
doc: "Process the `es` token (responder): perform the Diffie–Hellman \
between our local static and the remote ephemeral, and mix the \
shared secret into the chaining key. Writes nothing to the wire; \
subsequent payloads are encrypted under the advanced key.",
body: |inner, _stream| { sync_do_es_responder(inner)?; }
}
sync_recv_token! {
role: Responder, token: Es, method: es(), bounds: [<Proto::Curve as DhCurve>::SharedSecret: AsRef<[u8]>,],
doc: "Process the `es` token (responder): perform the Diffie–Hellman \
between our local static and the remote ephemeral, and mix the \
shared secret into the chaining key. Reads nothing from the wire; \
subsequent payloads are decrypted under the advanced key.",
body: |inner, _stream| { sync_do_es_responder(inner)?; }
}
sync_send_token! {
role: Initiator, token: Se, method: se(), bounds: [<Proto::Curve as DhCurve>::SharedSecret: AsRef<[u8]>,],
doc: "Process the `se` token (initiator): perform the Diffie–Hellman \
between our local static and the remote ephemeral, and mix the \
shared secret into the chaining key. Writes nothing to the wire; \
subsequent payloads are encrypted under the advanced key.",
body: |inner, _stream| { sync_do_se_initiator(inner)?; }
}
sync_recv_token! {
role: Initiator, token: Se, method: se(), bounds: [<Proto::Curve as DhCurve>::SharedSecret: AsRef<[u8]>,],
doc: "Process the `se` token (initiator): perform the Diffie–Hellman \
between our local static and the remote ephemeral, and mix the \
shared secret into the chaining key. Reads nothing from the wire; \
subsequent payloads are decrypted under the advanced key.",
body: |inner, _stream| { sync_do_se_initiator(inner)?; }
}
sync_send_token! {
role: Responder, token: Se, method: se(), bounds: [<Proto::Curve as DhCurve>::SharedSecret: AsRef<[u8]>,],
doc: "Process the `se` token (responder): perform the Diffie–Hellman \
between our local ephemeral and the remote static, and mix the \
shared secret into the chaining key. Writes nothing to the wire; \
subsequent payloads are encrypted under the advanced key.",
body: |inner, _stream| { sync_do_se_responder(inner)?; }
}
sync_recv_token! {
role: Responder, token: Se, method: se(), bounds: [<Proto::Curve as DhCurve>::SharedSecret: AsRef<[u8]>,],
doc: "Process the `se` token (responder): perform the Diffie–Hellman \
between our local ephemeral and the remote static, and mix the \
shared secret into the chaining key. Reads nothing from the wire; \
subsequent payloads are decrypted under the advanced key.",
body: |inner, _stream| { sync_do_se_responder(inner)?; }
}
sync_send_token! {
role: Initiator, token: Ss, method: ss(), bounds: [<Proto::Curve as DhCurve>::SharedSecret: AsRef<[u8]>,],
doc: "Process the `ss` token: perform the Diffie–Hellman between our \
local static and the remote static, and mix the shared secret \
into the chaining key. Writes nothing to the wire; subsequent \
payloads are encrypted under the advanced key.",
body: |inner, _stream| { sync_do_ss(inner)?; }
}
sync_send_token! {
role: Responder, token: Ss, method: ss(), bounds: [<Proto::Curve as DhCurve>::SharedSecret: AsRef<[u8]>,],
doc: "Process the `ss` token: perform the Diffie–Hellman between our \
local static and the remote static, and mix the shared secret \
into the chaining key. Writes nothing to the wire; subsequent \
payloads are encrypted under the advanced key.",
body: |inner, _stream| { sync_do_ss(inner)?; }
}
sync_recv_token! {
role: Initiator, token: Ss, method: ss(), bounds: [<Proto::Curve as DhCurve>::SharedSecret: AsRef<[u8]>,],
doc: "Process the `ss` token: perform the Diffie–Hellman between our \
local static and the remote static, and mix the shared secret \
into the chaining key. Reads nothing from the wire; subsequent \
payloads are decrypted under the advanced key.",
body: |inner, _stream| { sync_do_ss(inner)?; }
}
sync_recv_token! {
role: Responder, token: Ss, method: ss(), bounds: [<Proto::Curve as DhCurve>::SharedSecret: AsRef<[u8]>,],
doc: "Process the `ss` token: perform the Diffie–Hellman between our \
local static and the remote static, and mix the shared secret \
into the chaining key. Reads nothing from the wire; subsequent \
payloads are decrypted under the advanced key.",
body: |inner, _stream| { sync_do_ss(inner)?; }
}
sync_send_token! {
role: Initiator, token: Psk, method: psk(psk_key: &crate::psk::Psk), bounds: [],
doc: "Process the `psk` token: mix the 32-byte pre-shared key into both \
the chaining key and the handshake hash (Noise's `MixKeyAndHash`). \
Writes nothing to the wire; subsequent payloads are encrypted \
under the advanced key.",
body: |inner, _stream| { do_psk(inner, psk_key)?; }
}
sync_send_token! {
role: Responder, token: Psk, method: psk(psk_key: &crate::psk::Psk), bounds: [],
doc: "Process the `psk` token: mix the 32-byte pre-shared key into both \
the chaining key and the handshake hash (Noise's `MixKeyAndHash`). \
Writes nothing to the wire; subsequent payloads are encrypted \
under the advanced key.",
body: |inner, _stream| { do_psk(inner, psk_key)?; }
}
sync_recv_token! {
role: Initiator, token: Psk, method: psk(psk_key: &crate::psk::Psk), bounds: [],
doc: "Process the `psk` token: mix the 32-byte pre-shared key into both \
the chaining key and the handshake hash (Noise's `MixKeyAndHash`). \
Reads nothing from the wire; subsequent payloads are decrypted \
under the advanced key.",
body: |inner, _stream| { do_psk(inner, psk_key)?; }
}
sync_recv_token! {
role: Responder, token: Psk, method: psk(psk_key: &crate::psk::Psk), bounds: [],
doc: "Process the `psk` token: mix the 32-byte pre-shared key into both \
the chaining key and the handshake hash (Noise's `MixKeyAndHash`). \
Reads nothing from the wire; subsequent payloads are decrypted \
under the advanced key.",
body: |inner, _stream| { do_psk(inner, psk_key)?; }
}
#[cfg(test)]
mod tests {
use super::*;
use crate::noise::{Blake2b, ChaChaPoly, Initiator, Noise, P256, Responder, pattern};
use crate::provider::EphemeralOnly;
use crate::provider::ProviderExt;
use crate::psk::Psk;
use rand::{SeedableRng, rngs::StdRng};
use std::cell::RefCell;
use std::collections::VecDeque;
use std::io::Cursor;
use std::rc::Rc;
type Seal = Noise<pattern::N, P256, ChaChaPoly, Blake2b>;
type Channel = Noise<pattern::IKpsk1, P256, ChaChaPoly, Blake2b>;
type NoiseK = Noise<pattern::K, P256, ChaChaPoly, Blake2b>;
#[derive(Clone)]
struct Pipe {
inbound: Rc<RefCell<VecDeque<u8>>>,
outbound: Rc<RefCell<VecDeque<u8>>>,
}
impl std::io::Read for Pipe {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let mut q = self.inbound.borrow_mut();
let n = q.len().min(buf.len());
for slot in buf.iter_mut().take(n) {
*slot = q.pop_front().unwrap();
}
Ok(n)
}
}
impl std::io::Write for Pipe {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.outbound.borrow_mut().extend(buf.iter().copied());
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
#[test]
fn n_sync_seal_open_roundtrip() {
let mut provider = EphemeralOnly::new(StdRng::from_os_rng());
let recipient_static = provider.generate::<P256>().unwrap();
let recipient_pub = provider.public(&recipient_static).unwrap();
let sealer = SyncHandshake::<Seal, Initiator, _, _, _, _>::initiate(
EphemeralOnly::new(StdRng::from_os_rng()),
&[],
Vec::<u8>::new(),
)
.set_rs(recipient_pub);
let sealer_done = sealer.e().unwrap().es().unwrap();
let (mut send_transport, wire) = sealer_done.into_parts();
assert_eq!(wire.len(), 81);
let payload = [0x42u8; 32];
let mut sealed = [0u8; 48];
let sealed_len = send_transport.send(&payload, &mut sealed).unwrap();
let opener = SyncHandshake::<Seal, Responder, _, _, _, _>::respond(
EphemeralOnly::new(StdRng::from_os_rng()),
&[],
Cursor::new(wire),
)
.set_s(recipient_static)
.unwrap();
let (_revealed_e, recv) = opener.recv().e().unwrap();
let mut recv_transport = recv.es().unwrap();
assert_eq!(
send_transport.session_id(),
recv_transport.transport().session_id()
);
let mut opened = [0u8; 32];
let opened_len = recv_transport
.transport()
.receive(&sealed[..sealed_len], &mut opened)
.unwrap();
assert_eq!(opened_len, 32);
assert_eq!(opened, payload);
}
#[test]
fn n_sync_constructors_roundtrip() {
type N = Seal;
let mut provider = EphemeralOnly::new(StdRng::from_os_rng());
let recipient_static = provider.generate::<P256>().unwrap();
let recipient_pub = provider.public(&recipient_static).unwrap();
let sealer = N::sync_initiator(
EphemeralOnly::new(StdRng::from_os_rng()),
&[],
Vec::<u8>::new(),
)
.set_rs(recipient_pub);
let (mut send_transport, wire) = sealer.e().unwrap().es().unwrap().into_parts();
assert_eq!(wire.len(), 81);
let payload = [0x42u8; 32];
let mut sealed = [0u8; 48];
let sealed_len = send_transport.send(&payload, &mut sealed).unwrap();
let opener = N::sync_responder(
EphemeralOnly::new(StdRng::from_os_rng()),
&[],
Cursor::new(wire),
)
.set_s(recipient_static)
.unwrap();
let (_e, recv) = opener.recv().e().unwrap();
let mut recv_transport = recv.es().unwrap();
let mut opened = [0u8; 32];
let opened_len = recv_transport
.transport()
.receive(&sealed[..sealed_len], &mut opened)
.unwrap();
assert_eq!(opened_len, 32);
assert_eq!(opened, payload);
}
#[test]
fn n_sync_tampered_ephemeral_rejected() {
let mut provider = EphemeralOnly::new(StdRng::from_os_rng());
let recipient_static = provider.generate::<P256>().unwrap();
let recipient_pub = provider.public(&recipient_static).unwrap();
let sealer = SyncHandshake::<Seal, Initiator, _, _, _, _>::initiate(
EphemeralOnly::new(StdRng::from_os_rng()),
&[],
Vec::<u8>::new(),
)
.set_rs(recipient_pub);
let (_t, mut wire) = sealer.e().unwrap().es().unwrap().into_parts();
wire[1] ^= 0xFF;
let opener = SyncHandshake::<Seal, Responder, _, _, _, _>::respond(
EphemeralOnly::new(StdRng::from_os_rng()),
&[],
Cursor::new(wire),
)
.set_s(recipient_static)
.unwrap();
match opener.recv().e() {
Err(_) => {}
Ok((_e, recv)) => assert!(recv.es().is_err()),
}
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[test]
fn n_sync_seal_open_with_secure_enclave_provider() {
use crate::provider::apple::AppleSecureEnclave;
let mut provider = AppleSecureEnclave::new("uk.co.example.hiss-test");
let recipient_static = provider.generate_ephemeral::<P256>().unwrap();
let recipient_pub = provider.public(&recipient_static).unwrap();
let sealer = SyncHandshake::<Seal, Initiator, _, _, _, _>::initiate(
provider.clone(),
&[],
Vec::<u8>::new(),
)
.set_rs(recipient_pub);
let (mut send_transport, wire) = sealer.e().unwrap().es().unwrap().into_parts();
assert_eq!(wire.len(), 81);
let payload = [0x42u8; 32];
let mut sealed = [0u8; 48];
let sealed_len = send_transport.send(&payload, &mut sealed).unwrap();
let opener = SyncHandshake::<Seal, Responder, _, _, _, _>::respond(
provider.clone(),
&[],
Cursor::new(wire),
)
.set_s(recipient_static)
.unwrap();
let (_revealed_e, recv) = opener.recv().e().unwrap();
let mut recv_transport = recv.es().unwrap();
assert_eq!(
send_transport.session_id(),
recv_transport.transport().session_id()
);
let mut opened = [0u8; 32];
let opened_len = recv_transport
.transport()
.receive(&sealed[..sealed_len], &mut opened)
.unwrap();
assert_eq!(&opened[..opened_len], &payload);
}
#[tokio::test]
async fn ikpsk1_sync_round_trip() {
let mut provider = EphemeralOnly::new(StdRng::from_os_rng());
let initiator_static = provider.generate::<P256>().unwrap();
let initiator_pub = provider.public(&initiator_static).unwrap();
let responder_static = provider.generate::<P256>().unwrap();
let responder_pub = provider.public(&responder_static).unwrap();
let psk = Psk::from_bytes([0xAA; 32]);
let (i2r, r2i) = (
Rc::new(RefCell::new(VecDeque::<u8>::new())),
Rc::new(RefCell::new(VecDeque::<u8>::new())),
);
let init_stream = Pipe {
inbound: r2i.clone(),
outbound: i2r.clone(),
};
let resp_stream = Pipe {
inbound: i2r.clone(),
outbound: r2i.clone(),
};
let i_hs = SyncHandshake::<Channel, Initiator, _, _, _, _>::initiate(
EphemeralOnly::new(StdRng::from_os_rng()),
&[],
init_stream,
)
.set_rs(responder_pub);
let i_hs = i_hs
.e()
.unwrap()
.es()
.unwrap()
.s(initiator_static)
.unwrap()
.ss()
.unwrap()
.psk(&psk)
.unwrap();
assert_eq!(i2r.borrow().len(), 162);
let r_hs = SyncHandshake::<Channel, Responder, _, _, _, _>::respond(
EphemeralOnly::new(StdRng::from_os_rng()),
&[],
resp_stream,
)
.set_s(responder_static)
.unwrap();
let (_revealed_i_e, recv) = r_hs.recv().e().unwrap();
let recv = recv.es().unwrap();
let (revealed_i_pub, recv) = recv.s().unwrap();
assert_eq!(revealed_i_pub, initiator_pub);
let recv = recv.ss().unwrap();
let r_hs = recv.psk(&psk).unwrap();
let r_transport = r_hs.e().unwrap().ee().unwrap().se().unwrap();
assert_eq!(r2i.borrow().len(), 81);
let (_revealed_r_e, recv) = i_hs.recv().e().unwrap();
let i_transport = recv.ee().unwrap().se().unwrap();
assert_eq!(
i_transport.transport.session_id(),
r_transport.transport.session_id()
);
}
#[test]
fn k_sync_round_trip() {
let mut provider = EphemeralOnly::new(StdRng::from_os_rng());
let alice_static = provider.generate::<P256>().unwrap();
let alice_pub = provider.public(&alice_static).unwrap();
let bob_static = provider.generate::<P256>().unwrap();
let bob_pub = provider.public(&bob_static).unwrap();
let payload = [0x42u8; 32];
let sealer = SyncHandshake::<NoiseK, Initiator, _, _, _, _>::initiate(
EphemeralOnly::new(StdRng::from_os_rng()),
&[],
Vec::<u8>::new(),
)
.set_s(alice_static)
.unwrap()
.set_rs(bob_pub);
let (mut send_transport, wire) =
sealer.e().unwrap().es().unwrap().ss().unwrap().into_parts();
assert_eq!(wire.len(), 81);
let mut sealed = [0u8; 48];
let n = send_transport.send(&payload, &mut sealed).unwrap();
let opener = SyncHandshake::<NoiseK, Responder, _, _, _, _>::respond(
EphemeralOnly::new(StdRng::from_os_rng()),
&[],
Cursor::new(wire),
)
.set_rs(alice_pub)
.set_s(bob_static)
.unwrap();
let (_e, recv) = opener.recv().e().unwrap();
let mut recv_transport = recv.es().unwrap().ss().unwrap();
assert_eq!(
send_transport.session_id(),
recv_transport.transport().session_id()
);
let mut opened = [0u8; 32];
let on = recv_transport
.transport()
.receive(&sealed[..n], &mut opened)
.unwrap();
assert_eq!(&opened[..on], &payload);
}
}