Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
286 changes: 286 additions & 0 deletions Cargo.lock

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ block-modes = "0.2"
bloom-filter-rs = "0.1"
byteorder = "1.2"
bytes = "0.4"
c2-chacha = "0.1"
chrono = "0.4"
clap = { version = "2.32", optional = true }
config = { version = "0.9", default-features = false, features = ["toml"] }
Expand All @@ -26,6 +27,7 @@ data-encoding = "2.1"
env_logger = { version = "0.6", optional = true }
flate2 = "1.0"
futures = "0.1"
hkdf = "0.7"
i2p_ring = { git = "https://github.com/str4d/ring.git", rev = "7fe5a141201e4931ea2bbcd7eb3302fbf22867e9" }
i2p_snow = "0.5.1"
itertools = "0.8"
Expand All @@ -52,9 +54,11 @@ tokio-threadpool = "0.1"
tokio-timer = "0.2"
tokio-tls = "0.2"
untrusted = "0.6"
x25519-dalek = { version = "0.4", default-features = false, features = ["std", "u64_backend"] }
zip = { version = "0.5", default-features = false, features = ["deflate"] }

[dev-dependencies]
criterion = "0.2"
pretty_assertions = "0.5"
tempfile = "3"

Expand All @@ -65,3 +69,7 @@ nightly = []
[[bin]]
name = "ire"
required-features = ["cli"]

[[bench]]
name = "encls2_client_auth"
harness = false
191 changes: 191 additions & 0 deletions benches/encls2_client_auth.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
use criterion::{criterion_group, criterion_main, Criterion};
use ire::{
crypto::{SigningPrivateKey, SigningPublicKey},
data::{
dest::DestinationSecretKeys,
ls2::{
enc::{
auth::{ClientInfo, ClientSecretKey, PSKClientInfo, X25519ClientInfo},
EncLS2Payload, EncryptedLS2,
},
LeaseSet2,
},
},
};
use rand::{thread_rng, Rng, RngCore};
use x25519_dalek::{x25519, X25519_BASEPOINT_BYTES};

fn fake_ls2(created: u32, expires: u16) -> LeaseSet2 {
let (dest, ls2_sigkey) = {
let dsk = DestinationSecretKeys::new();
(dsk.dest, dsk.signing_private_key)
};

let mut ls2 = LeaseSet2::new(dest, created, expires, None);
ls2.sign(&ls2_sigkey).unwrap();
ls2
}

fn server_x25519(c: &mut Criterion) {
let mut rng = thread_rng();
let ls2 = fake_ls2(123_456_789, 2345);

let payload = EncLS2Payload::LS2(ls2);
let credential = b"credential";

let blinded_privkey = SigningPrivateKey::new();
let blinded_pubkey = SigningPublicKey::from_secret(&blinded_privkey).unwrap();

c.bench_function_over_inputs(
"EncLS2_Server_X25519",
move |b, &&count| {
let mut client_info = Vec::with_capacity(count);
for _ in 0..count {
let mut x25519_sk = [0u8; 32];
rng.fill_bytes(&mut x25519_sk);
let x25519_pk = x25519(x25519_sk, X25519_BASEPOINT_BYTES);
client_info.push(X25519ClientInfo(x25519_pk));
}
let client_info = ClientInfo::X25519(client_info);

b.iter(|| {
EncryptedLS2::encrypt_payload(
&payload,
credential,
blinded_pubkey.clone(),
None,
&blinded_privkey,
Some(client_info.clone()),
)
})
},
&[1, 10, 20, 50, 100],
);
}

fn client_x25519(c: &mut Criterion) {
let mut rng = thread_rng();
let ls2 = fake_ls2(123_456_789, 2345);

let payload = EncLS2Payload::LS2(ls2);
let credential = b"credential";

let blinded_privkey = SigningPrivateKey::new();
let blinded_pubkey = SigningPublicKey::from_secret(&blinded_privkey).unwrap();

c.bench_function_over_inputs(
"EncLS2_Client_X25519",
move |b, &&count| {
let mut auth_keys = Vec::with_capacity(count);
let mut client_info = Vec::with_capacity(count);
for _ in 0..count {
let mut x25519_sk = [0u8; 32];
rng.fill_bytes(&mut x25519_sk);
let x25519_pk = x25519(x25519_sk, X25519_BASEPOINT_BYTES);

auth_keys.push(ClientSecretKey::X25519(x25519_sk));
client_info.push(X25519ClientInfo(x25519_pk));
}
let client_info = ClientInfo::X25519(client_info);

let enc_ls2 = EncryptedLS2::encrypt_payload(
&payload,
credential,
blinded_pubkey.clone(),
None,
&blinded_privkey,
Some(client_info.clone()),
)
.unwrap();

b.iter(|| enc_ls2.decrypt(credential, Some(&auth_keys.last().unwrap())))
},
&[1, 10, 20, 50, 100],
);
}

fn server_psk(c: &mut Criterion) {
let mut rng = thread_rng();
let ls2 = fake_ls2(123_456_789, 2345);

let payload = EncLS2Payload::LS2(ls2);
let credential = b"credential";

let blinded_privkey = SigningPrivateKey::new();
let blinded_pubkey = SigningPublicKey::from_secret(&blinded_privkey).unwrap();

c.bench_function_over_inputs(
"EncLS2_Server_PSK",
move |b, &&count| {
let mut client_info = Vec::with_capacity(count);
for _ in 0..count {
let mut psk = [0; 32];
rng.fill(&mut psk[..]);
client_info.push(PSKClientInfo(psk));
}
let client_info = ClientInfo::PSK(client_info);

b.iter(|| {
EncryptedLS2::encrypt_payload(
&payload,
credential,
blinded_pubkey.clone(),
None,
&blinded_privkey,
Some(client_info.clone()),
)
})
},
&[1, 10, 20, 50, 100],
);
}

fn client_psk(c: &mut Criterion) {
let mut rng = thread_rng();
let ls2 = fake_ls2(123_456_789, 2345);

let payload = EncLS2Payload::LS2(ls2);
let credential = b"credential";

let blinded_privkey = SigningPrivateKey::new();
let blinded_pubkey = SigningPublicKey::from_secret(&blinded_privkey).unwrap();

c.bench_function_over_inputs(
"EncLS2_Client_PSK",
move |b, &&count| {
let mut auth_keys = Vec::with_capacity(count);
let mut client_info = Vec::with_capacity(count);
for _ in 0..count {
let mut psk = [0; 32];
rng.fill(&mut psk[..]);
let mut client_psk = [0; 32];
client_psk.copy_from_slice(&psk[..]);
auth_keys.push(ClientSecretKey::PSK(client_psk));
client_info.push(PSKClientInfo(psk));
}
let client_info = ClientInfo::PSK(client_info);

let enc_ls2 = EncryptedLS2::encrypt_payload(
&payload,
credential,
blinded_pubkey.clone(),
None,
&blinded_privkey,
Some(client_info.clone()),
)
.unwrap();

b.iter(|| enc_ls2.decrypt(credential, Some(&auth_keys.last().unwrap())))
},
&[1, 10, 20, 50, 100],
);
}

criterion_group!(
benches,
server_x25519,
client_x25519,
server_psk,
client_psk
);
criterion_main!(benches);
7 changes: 7 additions & 0 deletions src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,10 @@ pub const HIDDEN_CERT: u8 = 2;
pub const SIGNED_CERT: u8 = 3;
pub const MULTI_CERT: u8 = 4;
pub const KEY_CERT: u8 = 5;

// NetDB store types
pub const NETDB_STORE_RI: u8 = 0;
pub const NETDB_STORE_LS: u8 = 1;
pub const NETDB_STORE_LS2: u8 = 3;
pub const NETDB_STORE_ENC_LS2: u8 = 5;
pub const NETDB_STORE_META_LS2: u8 = 7;
33 changes: 32 additions & 1 deletion src/crypto/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use crate::constants;
use crate::crypto::{
EncType, PrivateKey, PublicKey, SessionKey, SigType, Signature, SigningPrivateKey,
CryptoKey, EncType, PrivateKey, PublicKey, SessionKey, SigType, Signature, SigningPrivateKey,
SigningPublicKey,
};

Expand Down Expand Up @@ -55,6 +55,37 @@
// Key material and signatures
//

// CryptoKey

named!(
pub crypto_key<CryptoKey>,
switch!(be_u16,
constants::ELGAMAL2048 => do_parse!(
tag!(b"\x01\x00") >> pubkey: public_key >> (CryptoKey::ElGamalAES(pubkey))

Check warning on line 64 in src/crypto/frame.rs

View check run for this annotation

Codecov / codecov/patch

src/crypto/frame.rs#L63-L64

Added lines #L63 - L64 were not covered by tests
) |
crypto_type => do_parse!(

Check warning on line 66 in src/crypto/frame.rs

View check run for this annotation

Codecov / codecov/patch

src/crypto/frame.rs#L66

Added line #L66 was not covered by tests
data: length_data!(be_u16)
>> (CryptoKey::Unsupported(crypto_type, data.to_vec()))

Check warning on line 68 in src/crypto/frame.rs

View check run for this annotation

Codecov / codecov/patch

src/crypto/frame.rs#L68

Added line #L68 was not covered by tests
)
)
);

pub fn gen_crypto_key<'a>(

Check warning on line 73 in src/crypto/frame.rs

View check run for this annotation

Codecov / codecov/patch

src/crypto/frame.rs#L73

Added line #L73 was not covered by tests
input: (&'a mut [u8], usize),
crypto_key: &CryptoKey,
) -> Result<(&'a mut [u8], usize), GenError> {
match crypto_key {
CryptoKey::ElGamalAES(pubkey) => do_gen!(

Check warning on line 78 in src/crypto/frame.rs

View check run for this annotation

Codecov / codecov/patch

src/crypto/frame.rs#L77-L78

Added lines #L77 - L78 were not covered by tests
input,
gen_be_u16!(constants::ELGAMAL2048) >> gen_be_u16!(256) >> gen_public_key(pubkey)

Check warning on line 80 in src/crypto/frame.rs

View check run for this annotation

Codecov / codecov/patch

src/crypto/frame.rs#L80

Added line #L80 was not covered by tests
),
CryptoKey::Unsupported(crypto_type, data) => do_gen!(

Check warning on line 82 in src/crypto/frame.rs

View check run for this annotation

Codecov / codecov/patch

src/crypto/frame.rs#L82

Added line #L82 was not covered by tests
input,
gen_be_u16!(*crypto_type) >> gen_be_u16!(data.len()) >> gen_slice!(data)

Check warning on line 84 in src/crypto/frame.rs

View check run for this annotation

Codecov / codecov/patch

src/crypto/frame.rs#L84

Added line #L84 was not covered by tests
),
}
}

// PublicKey

named!(pub public_key<PublicKey>, do_parse!(
Expand Down
27 changes: 25 additions & 2 deletions src/crypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

pub(crate) mod dh;
mod dsa;
pub(crate) mod elgamal;
pub mod elgamal;
pub(crate) mod math;

pub(crate) const AES_BLOCK_SIZE: usize = 16;
Expand All @@ -40,6 +40,7 @@
InvalidKey,
InvalidMessage,
InvalidSignature,
KeyExpired,
NoSignature,
SigningFailed,
TypeMismatch,
Expand All @@ -53,6 +54,7 @@
Error::InvalidKey => "Invalid cryptographic key".fmt(f),
Error::InvalidMessage => "Invalid message".fmt(f),
Error::InvalidSignature => "Bad signature".fmt(f),
Error::KeyExpired => "Key expired".fmt(f),
Error::NoSignature => "No signature".fmt(f),
Error::SigningFailed => "Failed to create a signature".fmt(f),
Error::TypeMismatch => "Signature type doesn't match key type".fmt(f),
Expand Down Expand Up @@ -156,7 +158,7 @@
}
}

/// Various encryption algorithms present on the network.
/// Field in a RouterInfo or Destination KeyCertificate.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum EncType {
ElGamal2048,
Expand Down Expand Up @@ -188,6 +190,27 @@
// Key material and signatures
//

/// Key material for initiating various end-to-end encryption algorithms.
#[derive(Clone, Debug)]
pub enum CryptoKey {
ElGamalAES(PublicKey),
Unsupported(u16, Vec<u8>),
}

pub enum CryptoSecretKey {
ElGamalAES(PrivateKey),
}

impl CryptoSecretKey {
pub fn new_keypair() -> (Self, CryptoKey) {
let (privkey, pubkey) = elgamal::KeyPairGenerator::generate();

Check warning on line 206 in src/crypto/mod.rs

View check run for this annotation

Codecov / codecov/patch

src/crypto/mod.rs#L205-L206

Added lines #L205 - L206 were not covered by tests
(
CryptoSecretKey::ElGamalAES(privkey),
CryptoKey::ElGamalAES(pubkey),

Check warning on line 209 in src/crypto/mod.rs

View check run for this annotation

Codecov / codecov/patch

src/crypto/mod.rs#L208-L209

Added lines #L208 - L209 were not covered by tests
)
}
}

/// The public component of an ElGamal encryption keypair. Represents only the
/// exponent, not the primes (which are constants).
pub struct PublicKey(pub [u8; 256]);
Expand Down
2 changes: 1 addition & 1 deletion src/data/dest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub(crate) mod frame;

/// A Destination defines a particular endpoint to which messages can be
/// directed for secure delivery.
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct Destination {
pub(super) public_key: PublicKey,
pub(super) padding: Option<Padding>,
Expand Down
2 changes: 1 addition & 1 deletion src/data/dest/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::data::frame::{

#[cfg_attr(rustfmt, rustfmt_skip)]
named!(
destination<Destination>,
pub destination<Destination>,
do_parse!(
public_key: public_key >>
signing_data: take!(constants::KEYCERT_SIGKEY_BYTES) >>
Expand Down
Loading