fix crypto
s
This commit is contained in:
parent
b1df2c9d2d
commit
c8fdded5a7
4
.gitignore
vendored
4
.gitignore
vendored
@ -61,3 +61,7 @@ $RECYCLE.BIN/
|
|||||||
### Rust
|
### Rust
|
||||||
target/
|
target/
|
||||||
logs/
|
logs/
|
||||||
|
|
||||||
|
flamegraph.svg
|
||||||
|
perf.data
|
||||||
|
perf.data.old
|
@ -66,7 +66,11 @@ impl Envelope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_signed_data(crypto: Crypto, data: &[u8]) -> VeilidAPIResult<Envelope> {
|
pub fn from_signed_data(
|
||||||
|
crypto: Crypto,
|
||||||
|
data: &[u8],
|
||||||
|
network_key: &Option<SharedSecret>,
|
||||||
|
) -> VeilidAPIResult<Envelope> {
|
||||||
// Ensure we are at least the length of the envelope
|
// 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
|
// Silent drop here, as we use zero length packets as part of the protocol for hole punching
|
||||||
if data.len() < MIN_ENVELOPE_SIZE {
|
if data.len() < MIN_ENVELOPE_SIZE {
|
||||||
@ -135,9 +139,22 @@ impl Envelope {
|
|||||||
let recipient_id_slice: [u8; PUBLIC_KEY_LENGTH] = data[0x4A..0x6A]
|
let recipient_id_slice: [u8; PUBLIC_KEY_LENGTH] = data[0x4A..0x6A]
|
||||||
.try_into()
|
.try_into()
|
||||||
.map_err(VeilidAPIError::internal)?;
|
.map_err(VeilidAPIError::internal)?;
|
||||||
let nonce: Nonce = Nonce::new(nonce_slice);
|
let mut nonce: Nonce = Nonce::new(nonce_slice);
|
||||||
let sender_id = PublicKey::new(sender_id_slice);
|
let mut sender_id = PublicKey::new(sender_id_slice);
|
||||||
let recipient_id = PublicKey::new(recipient_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
|
// Ensure sender_id and recipient_id are not the same
|
||||||
if sender_id == recipient_id {
|
if sender_id == recipient_id {
|
||||||
@ -175,13 +192,20 @@ impl Envelope {
|
|||||||
crypto: Crypto,
|
crypto: Crypto,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
node_id_secret: &SecretKey,
|
node_id_secret: &SecretKey,
|
||||||
|
network_key: &Option<SharedSecret>,
|
||||||
) -> VeilidAPIResult<Vec<u8>> {
|
) -> VeilidAPIResult<Vec<u8>> {
|
||||||
// Get DH secret
|
// Get DH secret
|
||||||
let vcrypto = crypto
|
let vcrypto = crypto
|
||||||
.get(self.crypto_kind)
|
.get(self.crypto_kind)
|
||||||
.expect("need to ensure only valid crypto kinds here");
|
.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
|
// Decrypt message without authentication
|
||||||
let body = vcrypto.crypt_no_auth_aligned_8(
|
let body = vcrypto.crypt_no_auth_aligned_8(
|
||||||
&data[0x6A..data.len() - 64],
|
&data[0x6A..data.len() - 64],
|
||||||
@ -197,6 +221,7 @@ impl Envelope {
|
|||||||
crypto: Crypto,
|
crypto: Crypto,
|
||||||
body: &[u8],
|
body: &[u8],
|
||||||
node_id_secret: &SecretKey,
|
node_id_secret: &SecretKey,
|
||||||
|
network_key: &Option<SharedSecret>,
|
||||||
) -> VeilidAPIResult<Vec<u8>> {
|
) -> VeilidAPIResult<Vec<u8>> {
|
||||||
// Ensure body isn't too long
|
// Ensure body isn't too long
|
||||||
let envelope_size: usize = body.len() + MIN_ENVELOPE_SIZE;
|
let envelope_size: usize = body.len() + MIN_ENVELOPE_SIZE;
|
||||||
@ -207,7 +232,7 @@ impl Envelope {
|
|||||||
let vcrypto = crypto
|
let vcrypto = crypto
|
||||||
.get(self.crypto_kind)
|
.get(self.crypto_kind)
|
||||||
.expect("need to ensure only valid crypto kinds here");
|
.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
|
// Write envelope body
|
||||||
let mut data = vec![0u8; envelope_size];
|
let mut data = vec![0u8; envelope_size];
|
||||||
@ -229,6 +254,22 @@ impl Envelope {
|
|||||||
// Write recipient node id
|
// Write recipient node id
|
||||||
data[0x4A..0x6A].copy_from_slice(&self.recipient_id.bytes);
|
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
|
// Encrypt and authenticate message
|
||||||
let encrypted_body = vcrypto.crypt_no_auth_unaligned(body, &self.nonce.bytes, &dh_secret);
|
let encrypted_body = vcrypto.crypt_no_auth_unaligned(body, &self.nonce.bytes, &dh_secret);
|
||||||
|
|
||||||
|
@ -3,8 +3,16 @@ use super::*;
|
|||||||
pub async fn test_envelope_round_trip(
|
pub async fn test_envelope_round_trip(
|
||||||
envelope_version: EnvelopeVersion,
|
envelope_version: EnvelopeVersion,
|
||||||
vcrypto: CryptoSystemVersion,
|
vcrypto: CryptoSystemVersion,
|
||||||
|
network_key: Option<SharedSecret>,
|
||||||
) {
|
) {
|
||||||
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
|
// Create envelope
|
||||||
let ts = Timestamp::from(0x12345678ABCDEF69u64);
|
let ts = Timestamp::from(0x12345678ABCDEF69u64);
|
||||||
@ -25,15 +33,15 @@ pub async fn test_envelope_round_trip(
|
|||||||
|
|
||||||
// Serialize to bytes
|
// Serialize to bytes
|
||||||
let enc_data = envelope
|
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");
|
.expect("failed to encrypt data");
|
||||||
|
|
||||||
// Deserialize from bytes
|
// 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");
|
.expect("failed to deserialize envelope from data");
|
||||||
|
|
||||||
let body2 = envelope2
|
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");
|
.expect("failed to decrypt envelope body");
|
||||||
|
|
||||||
// Compare envelope and body
|
// Compare envelope and body
|
||||||
@ -45,13 +53,13 @@ pub async fn test_envelope_round_trip(
|
|||||||
let mut mod_enc_data = enc_data.clone();
|
let mut mod_enc_data = enc_data.clone();
|
||||||
mod_enc_data[enc_data_len - 1] ^= 0x80u8;
|
mod_enc_data[enc_data_len - 1] ^= 0x80u8;
|
||||||
assert!(
|
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"
|
"should have failed to decode envelope with modified signature"
|
||||||
);
|
);
|
||||||
let mut mod_enc_data2 = enc_data.clone();
|
let mut mod_enc_data2 = enc_data.clone();
|
||||||
mod_enc_data2[enc_data_len - 65] ^= 0x80u8;
|
mod_enc_data2[enc_data_len - 65] ^= 0x80u8;
|
||||||
assert!(
|
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"
|
"should have failed to decode envelope with modified data"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -97,7 +105,9 @@ pub async fn test_all() {
|
|||||||
for v in VALID_CRYPTO_KINDS {
|
for v in VALID_CRYPTO_KINDS {
|
||||||
let vcrypto = crypto.get(v).unwrap();
|
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;
|
test_receipt_round_trip(ev, vcrypto).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,7 @@ impl NetworkManager {
|
|||||||
.iter()
|
.iter()
|
||||||
.filter_map(|nr| nr.make_peer_info(RoutingDomain::PublicInternet))
|
.filter_map(|nr| nr.make_peer_info(RoutingDomain::PublicInternet))
|
||||||
.collect();
|
.collect();
|
||||||
let mut json_bytes = serialize_json(bootstrap_peerinfo).as_bytes().to_vec();
|
let json_bytes = serialize_json(bootstrap_peerinfo).as_bytes().to_vec();
|
||||||
|
|
||||||
self.apply_network_key(&mut json_bytes);
|
|
||||||
|
|
||||||
// Reply with a chunk of signed routing table
|
// Reply with a chunk of signed routing table
|
||||||
match self
|
match self
|
||||||
@ -42,12 +40,9 @@ impl NetworkManager {
|
|||||||
pub async fn boot_request(&self, dial_info: DialInfo) -> EyreResult<Vec<PeerInfo>> {
|
pub async fn boot_request(&self, dial_info: DialInfo) -> EyreResult<Vec<PeerInfo>> {
|
||||||
let timeout_ms = self.with_config(|c| c.network.rpc.timeout_ms);
|
let timeout_ms = self.with_config(|c| c.network.rpc.timeout_ms);
|
||||||
// Send boot magic to requested peer address
|
// Send boot magic to requested peer address
|
||||||
let mut data = BOOT_MAGIC.to_vec();
|
let data = BOOT_MAGIC.to_vec();
|
||||||
|
|
||||||
// Apply network key
|
let out_data: Vec<u8> = network_result_value_or_log!(self
|
||||||
self.apply_network_key(&mut data);
|
|
||||||
|
|
||||||
let mut out_data: Vec<u8> = network_result_value_or_log!(self
|
|
||||||
.net()
|
.net()
|
||||||
.send_recv_data_unbound_to_dial_info(dial_info, data, timeout_ms)
|
.send_recv_data_unbound_to_dial_info(dial_info, data, timeout_ms)
|
||||||
.await? =>
|
.await? =>
|
||||||
@ -55,9 +50,6 @@ impl NetworkManager {
|
|||||||
return Ok(Vec::new());
|
return Ok(Vec::new());
|
||||||
});
|
});
|
||||||
|
|
||||||
// Apply network key
|
|
||||||
self.apply_network_key(&mut out_data);
|
|
||||||
|
|
||||||
let bootstrap_peerinfo: Vec<PeerInfo> =
|
let bootstrap_peerinfo: Vec<PeerInfo> =
|
||||||
deserialize_json(std::str::from_utf8(&out_data).wrap_err("bad utf8 in boot peerinfo")?)
|
deserialize_json(std::str::from_utf8(&out_data).wrap_err("bad utf8 in boot peerinfo")?)
|
||||||
.wrap_err("failed to deserialize boot peerinfo")?;
|
.wrap_err("failed to deserialize boot peerinfo")?;
|
||||||
|
@ -213,7 +213,7 @@ impl NetworkManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let network_key = if let Some(network_key_password) = network_key_password {
|
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();
|
let bcs = crypto.best();
|
||||||
@ -221,6 +221,9 @@ impl NetworkManager {
|
|||||||
Some(bcs.derive_shared_secret(network_key_password.as_bytes(), network_key_password.as_bytes()).expect("failed to derive network key"))
|
Some(bcs.derive_shared_secret(network_key_password.as_bytes(), network_key_password.as_bytes()).expect("failed to derive network key"))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
network_key
|
network_key
|
||||||
@ -795,7 +798,7 @@ impl NetworkManager {
|
|||||||
// Encode envelope
|
// Encode envelope
|
||||||
let envelope = Envelope::new(version, node_id.kind, ts, nonce, node_id.value, dest_node_id.value);
|
let envelope = Envelope::new(version, node_id.kind, ts, nonce, node_id.value, dest_node_id.value);
|
||||||
envelope
|
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")
|
.wrap_err("envelope failed to encode")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -835,10 +838,7 @@ impl NetworkManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Build the envelope to send
|
// Build the envelope to send
|
||||||
let mut out = self.build_envelope(best_node_id, envelope_version, body)?;
|
let out = self.build_envelope(best_node_id, envelope_version, body)?;
|
||||||
|
|
||||||
// Apply network key
|
|
||||||
self.apply_network_key(&mut out);
|
|
||||||
|
|
||||||
// Send the envelope via whatever means necessary
|
// Send the envelope via whatever means necessary
|
||||||
self.send_data(node_ref, out).await
|
self.send_data(node_ref, out).await
|
||||||
@ -849,7 +849,7 @@ impl NetworkManager {
|
|||||||
pub async fn send_out_of_band_receipt(
|
pub async fn send_out_of_band_receipt(
|
||||||
&self,
|
&self,
|
||||||
dial_info: DialInfo,
|
dial_info: DialInfo,
|
||||||
mut rcpt_data: Vec<u8>,
|
rcpt_data: Vec<u8>,
|
||||||
) -> EyreResult<()> {
|
) -> EyreResult<()> {
|
||||||
// Do we need to validate the outgoing receipt? Probably not
|
// Do we need to validate the outgoing receipt? Probably not
|
||||||
// because it is supposed to be opaque and the
|
// 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
|
// Also, in the case of an old 'version', returning the receipt
|
||||||
// should not be subject to our ability to decode it
|
// should not be subject to our ability to decode it
|
||||||
|
|
||||||
// Apply network key
|
|
||||||
self.apply_network_key(&mut rcpt_data);
|
|
||||||
|
|
||||||
// Send receipt directly
|
// Send receipt directly
|
||||||
log_net!(debug "send_out_of_band_receipt: dial_info={}", dial_info);
|
log_net!(debug "send_out_of_band_receipt: dial_info={}", dial_info);
|
||||||
network_result_value_or_log!(self
|
network_result_value_or_log!(self
|
||||||
@ -872,28 +869,13 @@ impl NetworkManager {
|
|||||||
Ok(())
|
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
|
// 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
|
// network protocol handler. Processes the envelope, authenticates and decrypts the RPC message
|
||||||
// and passes it to the RPC handler
|
// and passes it to the RPC handler
|
||||||
#[instrument(level = "trace", ret, err, skip(self, data), fields(data.len = data.len()))]
|
#[instrument(level = "trace", ret, err, skip(self, data), fields(data.len = data.len()))]
|
||||||
async fn on_recv_envelope(
|
async fn on_recv_envelope(
|
||||||
&self,
|
&self,
|
||||||
mut data: &mut [u8],
|
data: &mut [u8],
|
||||||
connection_descriptor: ConnectionDescriptor,
|
connection_descriptor: ConnectionDescriptor,
|
||||||
) -> EyreResult<bool> {
|
) -> EyreResult<bool> {
|
||||||
let root = span!(
|
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?
|
// Is this a direct bootstrap request instead of an envelope?
|
||||||
if data[0..4] == *BOOT_MAGIC {
|
if data[0..4] == *BOOT_MAGIC {
|
||||||
network_result_value_or_log!(self.handle_boot_request(connection_descriptor).await? => {});
|
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)
|
// 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,
|
Ok(v) => v,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log_net!(debug "envelope failed to decode: {}", e);
|
log_net!(debug "envelope failed to decode: {}", e);
|
||||||
@ -1041,9 +1020,6 @@ impl NetworkManager {
|
|||||||
// Relay the packet to the desired destination
|
// Relay the packet to the desired destination
|
||||||
log_net!("relaying {} bytes to {}", data.len(), relay_nr);
|
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())
|
network_result_value_or_log!(match self.send_data(relay_nr, data.to_vec())
|
||||||
.await {
|
.await {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
@ -1065,7 +1041,7 @@ impl NetworkManager {
|
|||||||
|
|
||||||
// Decrypt the envelope body
|
// Decrypt the envelope body
|
||||||
let body = match envelope
|
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,
|
Ok(v) => v,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log_net!(debug "failed to decrypt envelope body: {}",e);
|
log_net!(debug "failed to decrypt envelope body: {}",e);
|
||||||
|
Loading…
Reference in New Issue
Block a user