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

remove rustc-serialize (#359) #386

Merged
merged 13 commits into from
Aug 10, 2018
Merged
Show file tree
Hide file tree
Changes from 4 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
6 changes: 5 additions & 1 deletion secio/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ log = "0.4.1"
protobuf = "2.0.2"
rand = "0.3.17"
ring = { version = "0.12.1", features = ["rsa_signing"] }
rust-crypto = "^0.2"
aes-ctr = "0.1.0"
aesni = { git="https://github.com/cheme/block-ciphers.git", features = ["nocheck"], optional = true }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cheme is there anything in the git-repo that isn't in the release on crates.io? Or why can't we use that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes there was a little change, but RustCrypto guys merge it: RustCrypto/block-ciphers#22 , so we can now use the crates.io dependancy (I change it).

ctr = { version = "0.1", optional = true }
lazy_static = { version = "0.2.11", optional = true }
rw-stream-sink = { path = "../rw-stream-sink" }
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1", optional = true }
tokio-io = "0.1.0"
Expand All @@ -22,6 +25,7 @@ untrusted = "0.5.1"
[features]
default = ["secp256k1"]
secp256k1 = ["eth-secp256k1"]
aes-all = ["ctr","aesni","lazy_static"]

[dev-dependencies]
libp2p-tcp-transport = { path = "../tcp-transport" }
Expand Down
2 changes: 1 addition & 1 deletion secio/src/algo_support.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ macro_rules! supported_impl {
pub mod $mod_name {
use std::cmp::Ordering;
#[allow(unused_imports)]
use crypto::aes::KeySize;
use stream_cipher::KeySize;
#[allow(unused_imports)]
use ring::{agreement, digest};
use error::SecioError;
Expand Down
31 changes: 17 additions & 14 deletions secio/src/codec/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
//! Individual messages decoding.

use bytes::BytesMut;
use crypto::symmetriccipher::SynchronousStreamCipher;
use super::StreamCipher;

use error::SecioError;
use futures::sink::Sink;
Expand All @@ -40,7 +40,7 @@ use ring::hmac;
///
/// Also implements `Sink` for convenience.
pub struct DecoderMiddleware<S> {
cipher_state: Box<SynchronousStreamCipher>,
cipher_state: Box<StreamCipher>,
hmac_key: hmac::VerificationKey,
// TODO: when a new version of ring is released, we can use `hmac_key.digest_algorithm().output_len` instead
hmac_num_bytes: usize,
Expand All @@ -51,7 +51,7 @@ impl<S> DecoderMiddleware<S> {
#[inline]
pub fn new(
raw_stream: S,
cipher: Box<SynchronousStreamCipher>,
cipher: Box<StreamCipher>,
hmac_key: hmac::VerificationKey,
hmac_num_bytes: usize, // TODO: remove this parameter
) -> DecoderMiddleware<S> {
Expand Down Expand Up @@ -88,21 +88,24 @@ where
debug!("frame too short when decoding secio frame");
return Err(SecioError::FrameTooShort);
}

let (crypted_data, expected_hash) = frame.split_at(frame.len() - hmac_num_bytes);
debug_assert_eq!(expected_hash.len(), hmac_num_bytes);

if hmac::verify(&self.hmac_key, crypted_data, expected_hash).is_err() {
debug!("hmac mismatch when decoding secio frame");
return Err(SecioError::HmacNotMatching);
let content_length = frame.len() - hmac_num_bytes;
{
let (crypted_data, expected_hash) = frame.split_at(content_length);
debug_assert_eq!(expected_hash.len(), hmac_num_bytes);

if hmac::verify(&self.hmac_key, crypted_data, expected_hash).is_err() {
debug!("hmac mismatch when decoding secio frame");
return Err(SecioError::HmacNotMatching);
}
}

// Note that there is no way to decipher in place with rust-crypto right now.
let mut decrypted_data = crypted_data.to_vec();
let mut data_buf = frame.to_vec();
data_buf.truncate(content_length);
self.cipher_state
.process(&crypted_data, &mut decrypted_data);
.try_apply_keystream(&mut data_buf)
.map_err::<SecioError,_>(|e|e.into())?;

Ok(Async::Ready(Some(decrypted_data)))
Ok(Async::Ready(Some(data_buf)))
}
}

Expand Down
26 changes: 10 additions & 16 deletions secio/src/codec/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
//! Individual messages encoding.

use bytes::BytesMut;
use crypto::symmetriccipher::SynchronousStreamCipher;
use super::StreamCipher;
use futures::sink::Sink;
use futures::stream::Stream;
use futures::Poll;
Expand All @@ -36,15 +36,15 @@ use ring::hmac;
///
/// Also implements `Stream` for convenience.
pub struct EncoderMiddleware<S> {
cipher_state: Box<SynchronousStreamCipher>,
cipher_state: Box<StreamCipher>,
hmac_key: hmac::SigningKey,
raw_sink: S,
}

impl<S> EncoderMiddleware<S> {
pub fn new(
raw_sink: S,
cipher: Box<SynchronousStreamCipher>,
cipher: Box<StreamCipher>,
hmac_key: hmac::SigningKey,
) -> EncoderMiddleware<S> {
EncoderMiddleware {
Expand All @@ -63,21 +63,15 @@ where
type SinkError = S::SinkError;

fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
let capacity = item.len() + self.hmac_key.digest_algorithm().output_len;

// Apparently this is the fastest way of doing.
// See https://gist.github.com/kirushik/e0d93759b0cd102f814408595c20a9d0
let mut out_buffer = BytesMut::from(vec![0; capacity]);
let mut data_buf = item;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this line, instead of renaming the function parameter or using item in the code below?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Useless (just wanted to keep proto looks but does not need to be here).

// TODO if SinkError gets refactor to SecioError,
// then use try_apply_keystream
self.cipher_state.apply_keystream(&mut data_buf[..]);
let signature = hmac::sign(&self.hmac_key, &data_buf[..]);
data_buf.extend_from_slice(signature.as_ref());
self.raw_sink.start_send(data_buf)

{
let (out_data, out_sign) = out_buffer.split_at_mut(item.len());
self.cipher_state.process(&item, out_data);

let signature = hmac::sign(&self.hmac_key, out_data);
out_sign.copy_from_slice(signature.as_ref());
}

self.raw_sink.start_send(out_buffer)
}

#[inline]
Expand Down
47 changes: 17 additions & 30 deletions secio/src/codec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
use self::decode::DecoderMiddleware;
use self::encode::EncoderMiddleware;

use crypto::symmetriccipher::SynchronousStreamCipher;
use aes_ctr::stream_cipher::StreamCipherCore;
use ring::hmac;
use tokio_io::codec::length_delimited;
use tokio_io::{AsyncRead, AsyncWrite};
Expand All @@ -35,16 +35,19 @@ mod encode;
/// Type returned by `full_codec`.
pub type FullCodec<S> = DecoderMiddleware<EncoderMiddleware<length_delimited::Framed<S>>>;

pub type StreamCipher = StreamCipherCore;


/// Takes control of `socket`. Returns an object that implements `future::Sink` and
/// `future::Stream`. The `Stream` and `Sink` produce and accept `BytesMut` objects.
///
/// The conversion between the stream/sink items and the socket is done with the given cipher and
/// hash algorithm (which are generally decided during the handshake).
pub fn full_codec<S>(
socket: length_delimited::Framed<S>,
cipher_encoding: Box<SynchronousStreamCipher>,
cipher_encoding: Box<StreamCipher>,
encoding_hmac: hmac::SigningKey,
cipher_decoder: Box<SynchronousStreamCipher>,
cipher_decoder: Box<StreamCipher>,
decoding_hmac: hmac::VerificationKey,
) -> FullCodec<S>
where
Expand All @@ -61,12 +64,11 @@ mod tests {
extern crate tokio_tcp;
use self::tokio_tcp::TcpListener;
use self::tokio_tcp::TcpStream;
use stream_cipher::{ctr, KeySize};
use super::full_codec;
use super::DecoderMiddleware;
use super::EncoderMiddleware;
use bytes::BytesMut;
use crypto::aessafe::AesSafe256Encryptor;
use crypto::blockmodes::CtrMode;
use error::SecioError;
use futures::sync::mpsc::channel;
use futures::{Future, Sink, Stream};
Expand All @@ -77,6 +79,8 @@ mod tests {
use std::io::Error as IoError;
use tokio_io::codec::length_delimited::Framed;

const NULL_IV : [u8; 16] = [0;16];

#[test]
fn raw_encode_then_decode() {
let (data_tx, data_rx) = channel::<BytesMut>(256);
Expand All @@ -86,20 +90,15 @@ mod tests {
let cipher_key: [u8; 32] = rand::random();
let hmac_key: [u8; 32] = rand::random();


let encoder = EncoderMiddleware::new(
data_tx,
Box::new(CtrMode::new(
AesSafe256Encryptor::new(&cipher_key),
vec![0; 16],
)),
ctr(KeySize::KeySize256, &cipher_key, &NULL_IV[..]),
SigningKey::new(&SHA256, &hmac_key),
);
let decoder = DecoderMiddleware::new(
data_rx,
Box::new(CtrMode::new(
AesSafe256Encryptor::new(&cipher_key),
vec![0; 16],
)),
ctr(KeySize::KeySize256, &cipher_key, &NULL_IV[..]),
VerificationKey::new(&SHA256, &hmac_key),
32,
);
Expand All @@ -112,7 +111,7 @@ mod tests {
let (_, decoded) = tokio_current_thread::block_on_all(data_sent.join(data_received))
.map_err(|_| ())
.unwrap();
assert_eq!(decoded.unwrap(), data);
assert_eq!(&decoded.unwrap()[..], &data[..]);
}

#[test]
Expand All @@ -133,15 +132,9 @@ mod tests {

full_codec(
connec,
Box::new(CtrMode::new(
AesSafe256Encryptor::new(&cipher_key),
vec![0; 16],
)),
ctr(KeySize::KeySize256, &cipher_key, &NULL_IV[..]),
SigningKey::new(&SHA256, &hmac_key),
Box::new(CtrMode::new(
AesSafe256Encryptor::new(&cipher_key),
vec![0; 16],
)),
ctr(KeySize::KeySize256, &cipher_key, &NULL_IV[..]),
VerificationKey::new(&SHA256, &hmac_key),
)
},
Expand All @@ -154,15 +147,9 @@ mod tests {

full_codec(
stream,
Box::new(CtrMode::new(
AesSafe256Encryptor::new(&cipher_key_clone),
vec![0; 16],
)),
ctr(KeySize::KeySize256, &cipher_key_clone, &NULL_IV[..]),
SigningKey::new(&SHA256, &hmac_key_clone),
Box::new(CtrMode::new(
AesSafe256Encryptor::new(&cipher_key_clone),
vec![0; 16],
)),
ctr(KeySize::KeySize256, &cipher_key_clone, &NULL_IV[..]),
VerificationKey::new(&SHA256, &hmac_key_clone),
)
});
Expand Down
10 changes: 5 additions & 5 deletions secio/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

//! Defines the `SecioError` enum that groups all possible errors in SECIO.

use crypto::symmetriccipher::SymmetricCipherError;
use aes_ctr::stream_cipher::LoopError;
use std::error;
use std::fmt;
use std::io::Error as IoError;
Expand Down Expand Up @@ -55,8 +55,8 @@ pub enum SecioError {
/// The final check of the handshake failed.
NonceVerificationFailed,

/// Error while decoding/encoding data.
CipherError(SymmetricCipherError),
/// Error with block cipher.
CipherError(LoopError),

/// The received frame was of invalid length.
FrameTooShort,
Expand Down Expand Up @@ -111,9 +111,9 @@ impl fmt::Display for SecioError {
}
}

impl From<SymmetricCipherError> for SecioError {
impl From<LoopError> for SecioError {
#[inline]
fn from(err: SymmetricCipherError) -> SecioError {
fn from(err: LoopError) -> SecioError {
SecioError::CipherError(err)
}
}
Expand Down
7 changes: 3 additions & 4 deletions secio/src/handshake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
use algo_support;
use bytes::BytesMut;
use codec::{full_codec, FullCodec};
use crypto::aes::{ctr, KeySize};
use stream_cipher::{KeySize, ctr};
use error::SecioError;
use futures::future;
use futures::sink::Sink;
Expand Down Expand Up @@ -456,7 +456,6 @@ where
let (cipher_key_size, iv_size) = match chosen_cipher {
KeySize::KeySize128 => (16, 16),
KeySize::KeySize256 => (32, 16),
_ => panic!()
};

let mut longer_key = vec![0u8; 2 * (iv_size + cipher_key_size + 20)];
Expand Down Expand Up @@ -487,8 +486,8 @@ where
(cipher, hmac)
};

Ok(full_codec(socket, Box::new(encoding_cipher), encoding_hmac,
Box::new(decoding_cipher), decoding_hmac))
Ok(full_codec(socket, encoding_cipher, encoding_hmac,
decoding_cipher, decoding_hmac))
});

match codec {
Expand Down
6 changes: 5 additions & 1 deletion secio/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@
//! `SecioMiddleware` that implements `Sink` and `Stream` and can be used to send packets of data.
//!

extern crate aes_ctr;
#[cfg(feature = "secp256k1")]
extern crate asn1_der;
extern crate bytes;
extern crate crypto;
extern crate futures;
extern crate libp2p_core;
#[macro_use]
Expand All @@ -95,6 +95,9 @@ extern crate secp256k1;
extern crate tokio_io;
extern crate untrusted;

#[cfg(feature = "aes-all")]
#[macro_use]
extern crate lazy_static;
pub use self::error::SecioError;

#[cfg(feature = "secp256k1")]
Expand All @@ -118,6 +121,7 @@ mod codec;
mod error;
mod handshake;
mod structs_proto;
mod stream_cipher;

/// Implementation of the `ConnectionUpgrade` trait of `libp2p_core`. Automatically applies
/// secio on any connection.
Expand Down
Loading