use blake2::{
Blake2bMac,
digest::{FixedOutput, Update, typenum::U32},
};
use std::io::{Error, ErrorKind, Result};
const REPLICATE_INITIATOR: [u8; 32] = [
0x51, 0x81, 0x2A, 0x2A, 0x35, 0x9B, 0x50, 0x36, 0x95, 0x36, 0x77, 0x5D, 0xF8, 0x9E, 0x18, 0xE4,
0x77, 0x40, 0xF3, 0xDB, 0x72, 0xAC, 0xA, 0xE7, 0xB, 0x29, 0x59, 0x4C, 0x19, 0x4D, 0xC3, 0x16,
];
const REPLICATE_RESPONDER: [u8; 32] = [
0x4, 0x38, 0x49, 0x2D, 0x2, 0x97, 0xC, 0xC1, 0x35, 0x28, 0xAC, 0x2, 0x62, 0xBC, 0xA0, 0x7,
0x4E, 0x9, 0x26, 0x26, 0x2, 0x56, 0x86, 0x5A, 0xCC, 0xC0, 0xBF, 0x15, 0xBD, 0x79, 0x12, 0x7D,
];
#[derive(Debug, Clone, Default)]
pub struct HandshakeResult {
pub(crate) is_initiator: bool,
pub local_pubkey: Vec<u8>,
pub remote_pubkey: Vec<u8>,
pub(crate) handshake_hash: Vec<u8>,
}
impl HandshakeResult {
pub fn from_pre_encrypted(
is_initiator: bool,
local_pubkey: [u8; 32],
remote_pubkey: [u8; 32],
handshake_hash: Vec<u8>,
) -> Self {
Self {
is_initiator,
local_pubkey: local_pubkey.to_vec(),
remote_pubkey: remote_pubkey.to_vec(),
handshake_hash,
}
}
pub(crate) fn capability(&self, key: &[u8]) -> Option<Vec<u8>> {
Some(replicate_capability(
self.is_initiator,
key,
&self.handshake_hash,
))
}
pub(crate) fn remote_capability(&self, key: &[u8]) -> Option<Vec<u8>> {
Some(replicate_capability(
!self.is_initiator,
key,
&self.handshake_hash,
))
}
pub(crate) fn verify_remote_capability(
&self,
capability: Option<Vec<u8>>,
key: &[u8],
) -> Result<()> {
let expected_capability = self.remote_capability(key);
match (capability, expected_capability) {
(Some(c1), Some(c2)) if c1 == c2 => Ok(()),
(None, None) => Err(Error::new(
ErrorKind::PermissionDenied,
"Missing capabilities for verification",
)),
_ => Err(Error::new(
ErrorKind::PermissionDenied,
"Invalid remote channel capability",
)),
}
}
}
fn replicate_capability(is_initiator: bool, key: &[u8], handshake_hash: &[u8]) -> Vec<u8> {
let seed = if is_initiator {
REPLICATE_INITIATOR
} else {
REPLICATE_RESPONDER
};
let mut hasher =
Blake2bMac::<U32>::new_with_salt_and_personal(handshake_hash, &[], &[]).unwrap();
hasher.update(&seed);
hasher.update(key);
let hash = hasher.finalize_fixed();
hash.as_slice().to_vec()
}