everscale_network/adnl/
handshake.rs

1use std::convert::TryInto;
2use std::sync::Arc;
3
4use aes::cipher::{StreamCipher, StreamCipherSeek};
5use everscale_crypto::ed25519;
6
7use super::encryption::*;
8use super::keystore::Key;
9use super::node_id::{NodeIdFull, NodeIdShort};
10use super::packet_view::*;
11use crate::util::FastHashMap;
12
13#[inline(always)]
14pub fn compute_handshake_prefix_len(version: Option<u16>) -> usize {
15    96 + if version.is_some() { 4 } else { 0 }
16}
17
18/// Modifies `buffer` in-place to contain the handshake packet
19pub fn build_handshake_packet(
20    peer_id: &NodeIdShort,
21    peer_id_full: &NodeIdFull,
22    buffer: &mut Vec<u8>,
23    version: Option<u16>,
24) {
25    // Create temp local key
26    let temp_private_key = ed25519::SecretKey::generate(&mut rand::thread_rng());
27    let temp_private_key = ed25519::ExpandedSecretKey::from(&temp_private_key);
28    let temp_public_key = ed25519::PublicKey::from(&temp_private_key);
29
30    let shared_secret = temp_private_key.compute_shared_secret(peer_id_full.public_key());
31
32    // Prepare packet
33    let checksum: [u8; 32] = compute_packet_data_hash(version, buffer.as_slice());
34
35    let header_len = compute_handshake_prefix_len(version);
36    let buffer_len = buffer.len();
37    buffer.resize(header_len + buffer_len, 0);
38    buffer.copy_within(..buffer_len, header_len);
39
40    buffer[..32].copy_from_slice(peer_id.as_slice());
41    buffer[32..64].copy_from_slice(temp_public_key.as_bytes());
42
43    match version {
44        Some(version) => {
45            let mut xor = [
46                (version >> 8) as u8,
47                version as u8,
48                (version >> 8) as u8,
49                version as u8,
50            ];
51            for (i, byte) in buffer[..64].iter().enumerate() {
52                xor[i % 4] ^= *byte;
53            }
54            for (i, byte) in checksum.iter().enumerate() {
55                xor[i % 4] ^= *byte;
56            }
57            buffer[64..68].copy_from_slice(&xor);
58            buffer[68..100].copy_from_slice(&checksum);
59            build_packet_cipher(&shared_secret, &checksum).apply_keystream(&mut buffer[100..]);
60        }
61        None => {
62            buffer[64..96].copy_from_slice(&checksum);
63            build_packet_cipher(&shared_secret, &checksum).apply_keystream(&mut buffer[96..]);
64        }
65    }
66}
67
68/// Attempts to decode the buffer as an ADNL handshake packet. On a successful nonempty result,
69/// this buffer remains as decrypted packet data.
70///
71/// Expected packet structure (without version):
72///  - 0..=31 - short local node id
73///  - 32..=63 - sender pubkey
74///  - 64..=95 - checksum
75///  - 96..... - encrypted data
76///
77/// Expected packet structure (with version):
78///  - 0..=31 - short local node id
79///  - 32..=63 - sender pubkey
80///  - 64..=68 - XOR'ed ADNL version
81///  - 68..=100 - checksum
82///  - 100..... - encrypted data
83///
84/// **NOTE: even on failure buffer can be modified**
85pub fn parse_handshake_packet(
86    keys: &FastHashMap<NodeIdShort, Arc<Key>>,
87    buffer: &mut PacketView<'_>,
88) -> Result<Option<(NodeIdShort, Option<u16>)>, HandshakeError> {
89    const PUBLIC_KEY_RANGE: std::ops::Range<usize> = 32..64;
90
91    // Ordinary data ranges
92    const DATA_START: usize = 96;
93    const CHECKSUM_RANGE: std::ops::Range<usize> = 64..DATA_START;
94    const DATA_RANGE: std::ops::RangeFrom<usize> = DATA_START..;
95
96    // Data ranges for packets with ADNL version
97    const EXT_DATA_START: usize = 100;
98    const EXT_CHECKSUM_RANGE: std::ops::Range<usize> = 68..EXT_DATA_START;
99    const EXT_DATA_RANGE: std::ops::RangeFrom<usize> = EXT_DATA_START..;
100
101    if buffer.len() < DATA_START {
102        return Err(HandshakeError::BadHandshakePacketLength);
103    }
104
105    // SAFETY: NodeIdShort is 32 (<= 96) bytes and has the same layout as `[u8; 32]`
106    // due to `#[repr(transparent)]`
107    let local_id = unsafe { &*(buffer.as_ptr() as *const NodeIdShort) };
108
109    // Get local id
110    let local_key = match keys.get(local_id) {
111        Some(key) => key,
112        // No local keys found
113        None => return Ok(None),
114    };
115
116    // Compute shared secret
117    let shared_secret =
118        match ed25519::PublicKey::from_bytes(buffer[PUBLIC_KEY_RANGE].try_into().unwrap()) {
119            Some(other_public_key) => local_key
120                .secret_key()
121                .compute_shared_secret(&other_public_key),
122            None => return Err(HandshakeError::InvalidPublicKey),
123        };
124
125    if buffer.len() > EXT_DATA_START {
126        if let Some(version) =
127            decode_version::<EXT_DATA_START>((&buffer[..EXT_DATA_START]).try_into().unwrap())
128        {
129            // Build cipher
130            let mut cipher = build_packet_cipher(
131                &shared_secret,
132                &buffer[EXT_CHECKSUM_RANGE].try_into().unwrap(),
133            );
134
135            // Decode data
136            cipher.apply_keystream(&mut buffer[EXT_DATA_RANGE]);
137
138            // If hash is ok
139            if compute_packet_data_hash(Some(version), &buffer[EXT_DATA_RANGE]).as_slice()
140                == &buffer[EXT_CHECKSUM_RANGE]
141            {
142                // Leave only data in the buffer and return version
143                buffer.remove_prefix(EXT_DATA_START);
144                return Ok(Some((*local_id, Some(version))));
145            }
146
147            // Otherwise restore data
148            cipher.seek(0);
149            cipher.apply_keystream(&mut buffer[EXT_DATA_RANGE]);
150        }
151    }
152
153    // Decode data
154    build_packet_cipher(&shared_secret, &buffer[CHECKSUM_RANGE].try_into().unwrap())
155        .apply_keystream(&mut buffer[DATA_RANGE]);
156
157    // Check checksum
158    if compute_packet_data_hash(None, &buffer[DATA_RANGE]).as_slice() != &buffer[CHECKSUM_RANGE] {
159        return Err(HandshakeError::BadHandshakePacketChecksum);
160    }
161
162    // Leave only data in the buffer
163    buffer.remove_prefix(DATA_START);
164
165    Ok(Some((*local_id, None)))
166}
167
168#[derive(thiserror::Error, Debug)]
169pub enum HandshakeError {
170    #[error("Bad handshake packet length")]
171    BadHandshakePacketLength,
172    #[error("Bad handshake packet checksum")]
173    BadHandshakePacketChecksum,
174    #[error("Invalid public key")]
175    InvalidPublicKey,
176}