Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LeaseSet2 support #68

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
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 nom::*;

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 @@ pub fn gen_session_key<'a>(
// 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))
) |
crypto_type => do_parse!(
data: length_data!(be_u16)
>> (CryptoKey::Unsupported(crypto_type, data.to_vec()))
)
)
);

pub fn gen_crypto_key<'a>(
input: (&'a mut [u8], usize),
crypto_key: &CryptoKey,
) -> Result<(&'a mut [u8], usize), GenError> {
match crypto_key {
CryptoKey::ElGamalAES(pubkey) => do_gen!(
input,
gen_be_u16!(constants::ELGAMAL2048) >> gen_be_u16!(256) >> gen_public_key(pubkey)
),
CryptoKey::Unsupported(crypto_type, data) => do_gen!(
input,
gen_be_u16!(*crypto_type) >> gen_be_u16!(data.len()) >> gen_slice!(data)
),
}
}

// 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 frame;

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 @@ pub enum Error {
InvalidKey,
InvalidMessage,
InvalidSignature,
KeyExpired,
NoSignature,
SigningFailed,
TypeMismatch,
Expand All @@ -53,6 +54,7 @@ impl fmt::Display for Error {
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 @@ impl SigType {
}
}

/// 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 @@ impl EncType {
// 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();
(
CryptoSecretKey::ElGamalAES(privkey),
CryptoKey::ElGamalAES(pubkey),
)
}
}

/// 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