mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-04-30 05:02:16 +00:00
Add support for twofish cipher (#457)
This commit is contained in:
parent
ba4bd79fd9
commit
e2960b4317
@ -15,7 +15,8 @@ rand = "0.3.17"
|
|||||||
ring = { version = "0.12", features = ["rsa_signing"] }
|
ring = { version = "0.12", features = ["rsa_signing"] }
|
||||||
aes-ctr = "0.1.0"
|
aes-ctr = "0.1.0"
|
||||||
aesni = { version = "0.4.1", features = ["nocheck"], optional = true }
|
aesni = { version = "0.4.1", features = ["nocheck"], optional = true }
|
||||||
ctr = { version = "0.1", optional = true }
|
twofish = "0.1.0"
|
||||||
|
ctr = "0.1"
|
||||||
lazy_static = { version = "0.2.11", optional = true }
|
lazy_static = { version = "0.2.11", optional = true }
|
||||||
rw-stream-sink = { path = "../../misc/rw-stream-sink" }
|
rw-stream-sink = { path = "../../misc/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 }
|
||||||
@ -25,7 +26,7 @@ untrusted = "0.5"
|
|||||||
[features]
|
[features]
|
||||||
default = ["secp256k1"]
|
default = ["secp256k1"]
|
||||||
secp256k1 = ["eth-secp256k1"]
|
secp256k1 = ["eth-secp256k1"]
|
||||||
aes-all = ["ctr","aesni","lazy_static"]
|
aes-all = ["aesni","lazy_static"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
libp2p-tcp-transport = { path = "../../transports/tcp" }
|
libp2p-tcp-transport = { path = "../../transports/tcp" }
|
||||||
|
@ -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 stream_cipher::KeySize;
|
use stream_cipher::Cipher;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use ring::{agreement, digest};
|
use ring::{agreement, digest};
|
||||||
use error::SecioError;
|
use error::SecioError;
|
||||||
@ -83,9 +83,10 @@ supported_impl!(
|
|||||||
// TODO: the Go & JS implementations advertise Blowfish ; however doing so in Rust leads to
|
// TODO: the Go & JS implementations advertise Blowfish ; however doing so in Rust leads to
|
||||||
// runtime errors
|
// runtime errors
|
||||||
supported_impl!(
|
supported_impl!(
|
||||||
ciphers: KeySize,
|
ciphers: Cipher,
|
||||||
"AES-128" => KeySize::KeySize128,
|
"AES-128" => Cipher::Aes128,
|
||||||
"AES-256" => KeySize::KeySize256,
|
"AES-256" => Cipher::Aes256,
|
||||||
|
"TwofishCTR" => Cipher::Twofish,
|
||||||
);
|
);
|
||||||
|
|
||||||
supported_impl!(
|
supported_impl!(
|
||||||
|
@ -64,7 +64,7 @@ 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 stream_cipher::{ctr, Cipher};
|
||||||
use super::full_codec;
|
use super::full_codec;
|
||||||
use super::DecoderMiddleware;
|
use super::DecoderMiddleware;
|
||||||
use super::EncoderMiddleware;
|
use super::EncoderMiddleware;
|
||||||
@ -93,12 +93,12 @@ mod tests {
|
|||||||
|
|
||||||
let encoder = EncoderMiddleware::new(
|
let encoder = EncoderMiddleware::new(
|
||||||
data_tx,
|
data_tx,
|
||||||
ctr(KeySize::KeySize256, &cipher_key, &NULL_IV[..]),
|
ctr(Cipher::Aes256, &cipher_key, &NULL_IV[..]),
|
||||||
SigningKey::new(&SHA256, &hmac_key),
|
SigningKey::new(&SHA256, &hmac_key),
|
||||||
);
|
);
|
||||||
let decoder = DecoderMiddleware::new(
|
let decoder = DecoderMiddleware::new(
|
||||||
data_rx,
|
data_rx,
|
||||||
ctr(KeySize::KeySize256, &cipher_key, &NULL_IV[..]),
|
ctr(Cipher::Aes256, &cipher_key, &NULL_IV[..]),
|
||||||
VerificationKey::new(&SHA256, &hmac_key),
|
VerificationKey::new(&SHA256, &hmac_key),
|
||||||
32,
|
32,
|
||||||
);
|
);
|
||||||
@ -114,11 +114,11 @@ mod tests {
|
|||||||
assert_eq!(&decoded.unwrap()[..], &data[..]);
|
assert_eq!(&decoded.unwrap()[..], &data[..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
fn full_codec_encode_then_decode(cipher: Cipher) {
|
||||||
fn full_codec_encode_then_decode() {
|
|
||||||
let cipher_key: [u8; 32] = rand::random();
|
let cipher_key: [u8; 32] = rand::random();
|
||||||
let cipher_key_clone = cipher_key.clone();
|
let cipher_key_clone = cipher_key.clone();
|
||||||
let hmac_key: [u8; 32] = rand::random();
|
let key_size = cipher.key_size();
|
||||||
|
let hmac_key: [u8; 16] = rand::random();
|
||||||
let hmac_key_clone = hmac_key.clone();
|
let hmac_key_clone = hmac_key.clone();
|
||||||
let data = b"hello world";
|
let data = b"hello world";
|
||||||
let data_clone = data.clone();
|
let data_clone = data.clone();
|
||||||
@ -132,9 +132,9 @@ mod tests {
|
|||||||
|
|
||||||
full_codec(
|
full_codec(
|
||||||
connec,
|
connec,
|
||||||
ctr(KeySize::KeySize256, &cipher_key, &NULL_IV[..]),
|
ctr(cipher, &cipher_key[..key_size], &NULL_IV[..]),
|
||||||
SigningKey::new(&SHA256, &hmac_key),
|
SigningKey::new(&SHA256, &hmac_key),
|
||||||
ctr(KeySize::KeySize256, &cipher_key, &NULL_IV[..]),
|
ctr(cipher, &cipher_key[..key_size], &NULL_IV[..]),
|
||||||
VerificationKey::new(&SHA256, &hmac_key),
|
VerificationKey::new(&SHA256, &hmac_key),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -147,9 +147,9 @@ mod tests {
|
|||||||
|
|
||||||
full_codec(
|
full_codec(
|
||||||
stream,
|
stream,
|
||||||
ctr(KeySize::KeySize256, &cipher_key_clone, &NULL_IV[..]),
|
ctr(cipher, &cipher_key_clone[..key_size], &NULL_IV[..]),
|
||||||
SigningKey::new(&SHA256, &hmac_key_clone),
|
SigningKey::new(&SHA256, &hmac_key_clone),
|
||||||
ctr(KeySize::KeySize256, &cipher_key_clone, &NULL_IV[..]),
|
ctr(cipher, &cipher_key_clone[..key_size], &NULL_IV[..]),
|
||||||
VerificationKey::new(&SHA256, &hmac_key_clone),
|
VerificationKey::new(&SHA256, &hmac_key_clone),
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
@ -169,4 +169,19 @@ mod tests {
|
|||||||
let received = tokio_current_thread::block_on_all(fin).unwrap();
|
let received = tokio_current_thread::block_on_all(fin).unwrap();
|
||||||
assert_eq!(received, data);
|
assert_eq!(received, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn full_codec_encode_then_decode_aes128() {
|
||||||
|
full_codec_encode_then_decode(Cipher::Aes128);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn full_codec_encode_then_decode_aes256() {
|
||||||
|
full_codec_encode_then_decode(Cipher::Aes256);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn full_codec_encode_then_decode_twofish() {
|
||||||
|
full_codec_encode_then_decode(Cipher::Twofish);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 stream_cipher::{KeySize, ctr};
|
use stream_cipher::{Cipher, ctr};
|
||||||
use error::SecioError;
|
use error::SecioError;
|
||||||
use futures::future;
|
use futures::future;
|
||||||
use futures::sink::Sink;
|
use futures::sink::Sink;
|
||||||
@ -102,7 +102,7 @@ where
|
|||||||
// Crypto algorithms chosen for the communication.
|
// Crypto algorithms chosen for the communication.
|
||||||
chosen_exchange: Option<&'static agreement::Algorithm>,
|
chosen_exchange: Option<&'static agreement::Algorithm>,
|
||||||
// We only support AES for now, so store just a key size.
|
// We only support AES for now, so store just a key size.
|
||||||
chosen_cipher: Option<KeySize>,
|
chosen_cipher: Option<Cipher>,
|
||||||
chosen_hash: Option<&'static digest::Algorithm>,
|
chosen_hash: Option<&'static digest::Algorithm>,
|
||||||
|
|
||||||
// Ephemeral key generated for the handshake and then thrown away.
|
// Ephemeral key generated for the handshake and then thrown away.
|
||||||
@ -453,10 +453,8 @@ where
|
|||||||
let key = SigningKey::new(context.chosen_hash.unwrap(), key_material);
|
let key = SigningKey::new(context.chosen_hash.unwrap(), key_material);
|
||||||
|
|
||||||
let chosen_cipher = context.chosen_cipher.unwrap();
|
let chosen_cipher = context.chosen_cipher.unwrap();
|
||||||
let (cipher_key_size, iv_size) = match chosen_cipher {
|
let cipher_key_size = chosen_cipher.key_size();
|
||||||
KeySize::KeySize128 => (16, 16),
|
let iv_size = chosen_cipher.iv_size();
|
||||||
KeySize::KeySize256 => (32, 16),
|
|
||||||
};
|
|
||||||
|
|
||||||
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)];
|
||||||
stretch_key(&key, &mut longer_key);
|
stretch_key(&key, &mut longer_key);
|
||||||
|
@ -82,6 +82,7 @@ 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 ctr;
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
extern crate libp2p_core;
|
extern crate libp2p_core;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@ -93,6 +94,7 @@ extern crate rw_stream_sink;
|
|||||||
#[cfg(feature = "secp256k1")]
|
#[cfg(feature = "secp256k1")]
|
||||||
extern crate secp256k1;
|
extern crate secp256k1;
|
||||||
extern crate tokio_io;
|
extern crate tokio_io;
|
||||||
|
extern crate twofish;
|
||||||
extern crate untrusted;
|
extern crate untrusted;
|
||||||
|
|
||||||
#[cfg(feature = "aes-all")]
|
#[cfg(feature = "aes-all")]
|
||||||
|
@ -22,22 +22,42 @@ use super::codec::StreamCipher;
|
|||||||
use aes_ctr::stream_cipher::generic_array::GenericArray;
|
use aes_ctr::stream_cipher::generic_array::GenericArray;
|
||||||
use aes_ctr::stream_cipher::NewFixStreamCipher;
|
use aes_ctr::stream_cipher::NewFixStreamCipher;
|
||||||
use aes_ctr::{Aes128Ctr, Aes256Ctr};
|
use aes_ctr::{Aes128Ctr, Aes256Ctr};
|
||||||
|
use ctr::Ctr128;
|
||||||
|
use twofish::Twofish;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum KeySize {
|
pub enum Cipher {
|
||||||
KeySize128,
|
Aes128,
|
||||||
KeySize256,
|
Aes256,
|
||||||
|
Twofish,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns your stream cipher depending on `KeySize`.
|
impl Cipher {
|
||||||
|
/// Returns the size of in bytes of the key expected by the cipher.
|
||||||
|
pub fn key_size(&self) -> usize {
|
||||||
|
match *self {
|
||||||
|
Cipher::Aes128 => 16,
|
||||||
|
Cipher::Aes256 => 32,
|
||||||
|
Cipher::Twofish => 32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the size of in bytes of the IV expected by the cipher.
|
||||||
|
#[inline]
|
||||||
|
pub fn iv_size(&self) -> usize {
|
||||||
|
16 // CTR 128
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns your stream cipher depending on `Cipher`.
|
||||||
#[cfg(not(all(feature = "aes-all", any(target_arch = "x86_64", target_arch = "x86"))))]
|
#[cfg(not(all(feature = "aes-all", any(target_arch = "x86_64", target_arch = "x86"))))]
|
||||||
pub fn ctr(key_size: KeySize, key: &[u8], iv: &[u8]) -> StreamCipher {
|
pub fn ctr(key_size: Cipher, key: &[u8], iv: &[u8]) -> StreamCipher {
|
||||||
ctr_int(key_size, key, iv)
|
ctr_int(key_size, key, iv)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns your stream cipher depending on `KeySize`.
|
/// Returns your stream cipher depending on `Cipher`.
|
||||||
#[cfg(all(feature = "aes-all", any(target_arch = "x86_64", target_arch = "x86")))]
|
#[cfg(all(feature = "aes-all", any(target_arch = "x86_64", target_arch = "x86")))]
|
||||||
pub fn ctr(key_size: KeySize, key: &[u8], iv: &[u8]) -> StreamCipher {
|
pub fn ctr(key_size: Cipher, key: &[u8], iv: &[u8]) -> StreamCipher {
|
||||||
if *aes_alt::AES_NI {
|
if *aes_alt::AES_NI {
|
||||||
aes_alt::ctr_alt(key_size, key, iv)
|
aes_alt::ctr_alt(key_size, key, iv)
|
||||||
} else {
|
} else {
|
||||||
@ -48,14 +68,14 @@ pub fn ctr(key_size: KeySize, key: &[u8], iv: &[u8]) -> StreamCipher {
|
|||||||
|
|
||||||
#[cfg(all(feature = "aes-all", any(target_arch = "x86_64", target_arch = "x86")))]
|
#[cfg(all(feature = "aes-all", any(target_arch = "x86_64", target_arch = "x86")))]
|
||||||
mod aes_alt {
|
mod aes_alt {
|
||||||
extern crate ctr;
|
|
||||||
extern crate aesni;
|
extern crate aesni;
|
||||||
use ::codec::StreamCipher;
|
use ::codec::StreamCipher;
|
||||||
use self::ctr::Ctr128;
|
use ctr::Ctr128;
|
||||||
use self::aesni::{Aes128, Aes256};
|
use self::aesni::{Aes128, Aes256};
|
||||||
use self::ctr::stream_cipher::NewFixStreamCipher;
|
use ctr::stream_cipher::NewFixStreamCipher;
|
||||||
use self::ctr::stream_cipher::generic_array::GenericArray;
|
use ctr::stream_cipher::generic_array::GenericArray;
|
||||||
use super::KeySize;
|
use twofish::Twofish;
|
||||||
|
use super::Cipher;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref AES_NI: bool = is_x86_feature_detected!("aes")
|
pub static ref AES_NI: bool = is_x86_feature_detected!("aes")
|
||||||
@ -70,13 +90,17 @@ mod aes_alt {
|
|||||||
pub type Aes256Ctr = Ctr128<Aes256>;
|
pub type Aes256Ctr = Ctr128<Aes256>;
|
||||||
/// Returns alternate stream cipher if target functionalities does not allow standard one.
|
/// Returns alternate stream cipher if target functionalities does not allow standard one.
|
||||||
/// Eg : aes without sse
|
/// Eg : aes without sse
|
||||||
pub fn ctr_alt(key_size: KeySize, key: &[u8], iv: &[u8]) -> StreamCipher {
|
pub fn ctr_alt(key_size: Cipher, key: &[u8], iv: &[u8]) -> StreamCipher {
|
||||||
match key_size {
|
match key_size {
|
||||||
KeySize::KeySize128 => Box::new(Aes128Ctr::new(
|
Cipher::Aes128 => Box::new(Aes128Ctr::new(
|
||||||
GenericArray::from_slice(key),
|
GenericArray::from_slice(key),
|
||||||
GenericArray::from_slice(iv),
|
GenericArray::from_slice(iv),
|
||||||
)),
|
)),
|
||||||
KeySize::KeySize256 => Box::new(Aes256Ctr::new(
|
Cipher::Aes256 => Box::new(Aes256Ctr::new(
|
||||||
|
GenericArray::from_slice(key),
|
||||||
|
GenericArray::from_slice(iv),
|
||||||
|
)),
|
||||||
|
Cipher::Twofish => Box::new(Ctr128::<Twofish>::new(
|
||||||
GenericArray::from_slice(key),
|
GenericArray::from_slice(key),
|
||||||
GenericArray::from_slice(iv),
|
GenericArray::from_slice(iv),
|
||||||
)),
|
)),
|
||||||
@ -86,13 +110,17 @@ mod aes_alt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn ctr_int(key_size: KeySize, key: &[u8], iv: &[u8]) -> StreamCipher {
|
fn ctr_int(key_size: Cipher, key: &[u8], iv: &[u8]) -> StreamCipher {
|
||||||
match key_size {
|
match key_size {
|
||||||
KeySize::KeySize128 => Box::new(Aes128Ctr::new(
|
Cipher::Aes128 => Box::new(Aes128Ctr::new(
|
||||||
GenericArray::from_slice(key),
|
GenericArray::from_slice(key),
|
||||||
GenericArray::from_slice(iv),
|
GenericArray::from_slice(iv),
|
||||||
)),
|
)),
|
||||||
KeySize::KeySize256 => Box::new(Aes256Ctr::new(
|
Cipher::Aes256 => Box::new(Aes256Ctr::new(
|
||||||
|
GenericArray::from_slice(key),
|
||||||
|
GenericArray::from_slice(iv),
|
||||||
|
)),
|
||||||
|
Cipher::Twofish => Box::new(Ctr128::<Twofish>::new(
|
||||||
GenericArray::from_slice(key),
|
GenericArray::from_slice(key),
|
||||||
GenericArray::from_slice(iv),
|
GenericArray::from_slice(iv),
|
||||||
)),
|
)),
|
||||||
@ -105,7 +133,7 @@ fn ctr_int(key_size: KeySize, key: &[u8], iv: &[u8]) -> StreamCipher {
|
|||||||
))]
|
))]
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{KeySize, ctr};
|
use super::{Cipher, ctr};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn assert_non_native_run() {
|
fn assert_non_native_run() {
|
||||||
@ -113,7 +141,7 @@ mod tests {
|
|||||||
let key = [0;16];
|
let key = [0;16];
|
||||||
let iv = [0;16];
|
let iv = [0;16];
|
||||||
|
|
||||||
let mut aes = ctr(KeySize::KeySize128, &key, &iv);
|
let mut aes = ctr(Cipher::Aes128, &key, &iv);
|
||||||
let mut content = [0;16];
|
let mut content = [0;16];
|
||||||
assert!(aes
|
assert!(aes
|
||||||
.try_apply_keystream(&mut content).is_ok());
|
.try_apply_keystream(&mut content).is_ok());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user