hypercore_protocol/crypto/
handshake.rs1use blake2::{
7 Blake2bMac,
8 digest::{FixedOutput, Update, typenum::U32},
9};
10use std::io::{Error, ErrorKind, Result};
11
12const REPLICATE_INITIATOR: [u8; 32] = [
15 0x51, 0x81, 0x2A, 0x2A, 0x35, 0x9B, 0x50, 0x36, 0x95, 0x36, 0x77, 0x5D, 0xF8, 0x9E, 0x18, 0xE4,
16 0x77, 0x40, 0xF3, 0xDB, 0x72, 0xAC, 0xA, 0xE7, 0xB, 0x29, 0x59, 0x4C, 0x19, 0x4D, 0xC3, 0x16,
17];
18const REPLICATE_RESPONDER: [u8; 32] = [
19 0x4, 0x38, 0x49, 0x2D, 0x2, 0x97, 0xC, 0xC1, 0x35, 0x28, 0xAC, 0x2, 0x62, 0xBC, 0xA0, 0x7,
20 0x4E, 0x9, 0x26, 0x26, 0x2, 0x56, 0x86, 0x5A, 0xCC, 0xC0, 0xBF, 0x15, 0xBD, 0x79, 0x12, 0x7D,
21];
22
23#[derive(Debug, Clone, Default)]
29pub struct HandshakeResult {
30 pub(crate) is_initiator: bool,
31 pub local_pubkey: Vec<u8>,
33 pub remote_pubkey: Vec<u8>,
35 pub(crate) handshake_hash: Vec<u8>,
36}
37
38impl HandshakeResult {
39 pub fn from_pre_encrypted(
51 is_initiator: bool,
52 local_pubkey: [u8; 32],
53 remote_pubkey: [u8; 32],
54 handshake_hash: Vec<u8>,
55 ) -> Self {
56 Self {
57 is_initiator,
58 local_pubkey: local_pubkey.to_vec(),
59 remote_pubkey: remote_pubkey.to_vec(),
60 handshake_hash,
61 }
62 }
63
64 pub(crate) fn capability(&self, key: &[u8]) -> Option<Vec<u8>> {
66 Some(replicate_capability(
67 self.is_initiator,
68 key,
69 &self.handshake_hash,
70 ))
71 }
72
73 pub(crate) fn remote_capability(&self, key: &[u8]) -> Option<Vec<u8>> {
75 Some(replicate_capability(
76 !self.is_initiator,
77 key,
78 &self.handshake_hash,
79 ))
80 }
81
82 pub(crate) fn verify_remote_capability(
84 &self,
85 capability: Option<Vec<u8>>,
86 key: &[u8],
87 ) -> Result<()> {
88 let expected_capability = self.remote_capability(key);
89 match (capability, expected_capability) {
90 (Some(c1), Some(c2)) if c1 == c2 => Ok(()),
91 (None, None) => Err(Error::new(
92 ErrorKind::PermissionDenied,
93 "Missing capabilities for verification",
94 )),
95 _ => Err(Error::new(
96 ErrorKind::PermissionDenied,
97 "Invalid remote channel capability",
98 )),
99 }
100 }
101}
102
103fn replicate_capability(is_initiator: bool, key: &[u8], handshake_hash: &[u8]) -> Vec<u8> {
106 let seed = if is_initiator {
107 REPLICATE_INITIATOR
108 } else {
109 REPLICATE_RESPONDER
110 };
111
112 let mut hasher =
113 Blake2bMac::<U32>::new_with_salt_and_personal(handshake_hash, &[], &[]).unwrap();
114 hasher.update(&seed);
115 hasher.update(key);
116 let hash = hasher.finalize_fixed();
117
118 hash.as_slice().to_vec()
119}