diff --git a/Cargo.toml b/Cargo.toml index 9c4d9552..9fdae286 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,9 +32,10 @@ path = "src/bin/ssdns.rs" lto = true [features] -default = ["sodium", "rc4"] +default = ["sodium", "rc4", "aes-cfb"] sodium = ["libsodium-ffi"] -rc4 = [] +rc4 = ["openssl"] +aes-cfb = ["openssl"] single-threaded = [] [dependencies] @@ -44,7 +45,7 @@ rand = "0.6" time = "0.1" clap = "2" env_logger = "0.6" -openssl = "0.10" +openssl = { version = "0.10", optional = true } libc = "0.2" futures = "0.1" tokio-io = "0.1" diff --git a/README.md b/README.md index 6fd535bf..87c35ad3 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ shadowsocks is a fast tunnel proxy that helps you bypass firewalls. ## Dependencies -* libcrypto (OpenSSL) +* libcrypto (OpenSSL) (Required for `aes-cfb-*` and `rc4` ciphers) * libsodium >= 1.0.7 (Required for ciphers that are provided by libsodium) ## Build & Install @@ -24,9 +24,13 @@ shadowsocks is a fast tunnel proxy that helps you bypass firewalls. * `rc4` - Enabled `rc4` encryption algorithm. Some OpenSSL Crypto does not ship with `rc4`, because it was already deprecated in 2015. +* `aes-cfb` - Enabled `aes-cfb-*` encryption algorithm. + * `single-threaded` - Let `sslocal` and `ssserver` run in single threaded mode (by using `tokio::current_thread::Runtime`). -Default features: `["sodium", "rc4"]`. +Default features: `["sodium", "rc4", "aes-cfb"]`. + +NOTE: To disable dependency of OpenSSL, just disable feature `"rc4"` and `"aes-cfb"`. ### **crates.io** diff --git a/src/crypto/cipher.rs b/src/crypto/cipher.rs index 1f39abc2..cb0aeffc 100644 --- a/src/crypto/cipher.rs +++ b/src/crypto/cipher.rs @@ -3,13 +3,13 @@ use std::{ convert::From, fmt::{self, Debug, Display}, - io, - mem, + io, mem, str::{self, FromStr}, }; use crate::crypto::digest::{self, Digest, DigestType}; use bytes::{BufMut, Bytes, BytesMut}; +#[cfg(feature = "openssl")] use openssl::symm; use rand::{self, RngCore}; use ring::aead::{AES_128_GCM, AES_256_GCM, CHACHA20_POLY1305}; @@ -20,6 +20,7 @@ pub type CipherResult = Result; /// Cipher error pub enum Error { UnknownCipherType, + #[cfg(feature = "openssl")] OpenSSLError(::openssl::error::ErrorStack), IoError(io::Error), AeadDecryptFailed, @@ -30,6 +31,7 @@ impl Debug for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::UnknownCipherType => write!(f, "UnknownCipherType"), + #[cfg(feature = "openssl")] Error::OpenSSLError(ref err) => write!(f, "{:?}", err), Error::IoError(ref err) => write!(f, "{:?}", err), Error::AeadDecryptFailed => write!(f, "AEAD decrypt failed"), @@ -42,6 +44,7 @@ impl Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::UnknownCipherType => write!(f, "UnknownCipherType"), + #[cfg(feature = "openssl")] Error::OpenSSLError(ref err) => write!(f, "{}", err), Error::IoError(ref err) => write!(f, "{}", err), Error::AeadDecryptFailed => write!(f, "AeadDecryptFailed"), @@ -54,6 +57,7 @@ impl From for io::Error { fn from(e: Error) -> io::Error { match e { Error::UnknownCipherType => io::Error::new(io::ErrorKind::Other, "Unknown Cipher type"), + #[cfg(feature = "openssl")] Error::OpenSSLError(err) => From::from(err), Error::IoError(err) => err, Error::AeadDecryptFailed => io::Error::new(io::ErrorKind::Other, "AEAD decrypt error"), @@ -62,20 +66,29 @@ impl From for io::Error { } } +#[cfg(feature = "openssl")] impl From<::openssl::error::ErrorStack> for Error { fn from(e: ::openssl::error::ErrorStack) -> Error { Error::OpenSSLError(e) } } +#[cfg(feature = "aes-cfb")] const CIPHER_AES_128_CFB: &str = "aes-128-cfb"; +#[cfg(feature = "aes-cfb")] const CIPHER_AES_128_CFB_1: &str = "aes-128-cfb1"; +#[cfg(feature = "aes-cfb")] const CIPHER_AES_128_CFB_8: &str = "aes-128-cfb8"; +#[cfg(feature = "aes-cfb")] const CIPHER_AES_128_CFB_128: &str = "aes-128-cfb128"; +#[cfg(feature = "aes-cfb")] const CIPHER_AES_256_CFB: &str = "aes-256-cfb"; +#[cfg(feature = "aes-cfb")] const CIPHER_AES_256_CFB_1: &str = "aes-256-cfb1"; +#[cfg(feature = "aes-cfb")] const CIPHER_AES_256_CFB_8: &str = "aes-256-cfb8"; +#[cfg(feature = "aes-cfb")] const CIPHER_AES_256_CFB_128: &str = "aes-256-cfb128"; #[cfg(feature = "rc4")] @@ -113,14 +126,22 @@ pub enum CipherType { Table, Plain, + #[cfg(feature = "aes-cfb")] Aes128Cfb, + #[cfg(feature = "aes-cfb")] Aes128Cfb1, + #[cfg(feature = "aes-cfb")] Aes128Cfb8, + #[cfg(feature = "aes-cfb")] Aes128Cfb128, + #[cfg(feature = "aes-cfb")] Aes256Cfb, + #[cfg(feature = "aes-cfb")] Aes256Cfb1, + #[cfg(feature = "aes-cfb")] Aes256Cfb8, + #[cfg(feature = "aes-cfb")] Aes256Cfb128, #[cfg(feature = "rc4")] @@ -165,11 +186,17 @@ impl CipherType { match self { CipherType::Table | CipherType::Plain => 0, + #[cfg(feature = "aes-cfb")] CipherType::Aes128Cfb1 => symm::Cipher::aes_128_cfb1().key_len(), + #[cfg(feature = "aes-cfb")] CipherType::Aes128Cfb8 => symm::Cipher::aes_128_cfb8().key_len(), + #[cfg(feature = "aes-cfb")] CipherType::Aes128Cfb | CipherType::Aes128Cfb128 => symm::Cipher::aes_128_cfb128().key_len(), + #[cfg(feature = "aes-cfb")] CipherType::Aes256Cfb1 => symm::Cipher::aes_256_cfb1().key_len(), + #[cfg(feature = "aes-cfb")] CipherType::Aes256Cfb8 => symm::Cipher::aes_256_cfb8().key_len(), + #[cfg(feature = "aes-cfb")] CipherType::Aes256Cfb | CipherType::Aes256Cfb128 => symm::Cipher::aes_256_cfb128().key_len(), #[cfg(feature = "rc4")] @@ -234,21 +261,27 @@ impl CipherType { match self { CipherType::Table | CipherType::Plain => 0, + #[cfg(feature = "aes-cfb")] CipherType::Aes128Cfb1 => symm::Cipher::aes_128_cfb1() .iv_len() .expect("iv_len should not be None"), + #[cfg(feature = "aes-cfb")] CipherType::Aes128Cfb8 => symm::Cipher::aes_128_cfb8() .iv_len() .expect("iv_len should not be None"), + #[cfg(feature = "aes-cfb")] CipherType::Aes128Cfb | CipherType::Aes128Cfb128 => symm::Cipher::aes_128_cfb128() .iv_len() .expect("iv_len should not be None"), + #[cfg(feature = "aes-cfb")] CipherType::Aes256Cfb1 => symm::Cipher::aes_256_cfb1() .iv_len() .expect("iv_len should not be None"), + #[cfg(feature = "aes-cfb")] CipherType::Aes256Cfb8 => symm::Cipher::aes_256_cfb8() .iv_len() .expect("iv_len should not be None"), + #[cfg(feature = "aes-cfb")] CipherType::Aes256Cfb | CipherType::Aes256Cfb128 => symm::Cipher::aes_256_cfb128() .iv_len() .expect("iv_len should not be None"), @@ -347,14 +380,22 @@ impl FromStr for CipherType { match s { CIPHER_TABLE | "" => Ok(CipherType::Table), CIPHER_PLAIN => Ok(CipherType::Plain), + #[cfg(feature = "aes-cfb")] CIPHER_AES_128_CFB => Ok(CipherType::Aes128Cfb), + #[cfg(feature = "aes-cfb")] CIPHER_AES_128_CFB_1 => Ok(CipherType::Aes128Cfb1), + #[cfg(feature = "aes-cfb")] CIPHER_AES_128_CFB_8 => Ok(CipherType::Aes128Cfb8), + #[cfg(feature = "aes-cfb")] CIPHER_AES_128_CFB_128 => Ok(CipherType::Aes128Cfb128), + #[cfg(feature = "aes-cfb")] CIPHER_AES_256_CFB => Ok(CipherType::Aes256Cfb), + #[cfg(feature = "aes-cfb")] CIPHER_AES_256_CFB_1 => Ok(CipherType::Aes256Cfb1), + #[cfg(feature = "aes-cfb")] CIPHER_AES_256_CFB_8 => Ok(CipherType::Aes256Cfb8), + #[cfg(feature = "aes-cfb")] CIPHER_AES_256_CFB_128 => Ok(CipherType::Aes256Cfb128), #[cfg(feature = "rc4")] @@ -393,14 +434,22 @@ impl Display for CipherType { match *self { CipherType::Table => write!(f, "{}", CIPHER_TABLE), CipherType::Plain => write!(f, "{}", CIPHER_PLAIN), + #[cfg(feature = "aes-cfb")] CipherType::Aes128Cfb => write!(f, "{}", CIPHER_AES_128_CFB), + #[cfg(feature = "aes-cfb")] CipherType::Aes128Cfb1 => write!(f, "{}", CIPHER_AES_128_CFB_1), + #[cfg(feature = "aes-cfb")] CipherType::Aes128Cfb8 => write!(f, "{}", CIPHER_AES_128_CFB_8), + #[cfg(feature = "aes-cfb")] CipherType::Aes128Cfb128 => write!(f, "{}", CIPHER_AES_128_CFB_128), + #[cfg(feature = "aes-cfb")] CipherType::Aes256Cfb => write!(f, "{}", CIPHER_AES_256_CFB), + #[cfg(feature = "aes-cfb")] CipherType::Aes256Cfb1 => write!(f, "{}", CIPHER_AES_256_CFB_1), + #[cfg(feature = "aes-cfb")] CipherType::Aes256Cfb8 => write!(f, "{}", CIPHER_AES_256_CFB_8), + #[cfg(feature = "aes-cfb")] CipherType::Aes256Cfb128 => write!(f, "{}", CIPHER_AES_256_CFB_128), #[cfg(feature = "rc4")] diff --git a/src/crypto/mod.rs b/src/crypto/mod.rs index ca91158f..d20f0e18 100644 --- a/src/crypto/mod.rs +++ b/src/crypto/mod.rs @@ -5,13 +5,14 @@ pub use self::{ cipher::{CipherCategory, CipherResult, CipherType}, stream::{new_stream, BoxStreamCipher, StreamCipher}, }; +#[cfg(feature = "openssl")] use ::openssl::symm; -use std::convert::From; pub mod aead; pub mod cipher; pub mod digest; pub mod dummy; +#[cfg(feature = "openssl")] pub mod openssl; #[cfg(feature = "rc4")] pub mod rc4_md5; @@ -30,7 +31,8 @@ pub enum CryptoMode { Decrypt, } -impl From for symm::Mode { +#[cfg(feature = "openssl")] +impl std::convert::From for symm::Mode { fn from(m: CryptoMode) -> symm::Mode { match m { CryptoMode::Encrypt => symm::Mode::Encrypt, diff --git a/src/crypto/openssl.rs b/src/crypto/openssl.rs index a38b4279..ece0fa1c 100644 --- a/src/crypto/openssl.rs +++ b/src/crypto/openssl.rs @@ -19,11 +19,17 @@ impl OpenSSLCrypto { /// Creates by type pub fn new(cipher_type: cipher::CipherType, key: &[u8], iv: &[u8], mode: CryptoMode) -> OpenSSLCrypto { let t = match cipher_type { + #[cfg(feature = "aes-cfb")] CipherType::Aes128Cfb => symm::Cipher::aes_128_cfb128(), + #[cfg(feature = "aes-cfb")] CipherType::Aes128Cfb1 => symm::Cipher::aes_128_cfb1(), + #[cfg(feature = "aes-cfb")] CipherType::Aes128Cfb128 => symm::Cipher::aes_128_cfb128(), + #[cfg(feature = "aes-cfb")] CipherType::Aes256Cfb => symm::Cipher::aes_256_cfb128(), + #[cfg(feature = "aes-cfb")] CipherType::Aes256Cfb1 => symm::Cipher::aes_256_cfb1(), + #[cfg(feature = "aes-cfb")] CipherType::Aes256Cfb128 => symm::Cipher::aes_256_cfb128(), #[cfg(feature = "rc4")] diff --git a/src/crypto/stream.rs b/src/crypto/stream.rs index 7b2be500..7f468a72 100644 --- a/src/crypto/stream.rs +++ b/src/crypto/stream.rs @@ -2,16 +2,15 @@ use std::ops::{Deref, DerefMut}; +#[cfg(feature = "openssl")] +use crate::crypto::openssl; #[cfg(feature = "rc4")] use crate::crypto::rc4_md5; #[cfg(feature = "sodium")] use crate::crypto::sodium; use crate::crypto::{ cipher::{CipherCategory, CipherResult, CipherType}, - dummy, - openssl, - table, - CryptoMode, + dummy, table, CryptoMode, }; use bytes::BufMut; @@ -109,12 +108,14 @@ define_stream_ciphers! { pub DummyCipher => dummy::DummyCipher, #[cfg(feature = "rc4")] pub Rc4Md5Cipher => rc4_md5::Rc4Md5Cipher, + #[cfg(feature = "openssl")] pub OpenSSLCipher => openssl::OpenSSLCipher, #[cfg(feature = "sodium")] pub SodiumStreamCipher => sodium::SodiumStreamCipher, } /// Generate a specific Cipher with key and initialize vector +#[allow(unused_variables)] pub fn new_stream(t: CipherType, key: &[u8], iv: &[u8], mode: CryptoMode) -> BoxStreamCipher { assert!( t.category() == CipherCategory::Stream, @@ -133,7 +134,17 @@ pub fn new_stream(t: CipherType, key: &[u8], iv: &[u8], mode: CryptoMode) -> Box #[cfg(feature = "rc4")] CipherType::Rc4Md5 => StreamCipherVariant::new(rc4_md5::Rc4Md5Cipher::new(key, iv, mode)), - _ => StreamCipherVariant::new(openssl::OpenSSLCipher::new(t, key, iv, mode)), + #[cfg(feature = "openssl")] + CipherType::Aes128Cfb + | CipherType::Aes128Cfb1 + | CipherType::Aes128Cfb8 + | CipherType::Aes128Cfb128 + | CipherType::Aes256Cfb + | CipherType::Aes256Cfb1 + | CipherType::Aes256Cfb8 + | CipherType::Aes256Cfb128 => StreamCipherVariant::new(openssl::OpenSSLCipher::new(t, key, iv, mode)), + + _ => unreachable!("{} is not a stream cipher", t), }; BoxStreamCipher { cipher: Box::new(cipher),