From c8fdded5a71df1d69a1de8ad7b9b2d9ed89e7129 Mon Sep 17 00:00:00 2001 From: John Smith Date: Sat, 24 Jun 2023 21:23:48 -0400 Subject: [PATCH] fix crypto s --- .gitignore | 4 ++ veilid-core/src/crypto/envelope.rs | 53 ++++++++++++++++--- .../src/crypto/tests/test_envelope_receipt.rs | 24 ++++++--- .../src/network_manager/direct_boot.rs | 14 ++--- veilid-core/src/network_manager/mod.rs | 52 +++++------------- 5 files changed, 85 insertions(+), 62 deletions(-) diff --git a/.gitignore b/.gitignore index 44ae98d5..aa8d987d 100644 --- a/.gitignore +++ b/.gitignore @@ -61,3 +61,7 @@ $RECYCLE.BIN/ ### Rust target/ logs/ + +flamegraph.svg +perf.data +perf.data.old \ No newline at end of file diff --git a/veilid-core/src/crypto/envelope.rs b/veilid-core/src/crypto/envelope.rs index c123ea52..21c940f4 100644 --- a/veilid-core/src/crypto/envelope.rs +++ b/veilid-core/src/crypto/envelope.rs @@ -66,7 +66,11 @@ impl Envelope { } } - pub fn from_signed_data(crypto: Crypto, data: &[u8]) -> VeilidAPIResult { + pub fn from_signed_data( + crypto: Crypto, + data: &[u8], + network_key: &Option, + ) -> VeilidAPIResult { // Ensure we are at least the length of the envelope // Silent drop here, as we use zero length packets as part of the protocol for hole punching if data.len() < MIN_ENVELOPE_SIZE { @@ -135,9 +139,22 @@ impl Envelope { let recipient_id_slice: [u8; PUBLIC_KEY_LENGTH] = data[0x4A..0x6A] .try_into() .map_err(VeilidAPIError::internal)?; - let nonce: Nonce = Nonce::new(nonce_slice); - let sender_id = PublicKey::new(sender_id_slice); - let recipient_id = PublicKey::new(recipient_id_slice); + let mut nonce: Nonce = Nonce::new(nonce_slice); + let mut sender_id = PublicKey::new(sender_id_slice); + let mut recipient_id = PublicKey::new(recipient_id_slice); + + // Apply network key (not the best, but it will keep networks from colliding without much overhead) + if let Some(nk) = network_key.as_ref() { + for n in 0..NONCE_LENGTH { + nonce.bytes[n] ^= nk.bytes[n]; + } + for n in 0..CRYPTO_KEY_LENGTH { + sender_id.bytes[n] ^= nk.bytes[n]; + } + for n in 0..CRYPTO_KEY_LENGTH { + recipient_id.bytes[n] ^= nk.bytes[n]; + } + } // Ensure sender_id and recipient_id are not the same if sender_id == recipient_id { @@ -175,13 +192,20 @@ impl Envelope { crypto: Crypto, data: &[u8], node_id_secret: &SecretKey, + network_key: &Option, ) -> VeilidAPIResult> { // Get DH secret let vcrypto = crypto .get(self.crypto_kind) .expect("need to ensure only valid crypto kinds here"); - let dh_secret = vcrypto.cached_dh(&self.sender_id, node_id_secret)?; + let mut dh_secret = vcrypto.cached_dh(&self.sender_id, node_id_secret)?; + // Apply network key + if let Some(nk) = network_key.as_ref() { + for n in 0..CRYPTO_KEY_LENGTH { + dh_secret.bytes[n] ^= nk.bytes[n]; + } + } // Decrypt message without authentication let body = vcrypto.crypt_no_auth_aligned_8( &data[0x6A..data.len() - 64], @@ -197,6 +221,7 @@ impl Envelope { crypto: Crypto, body: &[u8], node_id_secret: &SecretKey, + network_key: &Option, ) -> VeilidAPIResult> { // Ensure body isn't too long let envelope_size: usize = body.len() + MIN_ENVELOPE_SIZE; @@ -207,7 +232,7 @@ impl Envelope { let vcrypto = crypto .get(self.crypto_kind) .expect("need to ensure only valid crypto kinds here"); - let dh_secret = vcrypto.cached_dh(&self.recipient_id, node_id_secret)?; + let mut dh_secret = vcrypto.cached_dh(&self.recipient_id, node_id_secret)?; // Write envelope body let mut data = vec![0u8; envelope_size]; @@ -229,6 +254,22 @@ impl Envelope { // Write recipient node id data[0x4A..0x6A].copy_from_slice(&self.recipient_id.bytes); + // Apply network key (not the best, but it will keep networks from colliding without much overhead) + if let Some(nk) = network_key.as_ref() { + for n in 0..SECRET_KEY_LENGTH { + dh_secret.bytes[n] ^= nk.bytes[n]; + } + for n in 0..NONCE_LENGTH { + data[0x12 + n] ^= nk.bytes[n]; + } + for n in 0..CRYPTO_KEY_LENGTH { + data[0x2A + n] ^= nk.bytes[n]; + } + for n in 0..CRYPTO_KEY_LENGTH { + data[0x4A + n] ^= nk.bytes[n]; + } + } + // Encrypt and authenticate message let encrypted_body = vcrypto.crypt_no_auth_unaligned(body, &self.nonce.bytes, &dh_secret); diff --git a/veilid-core/src/crypto/tests/test_envelope_receipt.rs b/veilid-core/src/crypto/tests/test_envelope_receipt.rs index 1e2698fc..1b8a41f6 100644 --- a/veilid-core/src/crypto/tests/test_envelope_receipt.rs +++ b/veilid-core/src/crypto/tests/test_envelope_receipt.rs @@ -3,8 +3,16 @@ use super::*; pub async fn test_envelope_round_trip( envelope_version: EnvelopeVersion, vcrypto: CryptoSystemVersion, + network_key: Option, ) { - info!("--- test envelope round trip ---"); + if network_key.is_some() { + info!( + "--- test envelope round trip {} w/network key ---", + vcrypto.kind() + ); + } else { + info!("--- test envelope round trip {} ---", vcrypto.kind()); + } // Create envelope let ts = Timestamp::from(0x12345678ABCDEF69u64); @@ -25,15 +33,15 @@ pub async fn test_envelope_round_trip( // Serialize to bytes let enc_data = envelope - .to_encrypted_data(vcrypto.crypto(), body, &sender_secret) + .to_encrypted_data(vcrypto.crypto(), body, &sender_secret, &network_key) .expect("failed to encrypt data"); // Deserialize from bytes - let envelope2 = Envelope::from_signed_data(vcrypto.crypto(), &enc_data) + let envelope2 = Envelope::from_signed_data(vcrypto.crypto(), &enc_data, &network_key) .expect("failed to deserialize envelope from data"); let body2 = envelope2 - .decrypt_body(vcrypto.crypto(), &enc_data, &recipient_secret) + .decrypt_body(vcrypto.crypto(), &enc_data, &recipient_secret, &network_key) .expect("failed to decrypt envelope body"); // Compare envelope and body @@ -45,13 +53,13 @@ pub async fn test_envelope_round_trip( let mut mod_enc_data = enc_data.clone(); mod_enc_data[enc_data_len - 1] ^= 0x80u8; assert!( - Envelope::from_signed_data(vcrypto.crypto(), &mod_enc_data).is_err(), + Envelope::from_signed_data(vcrypto.crypto(), &mod_enc_data, &network_key).is_err(), "should have failed to decode envelope with modified signature" ); let mut mod_enc_data2 = enc_data.clone(); mod_enc_data2[enc_data_len - 65] ^= 0x80u8; assert!( - Envelope::from_signed_data(vcrypto.crypto(), &mod_enc_data2).is_err(), + Envelope::from_signed_data(vcrypto.crypto(), &mod_enc_data2, &network_key).is_err(), "should have failed to decode envelope with modified data" ); } @@ -97,7 +105,9 @@ pub async fn test_all() { for v in VALID_CRYPTO_KINDS { let vcrypto = crypto.get(v).unwrap(); - test_envelope_round_trip(ev, vcrypto.clone()).await; + test_envelope_round_trip(ev, vcrypto.clone(), None).await; + test_envelope_round_trip(ev, vcrypto.clone(), Some(vcrypto.random_shared_secret())) + .await; test_receipt_round_trip(ev, vcrypto).await; } } diff --git a/veilid-core/src/network_manager/direct_boot.rs b/veilid-core/src/network_manager/direct_boot.rs index da33fc39..3f6c74ad 100644 --- a/veilid-core/src/network_manager/direct_boot.rs +++ b/veilid-core/src/network_manager/direct_boot.rs @@ -17,9 +17,7 @@ impl NetworkManager { .iter() .filter_map(|nr| nr.make_peer_info(RoutingDomain::PublicInternet)) .collect(); - let mut json_bytes = serialize_json(bootstrap_peerinfo).as_bytes().to_vec(); - - self.apply_network_key(&mut json_bytes); + let json_bytes = serialize_json(bootstrap_peerinfo).as_bytes().to_vec(); // Reply with a chunk of signed routing table match self @@ -42,12 +40,9 @@ impl NetworkManager { pub async fn boot_request(&self, dial_info: DialInfo) -> EyreResult> { let timeout_ms = self.with_config(|c| c.network.rpc.timeout_ms); // Send boot magic to requested peer address - let mut data = BOOT_MAGIC.to_vec(); + let data = BOOT_MAGIC.to_vec(); - // Apply network key - self.apply_network_key(&mut data); - - let mut out_data: Vec = network_result_value_or_log!(self + let out_data: Vec = network_result_value_or_log!(self .net() .send_recv_data_unbound_to_dial_info(dial_info, data, timeout_ms) .await? => @@ -55,9 +50,6 @@ impl NetworkManager { return Ok(Vec::new()); }); - // Apply network key - self.apply_network_key(&mut out_data); - let bootstrap_peerinfo: Vec = deserialize_json(std::str::from_utf8(&out_data).wrap_err("bad utf8 in boot peerinfo")?) .wrap_err("failed to deserialize boot peerinfo")?; diff --git a/veilid-core/src/network_manager/mod.rs b/veilid-core/src/network_manager/mod.rs index 8a64db3d..c164ed01 100644 --- a/veilid-core/src/network_manager/mod.rs +++ b/veilid-core/src/network_manager/mod.rs @@ -213,12 +213,15 @@ impl NetworkManager { }; let network_key = if let Some(network_key_password) = network_key_password { + if !network_key_password.is_empty() { + info!("Using network key"); - info!("Using network key"); - - let bcs = crypto.best(); - // Yes the use of the salt this way is generally bad, but this just needs to be hashed - Some(bcs.derive_shared_secret(network_key_password.as_bytes(), network_key_password.as_bytes()).expect("failed to derive network key")) + let bcs = crypto.best(); + // Yes the use of the salt this way is generally bad, but this just needs to be hashed + Some(bcs.derive_shared_secret(network_key_password.as_bytes(), network_key_password.as_bytes()).expect("failed to derive network key")) + } else { + None + } } else { None }; @@ -795,7 +798,7 @@ impl NetworkManager { // Encode envelope let envelope = Envelope::new(version, node_id.kind, ts, nonce, node_id.value, dest_node_id.value); envelope - .to_encrypted_data(self.crypto(), body.as_ref(), &node_id_secret) + .to_encrypted_data(self.crypto(), body.as_ref(), &node_id_secret, &self.unlocked_inner.network_key) .wrap_err("envelope failed to encode") } @@ -835,10 +838,7 @@ impl NetworkManager { }; // Build the envelope to send - let mut out = self.build_envelope(best_node_id, envelope_version, body)?; - - // Apply network key - self.apply_network_key(&mut out); + let out = self.build_envelope(best_node_id, envelope_version, body)?; // Send the envelope via whatever means necessary self.send_data(node_ref, out).await @@ -849,7 +849,7 @@ impl NetworkManager { pub async fn send_out_of_band_receipt( &self, dial_info: DialInfo, - mut rcpt_data: Vec, + rcpt_data: Vec, ) -> EyreResult<()> { // Do we need to validate the outgoing receipt? Probably not // because it is supposed to be opaque and the @@ -857,9 +857,6 @@ impl NetworkManager { // Also, in the case of an old 'version', returning the receipt // should not be subject to our ability to decode it - // Apply network key - self.apply_network_key(&mut rcpt_data); - // Send receipt directly log_net!(debug "send_out_of_band_receipt: dial_info={}", dial_info); network_result_value_or_log!(self @@ -872,28 +869,13 @@ impl NetworkManager { Ok(()) } - // Network isolation encryption - fn apply_network_key(&self, data: &mut [u8]) { - if let Some(network_key) = self.unlocked_inner.network_key { - let bcs = self.crypto().best(); - // Nonce abuse, but this is not supposed to be cryptographically sound - // it's just here to keep networks from accidentally bridging. - // A proper nonce would increase the data length here and change the packet sizes on the wire - bcs.crypt_in_place_no_auth( - data, - &network_key.bytes[0..NONCE_LENGTH].try_into().unwrap(), - &network_key, - ) - } - } - // Called when a packet potentially containing an RPC envelope is received by a low-level // network protocol handler. Processes the envelope, authenticates and decrypts the RPC message // and passes it to the RPC handler #[instrument(level = "trace", ret, err, skip(self, data), fields(data.len = data.len()))] async fn on_recv_envelope( &self, - mut data: &mut [u8], + data: &mut [u8], connection_descriptor: ConnectionDescriptor, ) -> EyreResult { let root = span!( @@ -942,9 +924,6 @@ impl NetworkManager { } }; - // Apply network key - self.apply_network_key(&mut data); - // Is this a direct bootstrap request instead of an envelope? if data[0..4] == *BOOT_MAGIC { network_result_value_or_log!(self.handle_boot_request(connection_descriptor).await? => {}); @@ -958,7 +937,7 @@ impl NetworkManager { } // Decode envelope header (may fail signature validation) - let envelope = match Envelope::from_signed_data(self.crypto(), data) { + let envelope = match Envelope::from_signed_data(self.crypto(), data, &self.unlocked_inner.network_key) { Ok(v) => v, Err(e) => { log_net!(debug "envelope failed to decode: {}", e); @@ -1041,9 +1020,6 @@ impl NetworkManager { // Relay the packet to the desired destination log_net!("relaying {} bytes to {}", data.len(), relay_nr); - // Apply network key - self.apply_network_key(&mut data); - network_result_value_or_log!(match self.send_data(relay_nr, data.to_vec()) .await { Ok(v) => v, @@ -1065,7 +1041,7 @@ impl NetworkManager { // Decrypt the envelope body let body = match envelope - .decrypt_body(self.crypto(), data, &node_id_secret) { + .decrypt_body(self.crypto(), data, &node_id_secret, &self.unlocked_inner.network_key) { Ok(v) => v, Err(e) => { log_net!(debug "failed to decrypt envelope body: {}",e);