summary history branches tags files
commit:ddebe6894b45641840f9e39eac83282e9f76af1d
author:Trevor Bentley
committer:Trevor Bentley
date:Mon May 27 22:33:21 2019 +0200
parents:a21387231528fddf2f9da9446c7c80121fab974c
Size optimizations for release dylib and new Rust example
diff --git a/Cargo.toml b/Cargo.toml
line changes: +1/-1
index 768267f..09a9921
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,5 +21,5 @@ overflow-checks = false
 [dependencies]
 x25519-dalek = "=0.5.2"
 ed25519-dalek = "=1.0.0-pre.1"
-chacha20-poly1305-aead = "=0.1.2"
+chacha20-poly1305-aead = { version = "=0.1.2", features= ["simd", "simd_opt"] }
 rand = "=0.6.5"

diff --git a/Xargo.toml b/Xargo.toml
line changes: +22/-0
index 0000000..95d07d3
--- /dev/null
+++ b/Xargo.toml
@@ -0,0 +1,22 @@
+# Xargo.toml
+#
+# Uses Xargo to build a local copy of Rust's libstd optimized for size, which
+# allows for better LTO optimization in the final Ossuary release library.
+# Doing this shaves about 100KB off of the shared lib.
+#
+# 'cargo install xargo' and 'rustup component add rust-src' if you need it.
+# Only works with nightly.
+#
+[dependencies]
+std = {default-features=false, features=["panic_immediate_abort"]}
+
+[profile.release]
+panic = "abort"
+opt-level = "z"
+debug = false
+rpath = false
+lto = true
+debug-assertions = false
+codegen-units = 1
+incremental = true
+overflow-checks = false

diff --git a/build_all_and_test.sh b/build_all_and_test.sh
line changes: +28/-0
index 0000000..46b2543
--- /dev/null
+++ b/build_all_and_test.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+set -e
+
+cargo test
+cargo bench -- --nocapture
+cargo build --examples
+cargo build --release --examples
+xargo build --target x86_64-apple-darwin --release
+strip -u -r -x -S target/release/libossuary.dylib
+strip -u -r -x -S target/x86_64-apple-darwin/release/libossuary.dylib
+mkdir -p examples/build/
+pushd examples/build > /dev/null
+cmake ..
+make
+popd > /dev/null
+
+echo ""
+echo "Debug build:"
+ls target/debug/*.dylib
+
+echo ""
+echo "Release build:"
+ls target/x86_64-apple-darwin/release/*.dylib
+
+echo ""
+echo "Examples:"
+find target/debug/examples/ -type f -perm +111 -d 1
+find examples/build/ -type f -perm +111 -d 1

diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
line changes: +22/-10
index 880c3f4..580b59c
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,20 +1,32 @@
 cmake_minimum_required(VERSION 3.12)
 project(ffi C)
 
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -flto -O0 -g")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -flto -O3")
+option(LINK_STATIC "Link against static library" false)
 
 add_executable (ffi ffi.c)
 target_include_directories (ffi PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../ffi)
-target_link_libraries (ffi LINK_PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../target/release/libossuary.dylib)
-
-#target_link_libraries (ffi LINK_PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../target/release/libossuary.a)
-#find_library(SECURITY_FRAMEWORK Security)
-#target_link_libraries(ffi LINK_PUBLIC ${SECURITY_FRAMEWORK})
+if (LINK_STATIC)
+	target_link_libraries (ffi LINK_PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../target/release/libossuary.a)
+	find_library(SECURITY_FRAMEWORK Security)
+	target_link_libraries(ffi LINK_PUBLIC ${SECURITY_FRAMEWORK})
+else()
+	target_link_libraries (ffi LINK_PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../target/release/libossuary.dylib)
+endif()
 
 add_executable (client client.c)
-target_include_directories (client PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../ffi)
-target_link_libraries (client LINK_PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../target/release/libossuary.dylib)
-
 add_executable (server server.c)
+target_include_directories (client PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../ffi)
 target_include_directories (server PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../ffi)
-target_link_libraries (server LINK_PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../target/release/libossuary.dylib)
+
+if (LINK_STATIC)
+	target_link_libraries (client LINK_PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../target/release/libossuary.a)
+	target_link_libraries (server LINK_PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../target/release/libossuary.a)
+	#target_link_libraries (server LINK_PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../target/x86_64-apple-darwin/release/libossuary.a)
+	find_library(SECURITY_FRAMEWORK Security)
+	target_link_libraries(client LINK_PUBLIC ${SECURITY_FRAMEWORK})
+	target_link_libraries(server LINK_PUBLIC ${SECURITY_FRAMEWORK})
+else()
+	target_link_libraries (client LINK_PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../target/release/libossuary.dylib)
+	target_link_libraries (server LINK_PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../target/release/libossuary.dylib)
+endif()

diff --git a/examples/example.rs b/examples/example.rs
line changes: +77/-0
index 0000000..6e8a12b
--- /dev/null
+++ b/examples/example.rs
@@ -0,0 +1,77 @@
+// example.rs
+//
+// Basic example of Ossuary communication library, without authentication
+//
+// Establishes a non-authenticated session between a client and server over a
+// TCP connection, and exchanges encrypted messages.
+//
+use ossuary::{OssuaryConnection, ConnectionType};
+use ossuary::OssuaryError;
+
+use std::thread;
+use std::net::{TcpListener, TcpStream};
+
+fn event_loop(mut conn: OssuaryConnection,
+              mut stream: TcpStream,
+              is_server: bool) -> Result<(), std::io::Error> {
+    let mut strings = vec!("message1", "message2", "message3");
+    let mut plaintext = Vec::<u8>::new();
+    let start = std::time::Instant::now();
+
+    // Simply run for 2 seconds
+    while start.elapsed().as_secs() < 2 {
+        match conn.handshake_done() {
+            // Handshaking
+            Ok(false) => {
+                conn.send_handshake(&mut stream).expect("handshake failed");
+                conn.recv_handshake(&mut stream).expect("handshake failed");
+            },
+            // Transmitting on encrypted connection
+            Ok(true) => {
+                if let Some(plaintext) = strings.pop() {
+                    let _ = conn.send_data(plaintext.as_bytes(), &mut stream);
+                }
+                if let Ok(_) =  conn.recv_data(&mut stream, &mut plaintext) {
+                    println!("({}) received: {:?}", is_server,
+                             String::from_utf8(plaintext.clone()).unwrap());
+                    plaintext.clear();
+                }
+            },
+            // Trust-On-First-Use
+            Err(OssuaryError::UntrustedServer(pubkey)) => {
+                let keys: Vec<&[u8]> = vec![&pubkey];
+                let _ = conn.add_authorized_keys(keys).unwrap();
+            }
+            // Uh-oh.
+            Err(e) => panic!("Handshake failed with error: {:?}", e),
+        }
+    }
+    Ok(())
+}
+
+fn server() -> Result<(), std::io::Error> {
+    let listener = TcpListener::bind("127.0.0.1:9988").unwrap();
+    let stream: TcpStream = listener.incoming().next().unwrap().unwrap();
+    let _ = stream.set_read_timeout(Some(std::time::Duration::from_millis(100u64)));
+    // This server lets any client connect
+    let conn = OssuaryConnection::new(ConnectionType::UnauthenticatedServer, None).unwrap();
+    let _ = event_loop(conn, stream, true);
+    Ok(())
+}
+
+fn client() -> Result<(), std::io::Error> {
+    let stream = TcpStream::connect("127.0.0.1:9988").unwrap();
+    let _ = stream.set_read_timeout(Some(std::time::Duration::from_millis(100u64)));
+    // This client doesn't know any servers, but will use Trust-On-First-Use
+    let conn = OssuaryConnection::new(ConnectionType::Client, None).unwrap();
+    let _ = event_loop(conn, stream, false);
+    Ok(())
+}
+
+fn main() {
+    let server = thread::spawn(move || { let _ = server(); });
+    std::thread::sleep(std::time::Duration::from_millis(500));
+    let child = thread::spawn(move || { let _ = client(); });
+    let _ = child.join();
+    let _ = server.join();
+}

diff --git a/src/clib.rs b/src/clib.rs
line changes: +2/-0
index 96fec85..5c00f36
--- a/src/clib.rs
+++ b/src/clib.rs
@@ -1,3 +1,5 @@
+//! Ossuary API exposed with a C FFI
+//!
 use crate::{OssuaryConnection, ConnectionType, OssuaryError, KEY_LEN, generate_auth_keypair};
 
 pub const OSSUARY_ERR_WOULD_BLOCK: i32 = -64;

diff --git a/src/connection.rs b/src/connection.rs
line changes: +7/-3
index 4dec8b5..d7549b4
--- a/src/connection.rs
+++ b/src/connection.rs
@@ -1,6 +1,5 @@
 use crate::*;
 
-//use rand::thread_rng;
 use rand::RngCore;
 use rand::rngs::OsRng;
 
@@ -27,7 +26,9 @@ impl OssuaryConnection {
     ///
     /// `auth_secret_key` is the secret portion of the long-term Ed25519 key
     /// used for host authentication.  If `None` is provided, a keypair will
-    /// be generated for the lifetime of this connection object.
+    /// be generated for the lifetime of this connection object.  This key
+    /// can be changed with [`OssuaryConnection::set_secret_key`].
+    ///
     pub fn new(conn_type: ConnectionType, auth_secret_key: Option<&[u8]>) -> Result<OssuaryConnection, OssuaryError> {
         let mut rng = OsRng::new().expect("RNG not available.");
 
@@ -199,7 +200,10 @@ impl OssuaryConnection {
         }
         Ok(count)
     }
-    /// Add authentication secret signing key
+    /// Set authentication secret signing key
+    ///
+    /// Changes the secret authentication key of this side of the connection,
+    /// which was previously set by [`OssuaryConnection::new`]
     ///
     /// `key` must be a `&[u8]` slice containing a valid 32-byte ed25519
     /// signing key.  Signing keys should be kept secret and should be stored

diff --git a/src/error.rs b/src/error.rs
line changes: +0/-2
index 44f5538..0a11e13
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,5 +1,3 @@
-use crate::*;
-
 #[derive(Clone, PartialEq)]
 /// Error produced by Ossuary or one of its dependencies
 pub enum OssuaryError {

diff --git a/src/handshake.rs b/src/handshake.rs
line changes: +11/-17
index df76521..f13ff8c
--- a/src/handshake.rs
+++ b/src/handshake.rs
@@ -2,6 +2,8 @@ use crate::*;
 
 use comm::{read_packet, write_packet, write_stored_packet};
 
+use std::io::Write;
+
 const CLIENT_HANDSHAKE_PACKET_LEN: usize = CHALLENGE_LEN + NONCE_LEN + KEY_LEN + 8;
 const CLIENT_AUTH_PACKET_LEN: usize = CLIENT_AUTH_SUBPACKET_LEN + 8;
 const SERVER_HANDSHAKE_PACKET_LEN: usize = NONCE_LEN + KEY_LEN + SERVER_HANDSHAKE_SUBPACKET_LEN + 8;
@@ -123,8 +125,7 @@ impl ServerHandshakePacket {
         enc_pkt.public_key.copy_from_slice(server_pubkey);
         enc_pkt.challenge.copy_from_slice(challenge);
         enc_pkt.signature.copy_from_slice(signature);
-        let mut subpkt: &mut [u8] = &mut pkt.subpacket;
-        encrypt_to_bytes(session_privkey, nonce, struct_as_slice(&enc_pkt), &mut subpkt)?;
+        encrypt_to_bytes(session_privkey, nonce, struct_as_slice(&enc_pkt), &mut pkt.subpacket)?;
         Ok(pkt)
     }
     fn from_packet(pkt: &NetworkPacket) -> Result<&ServerHandshakePacket, OssuaryError> {
@@ -188,8 +189,7 @@ impl ClientAuthenticationPacket {
         let mut enc_pkt: ClientEncryptedAuthenticationPacket = Default::default();
         enc_pkt.public_key.copy_from_slice(client_pubkey);
         enc_pkt.signature.copy_from_slice(signature);
-        let mut subpkt: &mut [u8] = &mut pkt.subpacket;
-        encrypt_to_bytes(session_privkey, nonce, struct_as_slice(&enc_pkt), &mut subpkt)?;
+        encrypt_to_bytes(session_privkey, nonce, struct_as_slice(&enc_pkt), &mut pkt.subpacket)?;
         Ok(pkt)
     }
     fn from_packet(pkt: &NetworkPacket) -> Result<&ClientAuthenticationPacket, OssuaryError> {
@@ -523,9 +523,8 @@ impl OssuaryConnection {
                                     return Err(OssuaryError::InvalidPacket("Received unexpected handshake packet.".into()));
                                 }
                             };
-                            let mut pt: &mut [u8] = &mut plaintext;
                             // note: pt is consumed by decrypt_to_bytes
-                            match decrypt_to_bytes(session, &nonce, &inner_pkt.subpacket, &mut pt) {
+                            match decrypt_to_bytes(session, &nonce, &inner_pkt.subpacket, &mut plaintext) {
                                 Ok(_) => {},
                                 Err(e) => {
                                     self.reset_state(None);
@@ -622,9 +621,8 @@ impl OssuaryConnection {
                                     return Err(OssuaryError::InvalidPacket("Received unexpected handshake packet.".into()));
                                 }
                             };
-                            let mut pt: &mut [u8] = &mut plaintext;
                             // note: pt is consumed by decrypt_to_bytes
-                            match decrypt_to_bytes(session, &nonce, &inner_pkt.subpacket, &mut pt) {
+                            match decrypt_to_bytes(session, &nonce, &inner_pkt.subpacket, &mut plaintext) {
                                 Ok(_) => {},
                                 Err(e) => {
                                     self.reset_state(None);
@@ -735,10 +733,8 @@ impl OssuaryConnection {
     }
 }
 
-fn encrypt_to_bytes<T,U>(session_key: &[u8], nonce: &[u8],
-                         data: &[u8], mut out: T) -> Result<usize, OssuaryError>
-where T: std::ops::DerefMut<Target = U>,
-      U: std::io::Write {
+fn encrypt_to_bytes(session_key: &[u8], nonce: &[u8],
+                    data: &[u8], mut out: &mut [u8]) -> Result<usize, OssuaryError> {
     let aad = [];
     let mut ciphertext = Vec::with_capacity(data.len());
     let tag = match encrypt(session_key,
@@ -762,10 +758,8 @@ where T: std::ops::DerefMut<Target = U>,
     Ok(size)
 }
 
-fn decrypt_to_bytes<T,U>(session_key: &[u8], nonce: &[u8],
-                         data: &[u8], mut out: T) -> Result<usize, OssuaryError>
-where T: std::ops::DerefMut<Target = U>,
-      U: std::io::Write {
+fn decrypt_to_bytes(session_key: &[u8], nonce: &[u8],
+                    data: &[u8], mut out: &mut [u8]) -> Result<usize, OssuaryError> {
     let s: &EncryptedPacket = slice_as_struct(data)?;
     if s.tag_len != 16 {
         return Err(OssuaryError::InvalidPacket("Invalid packet length".into()));
@@ -778,6 +772,6 @@ where T: std::ops::DerefMut<Target = U>,
     decrypt(session_key,
             &nonce,
             &aad, &ciphertext, &tag,
-            out.deref_mut())?;
+            &mut out)?;
     Ok(ciphertext.len())
 }

diff --git a/src/lib.rs b/src/lib.rs
line changes: +0/-5
index b521cae..268f994
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -135,11 +135,6 @@ mod error;
 
 pub use error::OssuaryError;
 
-extern crate x25519_dalek;
-extern crate ed25519_dalek;
-extern crate rand;
-extern crate chacha20_poly1305_aead;
-
 use chacha20_poly1305_aead::{encrypt,decrypt};
 use x25519_dalek::{EphemeralSecret, PublicKey as EphemeralPublic, SharedSecret};
 use ed25519_dalek::{Signature, Keypair, SecretKey, PublicKey};