diff --git a/README.md b/README.md index 8da5fe4..687345a 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ posted to the Niwl Server. The new decrypted message takes its place in the mess ### On the Privacy of REMs Fuzzytags themselves can only be linked to receivers via those in position of a RootSecret *or* Niwl Servers who -possess the `VerificationKey` - as such, assuming that there is no collusion between a particular REM and a Niwl Server +possess the `DetectionKey` - as such, assuming that there is no collusion between a particular REM and a Niwl Server there is no mechanism through which a REM can associate message with a (set of) receiver(s). Further, (again assuming no collusion between a particular REM and a Niwl Server), there is no mechanism for a REM to associate @@ -118,6 +118,21 @@ of the day (or week...etc.) - the only practical defense to this is to have more niwl system other than mixers - as traffic diversity increases, the less utility tells like frequency of message sends ultimately have. + +### Encryption + +For the purposes of this prototype message are encrypted using a simple one-use, unidirectional diffie-hellman derived key, +where the sending party generates an ephemeral keypair (which then uses libsodiums secretbox to perform the actual encryption). +This key binds the message to a particular fuzzytag (which prevents tampering) but does nothing else to certify the +authenticity of the message. + +Because of this only confidentiality and integrity of the message contents is asserted - no authentication mechanisms is provided. +Any party that knows the `PublicKey` and the public `TaggingKey` of another party can encrypt and send messages to them, +and the recipient party has no mechanism to certify the origin of these messages. + +Any applications built on top of Niwl need to provide an additional encryption layer that provides authenticity +(e.g. a complete diffie-hellman key exchange involving pre=exchanged long term identity public keys). + ### Notes on IP and other networking Metadata. niwl is designed to provide metadata security when operated over an unprotected network. Ideally, a niwl server should @@ -128,6 +143,12 @@ Clients may wish to hide their use of niwl from a network adversary (at a risk o This will also further reduce the ability of niwl to correlate senders with specific behaviour and can be seen as complimentary, but optional. +### Notes on future work and expansions + +There is no reason that a client could chain a sequence of mixers together via onion encrypted their original +message to multiple mix nodes. In that sense we can treat the system as a superposition of free-route mix networks. + + # Code Overview @@ -186,4 +207,6 @@ For a more detailed overview please check out each individual crate. ## References -* Danezis, George, and Len Sassaman. "Heartbeat traffic to counter (n-1) attacks: red-green-black mixes." Proceedings of the 2003 ACM workshop on Privacy in the electronic society. 2003. \ No newline at end of file +* Danezis, George, and Len Sassaman. "Heartbeat traffic to counter (n-1) attacks: red-green-black mixes." Proceedings of the 2003 ACM workshop on Privacy in the electronic society. 2003. + +* Sampigethaya, Krishna, and Radha Poovendran. "A survey on mix networks and their secure applications." Proceedings of the IEEE 94.12 (2006): 2142-2181. \ No newline at end of file diff --git a/niwl-client/src/main.rs b/niwl-client/src/main.rs index 5c5be6a..e181d7e 100644 --- a/niwl-client/src/main.rs +++ b/niwl-client/src/main.rs @@ -101,7 +101,7 @@ fn main() { .build() .unwrap() .block_on(async { - let result = profile.tag_and_send(server, contact, &cmd.message).await; + let result = profile.tag_and_send(&server, contact, &cmd.message).await; println!("{}", result.unwrap().text().await.unwrap()); }); } @@ -129,17 +129,29 @@ fn main() { .build() .unwrap() .block_on(async { - match profile.detect_tags(server).await { + match profile.detect_tags(&server).await { Ok(detected_tags) => { + let mut count = 0; + let mut to_me_count = 0; for (tag, ciphertext) in detected_tags.detected_tags.iter() { + count += 1; match profile.private_key.decrypt(ciphertext) { Some(message) => { + to_me_count += 1; println!("message: {}", message) } _ => {} } profile.update_previously_seen_tag(tag); } + if count > 0 { + println!( + "Received {} Messages from server. {} were true positives.", + count, to_me_count + ); + } else { + println!("Received no messages."); + } } Err(err) => { println!("Error: {}", err) diff --git a/niwl-rem/src/lib.rs b/niwl-rem/src/lib.rs index dc757ed..9c167b8 100644 --- a/niwl-rem/src/lib.rs +++ b/niwl-rem/src/lib.rs @@ -24,12 +24,7 @@ impl RandomEjectionMix { pub fn init(tag: Tag<24>) -> RandomEjectionMix { let mut store = vec![]; for i in 0..10 { - let random_tag = RootSecret::<24>::generate().tagging_key().generate_tag(); - let random_secret = PrivateKey::generate(); - let random_encryption = random_secret - .public_key() - .encrypt(&random_tag, &String::new()); - store.push(random_encryption); + store.push(RandomEjectionMix::get_random()); } RandomEjectionMix { @@ -39,6 +34,15 @@ impl RandomEjectionMix { } } + pub fn get_random() -> TaggedCiphertext { + let random_tag = RootSecret::<24>::generate().tagging_key().generate_tag(); + let random_secret = PrivateKey::generate(); + let random_encryption = random_secret + .public_key() + .encrypt(&random_tag, &String::new()); + random_encryption + } + pub fn push(&mut self, tag: &Tag<24>, plaintext: &String) -> Option { // The plaintext can either be a TaggedCiphertext OR a HeartBeat let message: serde_json::Result = diff --git a/niwl-rem/src/main.rs b/niwl-rem/src/main.rs index 4f6ce6e..232c3a2 100644 --- a/niwl-rem/src/main.rs +++ b/niwl-rem/src/main.rs @@ -3,7 +3,7 @@ use clap::Clap; use niwl::Profile; use niwl_rem::MixMessage::Heartbeat; use niwl_rem::{MixMessage, RandomEjectionMix}; -use rand::Rng; +use rand::{thread_rng, Rng}; use std::time::Duration; #[derive(Clap)] @@ -77,9 +77,26 @@ fn main() { if rem.check_heartbeat() == false { - println!("[ERROR] Niwl Server is Delaying Messages for more than 2 Minutes...Possible Attack...") + println!("[ERROR] Niwl Server is Delaying Messages for more than 2 Minutes...Possible Attack..."); + let num_messages : i32 = thread_rng().gen_range(0..100); + // Kick out a random number of messages... + for i in 0..num_messages { + random_delay(); + profile.send_to_self(&server, &serde_json::to_string( + &RandomEjectionMix::get_random(), + ).unwrap()).await; + } + } else { + // After every heart beat kick out a random + // message so we wil eventually clear the pool + random_delay(); + profile.send_to_self(&server,&serde_json::to_string( + &RandomEjectionMix::get_random(), + ).unwrap()).await; + } + match profile.detect_tags(&server).await { Ok(detected_tags) => { let mut latest_tag = None; diff --git a/niwl/src/encrypt.rs b/niwl/src/encrypt.rs index a0ca619..9c9795c 100644 --- a/niwl/src/encrypt.rs +++ b/niwl/src/encrypt.rs @@ -29,6 +29,13 @@ pub struct PublicKey(RistrettoPoint); impl PublicKey { /// Encrypt to Tag provides uni-directional encrypted pub fn encrypt(&self, tag: &Tag<24>, message: &String) -> TaggedCiphertext { + let mut paddedMessage = message.clone(); + if message.len() < 1024 { + for _i in message.len()..1024 { + paddedMessage += " " + } + } + // Generate a random point. We will use the public part as a nonce // And the private part to generate a key. let mut rng = OsRng::default(); @@ -51,7 +58,7 @@ impl PublicKey { let secret_box = SecretBox::new(key, Salsa20).unwrap(); // TODO: Fixed Size Packets - let ciphertext = secret_box.seal(message.as_bytes(), nonce); + let ciphertext = secret_box.seal(paddedMessage.as_bytes(), nonce); TaggedCiphertext { tag: tag.clone(), nonce: z, @@ -91,7 +98,7 @@ impl PrivateKey { let secret_box = SecretBox::new(key, Salsa20).unwrap(); match secret_box.unseal(ciphertext.ciphertext.as_slice(), nonce) { Some(plaintext) => match String::from_utf8(plaintext) { - Ok(plaintext) => Some(plaintext), + Ok(plaintext) => Some(String::from(plaintext.trim_end())), Err(_) => None, }, None => None, diff --git a/references/mixnet-survey-2006.pdf b/references/mixnet-survey-2006.pdf new file mode 100644 index 0000000..5029d03 Binary files /dev/null and b/references/mixnet-survey-2006.pdf differ