mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-04-25 11:02:12 +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"] }
|
||||
aes-ctr = "0.1.0"
|
||||
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 }
|
||||
rw-stream-sink = { path = "../../misc/rw-stream-sink" }
|
||||
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1", optional = true }
|
||||
@ -25,7 +26,7 @@ untrusted = "0.5"
|
||||
[features]
|
||||
default = ["secp256k1"]
|
||||
secp256k1 = ["eth-secp256k1"]
|
||||
aes-all = ["ctr","aesni","lazy_static"]
|
||||
aes-all = ["aesni","lazy_static"]
|
||||
|
||||
[dev-dependencies]
|
||||
libp2p-tcp-transport = { path = "../../transports/tcp" }
|
||||
|
@ -28,7 +28,7 @@ macro_rules! supported_impl {
|
||||
pub mod $mod_name {
|
||||
use std::cmp::Ordering;
|
||||
#[allow(unused_imports)]
|
||||
use stream_cipher::KeySize;
|
||||
use stream_cipher::Cipher;
|
||||
#[allow(unused_imports)]
|
||||
use ring::{agreement, digest};
|
||||
use error::SecioError;
|
||||
@ -83,9 +83,10 @@ supported_impl!(
|
||||
// TODO: the Go & JS implementations advertise Blowfish ; however doing so in Rust leads to
|
||||
// runtime errors
|
||||
supported_impl!(
|
||||
ciphers: KeySize,
|
||||
"AES-128" => KeySize::KeySize128,
|
||||
"AES-256" => KeySize::KeySize256,
|
||||
ciphers: Cipher,
|
||||
"AES-128" => Cipher::Aes128,
|
||||
"AES-256" => Cipher::Aes256,
|
||||
"TwofishCTR" => Cipher::Twofish,
|
||||
);
|
||||
|
||||
supported_impl!(
|
||||
|
@ -64,7 +64,7 @@ mod tests {
|
||||
extern crate tokio_tcp;
|
||||
use self::tokio_tcp::TcpListener;
|
||||
use self::tokio_tcp::TcpStream;
|
||||
use stream_cipher::{ctr, KeySize};
|
||||
use stream_cipher::{ctr, Cipher};
|
||||
use super::full_codec;
|
||||
use super::DecoderMiddleware;
|
||||
use super::EncoderMiddleware;
|
||||
@ -93,12 +93,12 @@ mod tests {
|
||||
|
||||
let encoder = EncoderMiddleware::new(
|
||||
data_tx,
|
||||
ctr(KeySize::KeySize256, &cipher_key, &NULL_IV[..]),
|
||||
ctr(Cipher::Aes256, &cipher_key, &NULL_IV[..]),
|
||||
SigningKey::new(&SHA256, &hmac_key),
|
||||
);
|
||||
let decoder = DecoderMiddleware::new(
|
||||
data_rx,
|
||||
ctr(KeySize::KeySize256, &cipher_key, &NULL_IV[..]),
|
||||
ctr(Cipher::Aes256, &cipher_key, &NULL_IV[..]),
|
||||
VerificationKey::new(&SHA256, &hmac_key),
|
||||
32,
|
||||
);
|
||||
@ -114,11 +114,11 @@ mod tests {
|
||||
assert_eq!(&decoded.unwrap()[..], &data[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_codec_encode_then_decode() {
|
||||
fn full_codec_encode_then_decode(cipher: Cipher) {
|
||||
let cipher_key: [u8; 32] = rand::random();
|
||||
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 data = b"hello world";
|
||||
let data_clone = data.clone();
|
||||
@ -132,9 +132,9 @@ mod tests {
|
||||
|
||||
full_codec(
|
||||
connec,
|
||||
ctr(KeySize::KeySize256, &cipher_key, &NULL_IV[..]),
|
||||
ctr(cipher, &cipher_key[..key_size], &NULL_IV[..]),
|
||||
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),
|
||||
)
|
||||
},
|
||||
@ -147,9 +147,9 @@ mod tests {
|
||||
|
||||
full_codec(
|
||||
stream,
|
||||
ctr(KeySize::KeySize256, &cipher_key_clone, &NULL_IV[..]),
|
||||
ctr(cipher, &cipher_key_clone[..key_size], &NULL_IV[..]),
|
||||
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),
|
||||
)
|
||||
});
|
||||
@ -169,4 +169,19 @@ mod tests {
|
||||
let received = tokio_current_thread::block_on_all(fin).unwrap();
|
||||
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 bytes::BytesMut;
|
||||
use codec::{full_codec, FullCodec};
|
||||
use stream_cipher::{KeySize, ctr};
|
||||
use stream_cipher::{Cipher, ctr};
|
||||
use error::SecioError;
|
||||
use futures::future;
|
||||
use futures::sink::Sink;
|
||||
@ -102,7 +102,7 @@ where
|
||||
// Crypto algorithms chosen for the communication.
|
||||
chosen_exchange: Option<&'static agreement::Algorithm>,
|
||||
// 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>,
|
||||
|
||||
// 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 chosen_cipher = context.chosen_cipher.unwrap();
|
||||
let (cipher_key_size, iv_size) = match chosen_cipher {
|
||||
KeySize::KeySize128 => (16, 16),
|
||||
KeySize::KeySize256 => (32, 16),
|
||||
};
|
||||
let cipher_key_size = chosen_cipher.key_size();
|
||||
let iv_size = chosen_cipher.iv_size();
|
||||
|
||||
let mut longer_key = vec![0u8; 2 * (iv_size + cipher_key_size + 20)];
|
||||
stretch_key(&key, &mut longer_key);
|
||||
|
@ -82,6 +82,7 @@ extern crate aes_ctr;
|
||||
#[cfg(feature = "secp256k1")]
|
||||
extern crate asn1_der;
|
||||
extern crate bytes;
|
||||
extern crate ctr;
|
||||
extern crate futures;
|
||||
extern crate libp2p_core;
|
||||
#[macro_use]
|
||||
@ -93,6 +94,7 @@ extern crate rw_stream_sink;
|
||||
#[cfg(feature = "secp256k1")]
|
||||
extern crate secp256k1;
|
||||
extern crate tokio_io;
|
||||
extern crate twofish;
|
||||
extern crate untrusted;
|
||||
|
||||
#[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::NewFixStreamCipher;
|
||||
use aes_ctr::{Aes128Ctr, Aes256Ctr};
|
||||
use ctr::Ctr128;
|
||||
use twofish::Twofish;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum KeySize {
|
||||
KeySize128,
|
||||
KeySize256,
|
||||
pub enum Cipher {
|
||||
Aes128,
|
||||
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"))))]
|
||||
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)
|
||||
}
|
||||
|
||||
/// 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")))]
|
||||
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 {
|
||||
aes_alt::ctr_alt(key_size, key, iv)
|
||||
} 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")))]
|
||||
mod aes_alt {
|
||||
extern crate ctr;
|
||||
extern crate aesni;
|
||||
use ::codec::StreamCipher;
|
||||
use self::ctr::Ctr128;
|
||||
use ctr::Ctr128;
|
||||
use self::aesni::{Aes128, Aes256};
|
||||
use self::ctr::stream_cipher::NewFixStreamCipher;
|
||||
use self::ctr::stream_cipher::generic_array::GenericArray;
|
||||
use super::KeySize;
|
||||
use ctr::stream_cipher::NewFixStreamCipher;
|
||||
use ctr::stream_cipher::generic_array::GenericArray;
|
||||
use twofish::Twofish;
|
||||
use super::Cipher;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref AES_NI: bool = is_x86_feature_detected!("aes")
|
||||
@ -70,13 +90,17 @@ mod aes_alt {
|
||||
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]) -> StreamCipher {
|
||||
pub fn ctr_alt(key_size: Cipher, key: &[u8], iv: &[u8]) -> StreamCipher {
|
||||
match key_size {
|
||||
KeySize::KeySize128 => Box::new(Aes128Ctr::new(
|
||||
Cipher::Aes128 => Box::new(Aes128Ctr::new(
|
||||
GenericArray::from_slice(key),
|
||||
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(iv),
|
||||
)),
|
||||
@ -86,13 +110,17 @@ mod aes_alt {
|
||||
}
|
||||
|
||||
#[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 {
|
||||
KeySize::KeySize128 => Box::new(Aes128Ctr::new(
|
||||
Cipher::Aes128 => Box::new(Aes128Ctr::new(
|
||||
GenericArray::from_slice(key),
|
||||
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(iv),
|
||||
)),
|
||||
@ -105,7 +133,7 @@ fn ctr_int(key_size: KeySize, key: &[u8], iv: &[u8]) -> StreamCipher {
|
||||
))]
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{KeySize, ctr};
|
||||
use super::{Cipher, ctr};
|
||||
|
||||
#[test]
|
||||
fn assert_non_native_run() {
|
||||
@ -113,7 +141,7 @@ mod tests {
|
||||
let key = [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];
|
||||
assert!(aes
|
||||
.try_apply_keystream(&mut content).is_ok());
|
||||
|
Loading…
x
Reference in New Issue
Block a user