use bytes::{BufMut, BytesMut};
use super::{IncomingInitiation, MacGenerator, OutgoingInitiation};
use crate::noise::protocol::HandshakeResponse;
use crate::noise::{
crypto::{
aead_decrypt, aead_encrypt, gen_ephemeral_key, hash, kdf1, kdf3, EphemeralPrivateKey,
PeerStaticSecret, PublicKey,
},
Error,
};
const MESSAGE_TYPE_HANDSHAKE_RESPONSE: u8 = 2u8;
const PACKET_SIZE: usize = 92;
pub struct OutgoingResponse {
pub hash: [u8; 32],
pub chaining_key: [u8; 32],
pub ephemeral_private_key: EphemeralPrivateKey,
}
impl OutgoingResponse {
pub fn new(
initiation: &IncomingInitiation,
local_index: u32,
secret: &PeerStaticSecret,
macs: &mut MacGenerator,
) -> (Self, Vec<u8>) {
let mut buf = BytesMut::with_capacity(PACKET_SIZE);
buf.put_u32_le(MESSAGE_TYPE_HANDSHAKE_RESPONSE as _);
buf.put_u32_le(local_index);
buf.put_u32_le(initiation.index);
let (ephemeral_pri, ephemeral_pub) = gen_ephemeral_key();
buf.put_slice(ephemeral_pub.as_bytes()); let c = kdf1(&initiation.chaining_key, ephemeral_pub.as_bytes());
let h = hash(&initiation.hash, ephemeral_pub.as_bytes());
let c = kdf1(
&c,
ephemeral_pri
.diffie_hellman(&initiation.ephemeral_public_key)
.as_bytes(),
);
let c = kdf1(
&c,
ephemeral_pri.diffie_hellman(secret.public_key()).as_bytes(),
);
let (c, t, k) = kdf3(&c, secret.psk());
let h = hash(&h, &t);
let empty = aead_encrypt(&k, 0, &[], &h).unwrap();
buf.put_slice(&empty); let h = hash(&h, &empty);
buf.put_slice(&macs.generate_mac1(&buf)); buf.put_slice(&macs.generate_mac2(&buf));
let payload = buf.freeze().to_vec();
(
Self {
hash: h,
chaining_key: c,
ephemeral_private_key: ephemeral_pri,
},
payload,
)
}
}
pub struct IncomingResponse {
pub index: u32,
pub ephemeral_public_key: PublicKey,
pub hash: [u8; 32],
pub chaining_key: [u8; 32],
}
impl IncomingResponse {
pub fn parse(
initiation: &OutgoingInitiation,
secret: &PeerStaticSecret,
packet: &HandshakeResponse,
) -> Result<Self, Error> {
let peer_ephemeral_pub = PublicKey::from(packet.ephemeral_public_key);
let c = kdf1(&initiation.chaining_key, peer_ephemeral_pub.as_bytes());
let h = hash(&initiation.hash, peer_ephemeral_pub.as_bytes());
let c = kdf1(
&c,
initiation
.ephemeral_private_key
.diffie_hellman(&peer_ephemeral_pub)
.as_bytes(),
);
let c = kdf1(
&c,
secret
.local()
.private_key()
.diffie_hellman(&peer_ephemeral_pub)
.as_bytes(),
);
let (c, t, k) = kdf3(&c, secret.psk());
let h = hash(&h, &t);
let empty = aead_decrypt(&k, 0, &packet.empty, &h)?;
if !empty.is_empty() {
return Err(Error::Decryption);
}
let h = hash(&h, &packet.empty);
Ok(Self {
index: packet.sender_index,
ephemeral_public_key: peer_ephemeral_pub,
hash: h,
chaining_key: c,
})
}
}