Compare commits

...

3 Commits

Author SHA1 Message Date
Simon Wicky 7915e05021 change log level for key storage 2023-06-05 13:34:25 +02:00
Simon Wicky dfc12b1aaa freeze secret for packet gen 2023-05-30 14:44:39 +00:00
Simon Wicky 5ed97fb3c9 add rey reuse 2023-05-30 13:50:10 +00:00
10 changed files with 401 additions and 357 deletions
Generated
+306 -349
View File
File diff suppressed because it is too large Load Diff
@@ -169,7 +169,7 @@ impl Client {
pub async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> { pub async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.query_nym_api( self.query_nym_api(
&[routes::API_VERSION, routes::MIXNODES, routes::ACTIVE], &[routes::API_VERSION, routes::MIXNODES],
NO_PARAMS, NO_PARAMS,
) )
.await .await
@@ -0,0 +1,38 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
use nym_sphinx_types::{
SharedSecret, RoutingKeys
};
#[derive(Clone, Debug)]
pub struct KeyStorage(Arc<Mutex<HashMap<SharedSecret, (RoutingKeys, Option<SharedSecret>)>>>);
impl KeyStorage {
pub fn new() -> Self {
KeyStorage(Arc::new(Mutex::new(
HashMap::new()
)))
}
pub fn lookup(&self, key : SharedSecret) -> Option<(RoutingKeys, Option<SharedSecret>)> {
match self.0.lock() {
Ok(map) => map.get(&key).cloned(),
Err(_) => None,
}
}
pub fn store(&self, key : SharedSecret, routing_key : RoutingKeys, blinded_shared_secret : Option<SharedSecret>) {
match self.0.lock() {
Ok(mut map) => map.insert(key, (routing_key, blinded_shared_secret)),
Err(_) => return,
};
}
}
@@ -3,3 +3,4 @@
pub mod error; pub mod error;
pub mod processor; pub mod processor;
mod key_storage;
@@ -3,6 +3,7 @@
use crate::measure; use crate::measure;
use crate::packet_processor::error::MixProcessingError; use crate::packet_processor::error::MixProcessingError;
use crate::packet_processor::key_storage::KeyStorage;
use log::*; use log::*;
use nym_sphinx_acknowledgements::surb_ack::SurbAck; use nym_sphinx_acknowledgements::surb_ack::SurbAck;
use nym_sphinx_addressing::nodes::NymNodeRoutingAddress; use nym_sphinx_addressing::nodes::NymNodeRoutingAddress;
@@ -11,7 +12,7 @@ use nym_sphinx_framing::packet::FramedSphinxPacket;
use nym_sphinx_params::{PacketMode, PacketSize}; use nym_sphinx_params::{PacketMode, PacketSize};
use nym_sphinx_types::{ use nym_sphinx_types::{
Delay as SphinxDelay, DestinationAddressBytes, NodeAddressBytes, Payload, PrivateKey, Delay as SphinxDelay, DestinationAddressBytes, NodeAddressBytes, Payload, PrivateKey,
ProcessedPacket, SphinxPacket, ProcessedPacket, RoutingKeys, SharedSecret, SphinxPacket,
}; };
use std::convert::TryFrom; use std::convert::TryFrom;
use std::sync::Arc; use std::sync::Arc;
@@ -38,6 +39,7 @@ pub enum MixProcessingResult {
pub struct SphinxPacketProcessor { pub struct SphinxPacketProcessor {
/// Private sphinx key of this node required to unwrap received sphinx packet. /// Private sphinx key of this node required to unwrap received sphinx packet.
sphinx_key: Arc<PrivateKey>, sphinx_key: Arc<PrivateKey>,
key_storage: KeyStorage,
} }
impl SphinxPacketProcessor { impl SphinxPacketProcessor {
@@ -45,6 +47,7 @@ impl SphinxPacketProcessor {
pub fn new(sphinx_key: PrivateKey) -> Self { pub fn new(sphinx_key: PrivateKey) -> Self {
SphinxPacketProcessor { SphinxPacketProcessor {
sphinx_key: Arc::new(sphinx_key), sphinx_key: Arc::new(sphinx_key),
key_storage: KeyStorage::new(),
} }
} }
@@ -65,6 +68,27 @@ impl SphinxPacketProcessor {
}) })
} }
/// Performs a sphinx unwrapping using given keys.
#[cfg_attr(
feature = "cpucycles",
instrument(skip(self, packet), fields(cpucycles))
)]
fn perform_initial_sphinx_packet_processing_with_keys(
&self,
packet: SphinxPacket,
new_blinded_secret: &Option<SharedSecret>,
routing_keys: RoutingKeys,
) -> Result<ProcessedPacket, MixProcessingError> {
measure!({
packet
.process_with_derived_keys(new_blinded_secret, routing_keys)
.map_err(|err| {
debug!("Failed to unwrap Sphinx packet: {err}");
MixProcessingError::SphinxProcessingError(err)
})
})
}
/// Takes the received framed packet and tries to unwrap it from the sphinx encryption. /// Takes the received framed packet and tries to unwrap it from the sphinx encryption.
#[cfg_attr( #[cfg_attr(
feature = "cpucycles", feature = "cpucycles",
@@ -81,8 +105,28 @@ impl SphinxPacketProcessor {
if packet_mode.is_old_vpn() { if packet_mode.is_old_vpn() {
return Err(MixProcessingError::ReceivedOldTypeVpnPacket); return Err(MixProcessingError::ReceivedOldTypeVpnPacket);
} }
//here be shared secret retrieval and hashmap lookup
self.perform_initial_sphinx_packet_processing(sphinx_packet) if let Some((routing_keys, blinded_shared_secret)) =
self.key_storage.lookup(sphinx_packet.shared_secret())
{
trace!("Packet already seen, reusing keys");
self.perform_initial_sphinx_packet_processing_with_keys(
sphinx_packet,
&blinded_shared_secret,
routing_keys,
)
} else {
trace!("New packet, deriving keys and storing them");
let key_secret = sphinx_packet.shared_secret();
let processed_packet =
self.perform_initial_sphinx_packet_processing(sphinx_packet)?;
self.key_storage.store(
key_secret,
processed_packet.routing_keys(),
processed_packet.shared_secret(),
);
Ok(processed_packet)
}
}) })
} }
@@ -175,12 +219,12 @@ impl SphinxPacketProcessor {
packet_mode: PacketMode, packet_mode: PacketMode,
) -> Result<MixProcessingResult, MixProcessingError> { ) -> Result<MixProcessingResult, MixProcessingError> {
match packet { match packet {
ProcessedPacket::ForwardHop(packet, address, delay) => { ProcessedPacket::ForwardHop(packet, address, delay, _) => {
self.process_forward_hop(*packet, address, delay, packet_mode) self.process_forward_hop(*packet, address, delay, packet_mode)
} }
// right now there's no use for the surb_id included in the header - probably it should get removed from the // right now there's no use for the surb_id included in the header - probably it should get removed from the
// sphinx all together? // sphinx all together?
ProcessedPacket::FinalHop(destination, _, payload) => { ProcessedPacket::FinalHop(destination, _, payload, _) => {
self.process_final_hop(destination, payload, packet_size, packet_mode) self.process_final_hop(destination, payload, packet_size, packet_mode)
} }
} }
@@ -60,6 +60,7 @@ impl SurbAck {
let surb_ack_packet = SphinxPacketBuilder::new() let surb_ack_packet = SphinxPacketBuilder::new()
.with_payload_size(PacketSize::AckPacket.payload_size()) .with_payload_size(PacketSize::AckPacket.payload_size())
.with_initial_secret(&[42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42].into())
.build_packet(surb_ack_payload, &route, &destination, &delays) .build_packet(surb_ack_payload, &route, &destination, &delays)
.unwrap(); .unwrap();
+1
View File
@@ -113,6 +113,7 @@ where
// once merged, that's an easy rng injection point for sphinx packets : ) // once merged, that's an easy rng injection point for sphinx packets : )
let packet = SphinxPacketBuilder::new() let packet = SphinxPacketBuilder::new()
.with_payload_size(packet_size.payload_size()) .with_payload_size(packet_size.payload_size())
.with_initial_secret(&[42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42].into())
.build_packet(packet_payload, &route, &destination, &delays) .build_packet(packet_payload, &route, &destination, &delays)
.unwrap(); .unwrap();
+1
View File
@@ -208,6 +208,7 @@ pub trait FragmentPreparer {
// there's absolutely no reason for this call to fail. // there's absolutely no reason for this call to fail.
let sphinx_packet = SphinxPacketBuilder::new() let sphinx_packet = SphinxPacketBuilder::new()
.with_payload_size(packet_size.payload_size()) .with_payload_size(packet_size.payload_size())
.with_initial_secret(&[42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42].into())
.build_packet(packet_payload, &route, &destination, &delays) .build_packet(packet_payload, &route, &destination, &delays)
.unwrap(); .unwrap();
+2 -1
View File
@@ -8,7 +8,8 @@ license = { workspace = true }
repository = { workspace = true } repository = { workspace = true }
[dependencies] [dependencies]
sphinx-packet = { version = "0.1.0" } #sphinx-packet = { version = "0.1.0" }
sphinx-packet = { git = "https://github.com/nymtech/sphinx.git", branch = "simon/key-reuse"}
#[patch.crates-io] #[patch.crates-io]
#sphinx-packet = { path = "../../../../sphinx" } #sphinx-packet = { path = "../../../../sphinx" }
+1 -1
View File
@@ -8,7 +8,7 @@ pub use sphinx_packet::{
PAYLOAD_KEY_SIZE, PAYLOAD_KEY_SIZE,
}, },
crypto::{self, EphemeralSecret, PrivateKey, PublicKey, SharedSecret}, crypto::{self, EphemeralSecret, PrivateKey, PublicKey, SharedSecret},
header::{self, delays, delays::Delay, ProcessedHeader, SphinxHeader, HEADER_SIZE}, header::{self, delays, delays::Delay, ProcessedHeader, SphinxHeader, HEADER_SIZE, keys::RoutingKeys},
packet::builder::{self, DEFAULT_PAYLOAD_SIZE}, packet::builder::{self, DEFAULT_PAYLOAD_SIZE},
payload::{Payload, PAYLOAD_OVERHEAD_SIZE}, payload::{Payload, PAYLOAD_OVERHEAD_SIZE},
route::{Destination, DestinationAddressBytes, Node, NodeAddressBytes, SURBIdentifier}, route::{Destination, DestinationAddressBytes, Node, NodeAddressBytes, SURBIdentifier},