mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-04-26 03:12:12 +00:00
* Replace rust-crypto dependency by RustCrypto project crate aes-ctr * Support for x86 build supporting both aesni and aessoft at runtime. Feature gated behind 'aes-all'. Building requires RUSTFLAGS="-C target-feature=+aes,+ssse3" and RUSTDOCFLAGS="-C target-feature=+aes,+ssse3". Only support x86 case. * Change CI to build with aes ni on all-features * Switch aes-all logic (is_x86 runtime test did not work as I thought when RUSTC aes and sse are enabled). To build with aes-all, aes and sse flag should not be set. * Use latest aesni from crates.io (with pr to disable compile time checks). * Replace rust-crypto dependency by RustCrypto project crate aes-ctr * Support for x86 build supporting both aesni and aessoft at runtime. Feature gated behind 'aes-all'. Building requires RUSTFLAGS="-C target-feature=+aes,+ssse3" and RUSTDOCFLAGS="-C target-feature=+aes,+ssse3". Only support x86 case. * Change CI to build with aes ni on all-features * Switch aes-all logic (is_x86 runtime test did not work as I thought when RUSTC aes and sse are enabled). To build with aes-all, aes and sse flag should not be set. * Use latest aesni from crates.io (with pr to disable compile time checks).
This commit is contained in:
parent
d94fe1b831
commit
73996885cb
@ -13,7 +13,10 @@ log = "0.4.1"
|
|||||||
protobuf = "2.0.2"
|
protobuf = "2.0.2"
|
||||||
rand = "0.3.17"
|
rand = "0.3.17"
|
||||||
ring = { version = "0.12.1", features = ["rsa_signing"] }
|
ring = { version = "0.12.1", features = ["rsa_signing"] }
|
||||||
rust-crypto = "^0.2"
|
aes-ctr = "0.1.0"
|
||||||
|
aesni = { version = "0.4.1", features = ["nocheck"], optional = true }
|
||||||
|
ctr = { version = "0.1", optional = true }
|
||||||
|
lazy_static = { version = "0.2.11", optional = true }
|
||||||
rw-stream-sink = { path = "../rw-stream-sink" }
|
rw-stream-sink = { path = "../rw-stream-sink" }
|
||||||
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1", optional = true }
|
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1", optional = true }
|
||||||
tokio-io = "0.1.0"
|
tokio-io = "0.1.0"
|
||||||
@ -22,6 +25,7 @@ untrusted = "0.5.1"
|
|||||||
[features]
|
[features]
|
||||||
default = ["secp256k1"]
|
default = ["secp256k1"]
|
||||||
secp256k1 = ["eth-secp256k1"]
|
secp256k1 = ["eth-secp256k1"]
|
||||||
|
aes-all = ["ctr","aesni","lazy_static"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
libp2p-tcp-transport = { path = "../tcp-transport" }
|
libp2p-tcp-transport = { path = "../tcp-transport" }
|
||||||
|
@ -28,7 +28,7 @@ macro_rules! supported_impl {
|
|||||||
pub mod $mod_name {
|
pub mod $mod_name {
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crypto::aes::KeySize;
|
use stream_cipher::KeySize;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use ring::{agreement, digest};
|
use ring::{agreement, digest};
|
||||||
use error::SecioError;
|
use error::SecioError;
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
//! Individual messages decoding.
|
//! Individual messages decoding.
|
||||||
|
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
use crypto::symmetriccipher::SynchronousStreamCipher;
|
use super::StreamCipher;
|
||||||
|
|
||||||
use error::SecioError;
|
use error::SecioError;
|
||||||
use futures::sink::Sink;
|
use futures::sink::Sink;
|
||||||
@ -40,7 +40,7 @@ use ring::hmac;
|
|||||||
///
|
///
|
||||||
/// Also implements `Sink` for convenience.
|
/// Also implements `Sink` for convenience.
|
||||||
pub struct DecoderMiddleware<S> {
|
pub struct DecoderMiddleware<S> {
|
||||||
cipher_state: Box<SynchronousStreamCipher>,
|
cipher_state: Box<StreamCipher>,
|
||||||
hmac_key: hmac::VerificationKey,
|
hmac_key: hmac::VerificationKey,
|
||||||
// TODO: when a new version of ring is released, we can use `hmac_key.digest_algorithm().output_len` instead
|
// TODO: when a new version of ring is released, we can use `hmac_key.digest_algorithm().output_len` instead
|
||||||
hmac_num_bytes: usize,
|
hmac_num_bytes: usize,
|
||||||
@ -51,7 +51,7 @@ impl<S> DecoderMiddleware<S> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
raw_stream: S,
|
raw_stream: S,
|
||||||
cipher: Box<SynchronousStreamCipher>,
|
cipher: Box<StreamCipher>,
|
||||||
hmac_key: hmac::VerificationKey,
|
hmac_key: hmac::VerificationKey,
|
||||||
hmac_num_bytes: usize, // TODO: remove this parameter
|
hmac_num_bytes: usize, // TODO: remove this parameter
|
||||||
) -> DecoderMiddleware<S> {
|
) -> DecoderMiddleware<S> {
|
||||||
@ -88,21 +88,24 @@ where
|
|||||||
debug!("frame too short when decoding secio frame");
|
debug!("frame too short when decoding secio frame");
|
||||||
return Err(SecioError::FrameTooShort);
|
return Err(SecioError::FrameTooShort);
|
||||||
}
|
}
|
||||||
|
let content_length = frame.len() - hmac_num_bytes;
|
||||||
let (crypted_data, expected_hash) = frame.split_at(frame.len() - hmac_num_bytes);
|
{
|
||||||
|
let (crypted_data, expected_hash) = frame.split_at(content_length);
|
||||||
debug_assert_eq!(expected_hash.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() {
|
if hmac::verify(&self.hmac_key, crypted_data, expected_hash).is_err() {
|
||||||
debug!("hmac mismatch when decoding secio frame");
|
debug!("hmac mismatch when decoding secio frame");
|
||||||
return Err(SecioError::HmacNotMatching);
|
return Err(SecioError::HmacNotMatching);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Note that there is no way to decipher in place with rust-crypto right now.
|
let mut data_buf = frame.to_vec();
|
||||||
let mut decrypted_data = crypted_data.to_vec();
|
data_buf.truncate(content_length);
|
||||||
self.cipher_state
|
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)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
//! Individual messages encoding.
|
//! Individual messages encoding.
|
||||||
|
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
use crypto::symmetriccipher::SynchronousStreamCipher;
|
use super::StreamCipher;
|
||||||
use futures::sink::Sink;
|
use futures::sink::Sink;
|
||||||
use futures::stream::Stream;
|
use futures::stream::Stream;
|
||||||
use futures::Poll;
|
use futures::Poll;
|
||||||
@ -36,7 +36,7 @@ use ring::hmac;
|
|||||||
///
|
///
|
||||||
/// Also implements `Stream` for convenience.
|
/// Also implements `Stream` for convenience.
|
||||||
pub struct EncoderMiddleware<S> {
|
pub struct EncoderMiddleware<S> {
|
||||||
cipher_state: Box<SynchronousStreamCipher>,
|
cipher_state: Box<StreamCipher>,
|
||||||
hmac_key: hmac::SigningKey,
|
hmac_key: hmac::SigningKey,
|
||||||
raw_sink: S,
|
raw_sink: S,
|
||||||
}
|
}
|
||||||
@ -44,7 +44,7 @@ pub struct EncoderMiddleware<S> {
|
|||||||
impl<S> EncoderMiddleware<S> {
|
impl<S> EncoderMiddleware<S> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
raw_sink: S,
|
raw_sink: S,
|
||||||
cipher: Box<SynchronousStreamCipher>,
|
cipher: Box<StreamCipher>,
|
||||||
hmac_key: hmac::SigningKey,
|
hmac_key: hmac::SigningKey,
|
||||||
) -> EncoderMiddleware<S> {
|
) -> EncoderMiddleware<S> {
|
||||||
EncoderMiddleware {
|
EncoderMiddleware {
|
||||||
@ -63,21 +63,15 @@ where
|
|||||||
type SinkError = S::SinkError;
|
type SinkError = S::SinkError;
|
||||||
|
|
||||||
fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::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.
|
let mut data_buf = item;
|
||||||
// See https://gist.github.com/kirushik/e0d93759b0cd102f814408595c20a9d0
|
// TODO if SinkError gets refactor to SecioError,
|
||||||
let mut out_buffer = BytesMut::from(vec![0; capacity]);
|
// 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]
|
#[inline]
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
use self::decode::DecoderMiddleware;
|
use self::decode::DecoderMiddleware;
|
||||||
use self::encode::EncoderMiddleware;
|
use self::encode::EncoderMiddleware;
|
||||||
|
|
||||||
use crypto::symmetriccipher::SynchronousStreamCipher;
|
use aes_ctr::stream_cipher::StreamCipherCore;
|
||||||
use ring::hmac;
|
use ring::hmac;
|
||||||
use tokio_io::codec::length_delimited;
|
use tokio_io::codec::length_delimited;
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
@ -35,6 +35,9 @@ mod encode;
|
|||||||
/// Type returned by `full_codec`.
|
/// Type returned by `full_codec`.
|
||||||
pub type FullCodec<S> = DecoderMiddleware<EncoderMiddleware<length_delimited::Framed<S>>>;
|
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
|
/// Takes control of `socket`. Returns an object that implements `future::Sink` and
|
||||||
/// `future::Stream`. The `Stream` and `Sink` produce and accept `BytesMut` objects.
|
/// `future::Stream`. The `Stream` and `Sink` produce and accept `BytesMut` objects.
|
||||||
///
|
///
|
||||||
@ -42,9 +45,9 @@ pub type FullCodec<S> = DecoderMiddleware<EncoderMiddleware<length_delimited::Fr
|
|||||||
/// hash algorithm (which are generally decided during the handshake).
|
/// hash algorithm (which are generally decided during the handshake).
|
||||||
pub fn full_codec<S>(
|
pub fn full_codec<S>(
|
||||||
socket: length_delimited::Framed<S>,
|
socket: length_delimited::Framed<S>,
|
||||||
cipher_encoding: Box<SynchronousStreamCipher>,
|
cipher_encoding: Box<StreamCipher>,
|
||||||
encoding_hmac: hmac::SigningKey,
|
encoding_hmac: hmac::SigningKey,
|
||||||
cipher_decoder: Box<SynchronousStreamCipher>,
|
cipher_decoder: Box<StreamCipher>,
|
||||||
decoding_hmac: hmac::VerificationKey,
|
decoding_hmac: hmac::VerificationKey,
|
||||||
) -> FullCodec<S>
|
) -> FullCodec<S>
|
||||||
where
|
where
|
||||||
@ -61,12 +64,11 @@ mod tests {
|
|||||||
extern crate tokio_tcp;
|
extern crate tokio_tcp;
|
||||||
use self::tokio_tcp::TcpListener;
|
use self::tokio_tcp::TcpListener;
|
||||||
use self::tokio_tcp::TcpStream;
|
use self::tokio_tcp::TcpStream;
|
||||||
|
use stream_cipher::{ctr, KeySize};
|
||||||
use super::full_codec;
|
use super::full_codec;
|
||||||
use super::DecoderMiddleware;
|
use super::DecoderMiddleware;
|
||||||
use super::EncoderMiddleware;
|
use super::EncoderMiddleware;
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
use crypto::aessafe::AesSafe256Encryptor;
|
|
||||||
use crypto::blockmodes::CtrMode;
|
|
||||||
use error::SecioError;
|
use error::SecioError;
|
||||||
use futures::sync::mpsc::channel;
|
use futures::sync::mpsc::channel;
|
||||||
use futures::{Future, Sink, Stream};
|
use futures::{Future, Sink, Stream};
|
||||||
@ -77,6 +79,8 @@ mod tests {
|
|||||||
use std::io::Error as IoError;
|
use std::io::Error as IoError;
|
||||||
use tokio_io::codec::length_delimited::Framed;
|
use tokio_io::codec::length_delimited::Framed;
|
||||||
|
|
||||||
|
const NULL_IV : [u8; 16] = [0;16];
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn raw_encode_then_decode() {
|
fn raw_encode_then_decode() {
|
||||||
let (data_tx, data_rx) = channel::<BytesMut>(256);
|
let (data_tx, data_rx) = channel::<BytesMut>(256);
|
||||||
@ -86,20 +90,15 @@ mod tests {
|
|||||||
let cipher_key: [u8; 32] = rand::random();
|
let cipher_key: [u8; 32] = rand::random();
|
||||||
let hmac_key: [u8; 32] = rand::random();
|
let hmac_key: [u8; 32] = rand::random();
|
||||||
|
|
||||||
|
|
||||||
let encoder = EncoderMiddleware::new(
|
let encoder = EncoderMiddleware::new(
|
||||||
data_tx,
|
data_tx,
|
||||||
Box::new(CtrMode::new(
|
ctr(KeySize::KeySize256, &cipher_key, &NULL_IV[..]),
|
||||||
AesSafe256Encryptor::new(&cipher_key),
|
|
||||||
vec![0; 16],
|
|
||||||
)),
|
|
||||||
SigningKey::new(&SHA256, &hmac_key),
|
SigningKey::new(&SHA256, &hmac_key),
|
||||||
);
|
);
|
||||||
let decoder = DecoderMiddleware::new(
|
let decoder = DecoderMiddleware::new(
|
||||||
data_rx,
|
data_rx,
|
||||||
Box::new(CtrMode::new(
|
ctr(KeySize::KeySize256, &cipher_key, &NULL_IV[..]),
|
||||||
AesSafe256Encryptor::new(&cipher_key),
|
|
||||||
vec![0; 16],
|
|
||||||
)),
|
|
||||||
VerificationKey::new(&SHA256, &hmac_key),
|
VerificationKey::new(&SHA256, &hmac_key),
|
||||||
32,
|
32,
|
||||||
);
|
);
|
||||||
@ -112,7 +111,7 @@ mod tests {
|
|||||||
let (_, decoded) = tokio_current_thread::block_on_all(data_sent.join(data_received))
|
let (_, decoded) = tokio_current_thread::block_on_all(data_sent.join(data_received))
|
||||||
.map_err(|_| ())
|
.map_err(|_| ())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(decoded.unwrap(), data);
|
assert_eq!(&decoded.unwrap()[..], &data[..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -133,15 +132,9 @@ mod tests {
|
|||||||
|
|
||||||
full_codec(
|
full_codec(
|
||||||
connec,
|
connec,
|
||||||
Box::new(CtrMode::new(
|
ctr(KeySize::KeySize256, &cipher_key, &NULL_IV[..]),
|
||||||
AesSafe256Encryptor::new(&cipher_key),
|
|
||||||
vec![0; 16],
|
|
||||||
)),
|
|
||||||
SigningKey::new(&SHA256, &hmac_key),
|
SigningKey::new(&SHA256, &hmac_key),
|
||||||
Box::new(CtrMode::new(
|
ctr(KeySize::KeySize256, &cipher_key, &NULL_IV[..]),
|
||||||
AesSafe256Encryptor::new(&cipher_key),
|
|
||||||
vec![0; 16],
|
|
||||||
)),
|
|
||||||
VerificationKey::new(&SHA256, &hmac_key),
|
VerificationKey::new(&SHA256, &hmac_key),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -154,15 +147,9 @@ mod tests {
|
|||||||
|
|
||||||
full_codec(
|
full_codec(
|
||||||
stream,
|
stream,
|
||||||
Box::new(CtrMode::new(
|
ctr(KeySize::KeySize256, &cipher_key_clone, &NULL_IV[..]),
|
||||||
AesSafe256Encryptor::new(&cipher_key_clone),
|
|
||||||
vec![0; 16],
|
|
||||||
)),
|
|
||||||
SigningKey::new(&SHA256, &hmac_key_clone),
|
SigningKey::new(&SHA256, &hmac_key_clone),
|
||||||
Box::new(CtrMode::new(
|
ctr(KeySize::KeySize256, &cipher_key_clone, &NULL_IV[..]),
|
||||||
AesSafe256Encryptor::new(&cipher_key_clone),
|
|
||||||
vec![0; 16],
|
|
||||||
)),
|
|
||||||
VerificationKey::new(&SHA256, &hmac_key_clone),
|
VerificationKey::new(&SHA256, &hmac_key_clone),
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
//! Defines the `SecioError` enum that groups all possible errors in SECIO.
|
//! 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::error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::Error as IoError;
|
use std::io::Error as IoError;
|
||||||
@ -55,8 +55,8 @@ pub enum SecioError {
|
|||||||
/// The final check of the handshake failed.
|
/// The final check of the handshake failed.
|
||||||
NonceVerificationFailed,
|
NonceVerificationFailed,
|
||||||
|
|
||||||
/// Error while decoding/encoding data.
|
/// Error with block cipher.
|
||||||
CipherError(SymmetricCipherError),
|
CipherError(LoopError),
|
||||||
|
|
||||||
/// The received frame was of invalid length.
|
/// The received frame was of invalid length.
|
||||||
FrameTooShort,
|
FrameTooShort,
|
||||||
@ -111,9 +111,9 @@ impl fmt::Display for SecioError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SymmetricCipherError> for SecioError {
|
impl From<LoopError> for SecioError {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(err: SymmetricCipherError) -> SecioError {
|
fn from(err: LoopError) -> SecioError {
|
||||||
SecioError::CipherError(err)
|
SecioError::CipherError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
use algo_support;
|
use algo_support;
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
use codec::{full_codec, FullCodec};
|
use codec::{full_codec, FullCodec};
|
||||||
use crypto::aes::{ctr, KeySize};
|
use stream_cipher::{KeySize, ctr};
|
||||||
use error::SecioError;
|
use error::SecioError;
|
||||||
use futures::future;
|
use futures::future;
|
||||||
use futures::sink::Sink;
|
use futures::sink::Sink;
|
||||||
@ -456,7 +456,6 @@ where
|
|||||||
let (cipher_key_size, iv_size) = match chosen_cipher {
|
let (cipher_key_size, iv_size) = match chosen_cipher {
|
||||||
KeySize::KeySize128 => (16, 16),
|
KeySize::KeySize128 => (16, 16),
|
||||||
KeySize::KeySize256 => (32, 16),
|
KeySize::KeySize256 => (32, 16),
|
||||||
_ => panic!()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut longer_key = vec![0u8; 2 * (iv_size + cipher_key_size + 20)];
|
let mut longer_key = vec![0u8; 2 * (iv_size + cipher_key_size + 20)];
|
||||||
@ -487,8 +486,8 @@ where
|
|||||||
(cipher, hmac)
|
(cipher, hmac)
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(full_codec(socket, Box::new(encoding_cipher), encoding_hmac,
|
Ok(full_codec(socket, encoding_cipher, encoding_hmac,
|
||||||
Box::new(decoding_cipher), decoding_hmac))
|
decoding_cipher, decoding_hmac))
|
||||||
});
|
});
|
||||||
|
|
||||||
match codec {
|
match codec {
|
||||||
|
@ -78,10 +78,10 @@
|
|||||||
//! `SecioMiddleware` that implements `Sink` and `Stream` and can be used to send packets of data.
|
//! `SecioMiddleware` that implements `Sink` and `Stream` and can be used to send packets of data.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
extern crate aes_ctr;
|
||||||
#[cfg(feature = "secp256k1")]
|
#[cfg(feature = "secp256k1")]
|
||||||
extern crate asn1_der;
|
extern crate asn1_der;
|
||||||
extern crate bytes;
|
extern crate bytes;
|
||||||
extern crate crypto;
|
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
extern crate libp2p_core;
|
extern crate libp2p_core;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@ -95,6 +95,9 @@ extern crate secp256k1;
|
|||||||
extern crate tokio_io;
|
extern crate tokio_io;
|
||||||
extern crate untrusted;
|
extern crate untrusted;
|
||||||
|
|
||||||
|
#[cfg(feature = "aes-all")]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
pub use self::error::SecioError;
|
pub use self::error::SecioError;
|
||||||
|
|
||||||
#[cfg(feature = "secp256k1")]
|
#[cfg(feature = "secp256k1")]
|
||||||
@ -118,6 +121,7 @@ mod codec;
|
|||||||
mod error;
|
mod error;
|
||||||
mod handshake;
|
mod handshake;
|
||||||
mod structs_proto;
|
mod structs_proto;
|
||||||
|
mod stream_cipher;
|
||||||
|
|
||||||
/// Implementation of the `ConnectionUpgrade` trait of `libp2p_core`. Automatically applies
|
/// Implementation of the `ConnectionUpgrade` trait of `libp2p_core`. Automatically applies
|
||||||
/// secio on any connection.
|
/// secio on any connection.
|
||||||
|
109
secio/src/stream_cipher.rs
Normal file
109
secio/src/stream_cipher.rs
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
|
||||||
|
use aes_ctr::stream_cipher::generic_array::GenericArray;
|
||||||
|
use aes_ctr::stream_cipher::{NewFixStreamCipher, StreamCipherCore};
|
||||||
|
use aes_ctr::{Aes128Ctr, Aes256Ctr};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum KeySize {
|
||||||
|
KeySize128,
|
||||||
|
KeySize256,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns your stream cipher depending on `KeySize`.
|
||||||
|
#[cfg(not(all(feature = "aes-all", any(target_arch = "x86_64", target_arch = "x86"))))]
|
||||||
|
pub(crate) fn ctr(key_size: KeySize, key: &[u8], iv: &[u8]) -> Box<StreamCipherCore + 'static> {
|
||||||
|
ctr_int(key_size, key, iv)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns your stream cipher depending on `KeySize`.
|
||||||
|
#[cfg(all(feature = "aes-all", any(target_arch = "x86_64", target_arch = "x86")))]
|
||||||
|
pub(crate) fn ctr(key_size: KeySize, key: &[u8], iv: &[u8]) -> Box<StreamCipherCore + 'static> {
|
||||||
|
if *aes_alt::AES_NI {
|
||||||
|
aes_alt::ctr_alt(key_size, key, iv)
|
||||||
|
} else {
|
||||||
|
ctr_int(key_size, key, iv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(all(feature = "aes-all", any(target_arch = "x86_64", target_arch = "x86")))]
|
||||||
|
mod aes_alt {
|
||||||
|
extern crate ctr;
|
||||||
|
extern crate aesni;
|
||||||
|
use self::ctr::Ctr128;
|
||||||
|
use self::aesni::{Aes128, Aes256};
|
||||||
|
use self::ctr::stream_cipher::{NewFixStreamCipher, StreamCipherCore};
|
||||||
|
use self::ctr::stream_cipher::generic_array::GenericArray;
|
||||||
|
use super::KeySize;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref AES_NI: bool = is_x86_feature_detected!("aes")
|
||||||
|
&& is_x86_feature_detected!("sse2")
|
||||||
|
&& is_x86_feature_detected!("sse3");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// AES-128 in CTR mode
|
||||||
|
pub type Aes128Ctr = Ctr128<Aes128>;
|
||||||
|
/// AES-256 in CTR mode
|
||||||
|
pub type Aes256Ctr = Ctr128<Aes256>;
|
||||||
|
/// Returns alternate stream cipher if target functionalities does not allow standard one.
|
||||||
|
/// Eg : aes without sse
|
||||||
|
pub fn ctr_alt(key_size: KeySize, key: &[u8], iv: &[u8]) -> Box<StreamCipherCore + 'static> {
|
||||||
|
match key_size {
|
||||||
|
KeySize::KeySize128 => Box::new(Aes128Ctr::new(
|
||||||
|
GenericArray::from_slice(key),
|
||||||
|
GenericArray::from_slice(iv),
|
||||||
|
)),
|
||||||
|
KeySize::KeySize256 => Box::new(Aes256Ctr::new(
|
||||||
|
GenericArray::from_slice(key),
|
||||||
|
GenericArray::from_slice(iv),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn ctr_int(key_size: KeySize, key: &[u8], iv: &[u8]) -> Box<StreamCipherCore + 'static> {
|
||||||
|
match key_size {
|
||||||
|
KeySize::KeySize128 => Box::new(Aes128Ctr::new(
|
||||||
|
GenericArray::from_slice(key),
|
||||||
|
GenericArray::from_slice(iv),
|
||||||
|
)),
|
||||||
|
KeySize::KeySize256 => Box::new(Aes256Ctr::new(
|
||||||
|
GenericArray::from_slice(key),
|
||||||
|
GenericArray::from_slice(iv),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(
|
||||||
|
feature = "aes-all",
|
||||||
|
any(target_arch = "x86_64", target_arch = "x86"),
|
||||||
|
))]
|
||||||
|
#[test]
|
||||||
|
fn assert_non_native_run() {
|
||||||
|
// this test is for asserting aes unsuported opcode does not break on old cpu
|
||||||
|
let key = [0;16];
|
||||||
|
let iv = [0;16];
|
||||||
|
|
||||||
|
let mut aes = ctr(KeySize::KeySize128, &key, &iv);
|
||||||
|
let mut content = [0;16];
|
||||||
|
assert!(aes
|
||||||
|
.try_apply_keystream(&mut content).is_ok());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// aesni compile check for aes-all (aes-all import aesni through aes_ctr only if those checks pass)
|
||||||
|
#[cfg(all(
|
||||||
|
feature = "aes-all",
|
||||||
|
any(target_arch = "x86_64", target_arch = "x86"),
|
||||||
|
any(target_feature = "aes", target_feature = "ssse3"),
|
||||||
|
))]
|
||||||
|
compile_error!(
|
||||||
|
"aes-all must be compile without aes and sse3 flags : currently \
|
||||||
|
is_x86_feature_detected macro will not detect feature correctly otherwhise. \
|
||||||
|
RUSTFLAGS=\"-C target-feature=+aes,+ssse3\" enviromental variable. \
|
||||||
|
For x86 target arch additionally enable sse2 target feature."
|
||||||
|
);
|
Loading…
x
Reference in New Issue
Block a user